Drawing line in d3js results in d3.v5.min.js:2 Error: <path> attribute d: Expected number
Drawing line in d3js results in d3.v5.min.js:2 Error: <path> attribute d: Expected number
我有一个双 y 轴图表,我想在其中显示总分条和平均分线。
试玩之后,我已经配置了所有东西,除了无法显示的行。
我收到控制台错误 d3.v5.min.js:2 Error: <path> attribute d: Expected number, "MNaN,189.02173913…".
所以我认为我的 lineFunction
有问题,但我看不出是什么,它应该 return x 和 y 值来绘制直线。
我用 this page 作为灵感
我已经检查了类似答案的解决方案 and ,但是我的 Average
变量已经是一个数字,所以这对我来说似乎没问题。
我错过了什么?
我的代码:
//// VERTICAL BAR CHART WITH SVG AND NAMES SINGLE X AND DUAL Y AXES
// Create data array of values to visualize
var dataArray = [{ "Player": "John Doe", "Points": 23, "Average": 4.5 }, { "Player": "Jane Doe", "Points": 13, "Average": 2.3 }, { "Player": "Mary Jane", "Points": 21, "Average": 1.5 }, { "Player": "Debasis Das", "Points": 14, "Average": 5.7 }, { "Player": "Nishant", "Points": 37, "Average": 5.9 }, { "Player": "Mark", "Points": 15, "Average": 6.2 }, { "Player": "Andrew", "Points": 18, "Average": 1.2 }, { "Player": "Simon", "Points": 34, "Average": 3.1 }, { "Player": "Lisa", "Points": 30, "Average": 9.2 }, { "Player": "Marga", "Points": 20, "Average": 7.8 }];
// Create variable for the SVG
var canvas = d3.select(".v5chart").append("g").attr("transform", "translate(20,30)");
var canvasWidth = 500;
var maxValue = d3.max(dataArray, function (d) { return d.Points; });
var maxValue2 = d3.max(dataArray, function (d) { return d.Average; });
//console.error("maxValue2:" + maxValue2);
var canvasHeight = maxValue * 10;
var canvasHeight2 = maxValue2 * 10;
//make sure y-axes are equal in height
if (canvasHeight > canvasHeight2) {canvasHeight2 = canvasHeight;}
else if (canvasHeight < canvasHeight2) {canvasHeight = canvasHeight2;}
var heightScale = d3.scaleLinear()
.domain([0, d3.max(dataArray, function (d) { return d.Points; })])
.range([canvasHeight, 0]); //use max value (37) * 10
var y_axis = d3.axisLeft()
.scale(heightScale);
var heightScale2 = d3.scaleLinear()
.domain([0, d3.max(dataArray, function (d) { return d.Average; })])
.range([canvasHeight2, 0]);
var y_axis2 = d3.axisRight()
.scale(heightScale2);
//band settings x axis
var xScale = d3.scaleBand()
.domain(dataArray.map(function (d) { return d.Player; }))
.range([0, canvasWidth]).padding([0.1]);
var x_Axis = d3.axisBottom(xScale);
// create bars
canvas.selectAll("rect")
.data(dataArray)
.enter().append("rect")
.attr("class", "bar")
.attr("height", function (d, i) { return (d.Points * 10) })
.attr("width", xScale.bandwidth())
.attr("x", function (d, i) { return xScale(d.Player); })
.attr("y", function (d, i) { return canvasHeight - (d.Points * 10) });
// text for in vertical bars
canvas.selectAll("text")
.data(dataArray)
.enter().append("text")
.text(function (d) { return d.Points })
.attr("text-anchor", "middle")
.attr("class", "text")
.attr("x", function (d, i) { return (xScale(d.Player) + xScale.bandwidth() / 2); })
.attr("y", function (d, i) { return canvasHeight + 20 - (d.Points * 10) });
var yScale = d3.scaleLinear()
.domain([0, maxValue2]) // input
.range([canvasHeight2, 0]); // output
var lineFunction = d3.line()
.x(function (d, i) { return xScale(i); }) // set the x values for the line generator
.y(function (d, i) { return yScale(d.Average); }) // set the y values for the line generator
.curve(d3.curveMonotoneX); // apply smoothing to the line
// 4. Call the y axis in a group tag
canvas.append("g")
.attr("class", "y axis")
.call(d3.axisRight(yScale)) // Create an axis component with d3.axisLeft
.attr("transform", "translate(" + canvasWidth + ",0)")
.append("text")
.attr("fill", "#000")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", "-1em")
.attr("text-anchor", "end")
.text("Average");
canvas.append("path")
.attr("class", "line")
.attr("d", lineFunction(dataArray));
canvas.selectAll(".dot")
.data(dataArray)
.enter().append("circle") // Uses the enter().append() method
.attr("class", "dot") // Assign a class for styling
.attr("cx", function (d, i) { return xScale(d.Player) })
.attr("cy", function (d) { return yScale(d.Average) })
.attr("r", 5)
.on("mouseover", function (a, b, c) {
console.log(a)
//this.attr('class', 'focus')
})
.on("mouseout", function () { })
.append("text")
.attr("text-anchor", "middle")
.text(function (d) {
return d.Average;
});
//y axis 1 settings
canvas.append("g")
.attr("transform", "translate(0,0)")
.call(y_axis)
.append("text")
.attr("fill", "#000")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", "0.71em")
.attr("text-anchor", "end")
.text("Points");
//x axis
canvas.append("g")
.attr("transform", "translate(0," + canvasHeight + ")")
.call(x_Axis)
.selectAll("text")
.attr("x", 30)
.attr("transform", function (d) {
return "rotate(65)"
});
/*Rectangle bar class styling*/
.bar {
fill: #0080FF
}
.bar:hover {
fill: #003366
}
/*Text class styling*/
.text {
fill: white;
font-family: sans-serif
}
/* Style the lines by removing the fill and applying a stroke */
.line {
fill: none;
stroke: #ffab00;
stroke-width: 3;
}
.overlay {
fill: none;
pointer-events: all;
}
/* Style the dots by assigning a fill and stroke */
.dot {
fill: #ffab00;
stroke: #fff;
}
.focus circle {
fill: none;
stroke: steelblue;
}
<script src="https://d3js.org/d3.v5.min.js"></script>
<svg class="v5chart" width="960" height="500"></svg>
在 d3 的文档中;
The first element in domain will be mapped to the first band, the
second domain value to the second band, and so on. Domain values are
stored internally in a map from stringified value to index; the
resulting index is then used to determine the band. Thus, a band
scale’s values must be coercible to a string, and the stringified
version of the domain value uniquely identifies the corresponding
band. If domain is not specified, this method returns the current
domain.
但是在您的 xScale 函数中,您使用的是带有 Player 键的 dataArray 的映射值。我的意思是,如果你想从 xScale 函数中获得任何正确的数字,你必须将它与播放键一起使用,如 'John Doe'、'Jane Doe' 等
综上所述,如果将line函数改成这个,你会看到结果:
var lineFunction = d3.line()
.x(function (d, i) { return xScale(d.Player); /*return xScale(i)*/ })
.y(function (d, i) { return yScale(d.Average); })
.curve(d3.curveMonotoneX);
我猜,你想在这之后解决对齐问题。由你决定。
我有一个双 y 轴图表,我想在其中显示总分条和平均分线。 试玩之后,我已经配置了所有东西,除了无法显示的行。
我收到控制台错误 d3.v5.min.js:2 Error: <path> attribute d: Expected number, "MNaN,189.02173913…".
所以我认为我的 lineFunction
有问题,但我看不出是什么,它应该 return x 和 y 值来绘制直线。
我用 this page 作为灵感
我已经检查了类似答案的解决方案 Average
变量已经是一个数字,所以这对我来说似乎没问题。
我错过了什么?
我的代码:
//// VERTICAL BAR CHART WITH SVG AND NAMES SINGLE X AND DUAL Y AXES
// Create data array of values to visualize
var dataArray = [{ "Player": "John Doe", "Points": 23, "Average": 4.5 }, { "Player": "Jane Doe", "Points": 13, "Average": 2.3 }, { "Player": "Mary Jane", "Points": 21, "Average": 1.5 }, { "Player": "Debasis Das", "Points": 14, "Average": 5.7 }, { "Player": "Nishant", "Points": 37, "Average": 5.9 }, { "Player": "Mark", "Points": 15, "Average": 6.2 }, { "Player": "Andrew", "Points": 18, "Average": 1.2 }, { "Player": "Simon", "Points": 34, "Average": 3.1 }, { "Player": "Lisa", "Points": 30, "Average": 9.2 }, { "Player": "Marga", "Points": 20, "Average": 7.8 }];
// Create variable for the SVG
var canvas = d3.select(".v5chart").append("g").attr("transform", "translate(20,30)");
var canvasWidth = 500;
var maxValue = d3.max(dataArray, function (d) { return d.Points; });
var maxValue2 = d3.max(dataArray, function (d) { return d.Average; });
//console.error("maxValue2:" + maxValue2);
var canvasHeight = maxValue * 10;
var canvasHeight2 = maxValue2 * 10;
//make sure y-axes are equal in height
if (canvasHeight > canvasHeight2) {canvasHeight2 = canvasHeight;}
else if (canvasHeight < canvasHeight2) {canvasHeight = canvasHeight2;}
var heightScale = d3.scaleLinear()
.domain([0, d3.max(dataArray, function (d) { return d.Points; })])
.range([canvasHeight, 0]); //use max value (37) * 10
var y_axis = d3.axisLeft()
.scale(heightScale);
var heightScale2 = d3.scaleLinear()
.domain([0, d3.max(dataArray, function (d) { return d.Average; })])
.range([canvasHeight2, 0]);
var y_axis2 = d3.axisRight()
.scale(heightScale2);
//band settings x axis
var xScale = d3.scaleBand()
.domain(dataArray.map(function (d) { return d.Player; }))
.range([0, canvasWidth]).padding([0.1]);
var x_Axis = d3.axisBottom(xScale);
// create bars
canvas.selectAll("rect")
.data(dataArray)
.enter().append("rect")
.attr("class", "bar")
.attr("height", function (d, i) { return (d.Points * 10) })
.attr("width", xScale.bandwidth())
.attr("x", function (d, i) { return xScale(d.Player); })
.attr("y", function (d, i) { return canvasHeight - (d.Points * 10) });
// text for in vertical bars
canvas.selectAll("text")
.data(dataArray)
.enter().append("text")
.text(function (d) { return d.Points })
.attr("text-anchor", "middle")
.attr("class", "text")
.attr("x", function (d, i) { return (xScale(d.Player) + xScale.bandwidth() / 2); })
.attr("y", function (d, i) { return canvasHeight + 20 - (d.Points * 10) });
var yScale = d3.scaleLinear()
.domain([0, maxValue2]) // input
.range([canvasHeight2, 0]); // output
var lineFunction = d3.line()
.x(function (d, i) { return xScale(i); }) // set the x values for the line generator
.y(function (d, i) { return yScale(d.Average); }) // set the y values for the line generator
.curve(d3.curveMonotoneX); // apply smoothing to the line
// 4. Call the y axis in a group tag
canvas.append("g")
.attr("class", "y axis")
.call(d3.axisRight(yScale)) // Create an axis component with d3.axisLeft
.attr("transform", "translate(" + canvasWidth + ",0)")
.append("text")
.attr("fill", "#000")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", "-1em")
.attr("text-anchor", "end")
.text("Average");
canvas.append("path")
.attr("class", "line")
.attr("d", lineFunction(dataArray));
canvas.selectAll(".dot")
.data(dataArray)
.enter().append("circle") // Uses the enter().append() method
.attr("class", "dot") // Assign a class for styling
.attr("cx", function (d, i) { return xScale(d.Player) })
.attr("cy", function (d) { return yScale(d.Average) })
.attr("r", 5)
.on("mouseover", function (a, b, c) {
console.log(a)
//this.attr('class', 'focus')
})
.on("mouseout", function () { })
.append("text")
.attr("text-anchor", "middle")
.text(function (d) {
return d.Average;
});
//y axis 1 settings
canvas.append("g")
.attr("transform", "translate(0,0)")
.call(y_axis)
.append("text")
.attr("fill", "#000")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", "0.71em")
.attr("text-anchor", "end")
.text("Points");
//x axis
canvas.append("g")
.attr("transform", "translate(0," + canvasHeight + ")")
.call(x_Axis)
.selectAll("text")
.attr("x", 30)
.attr("transform", function (d) {
return "rotate(65)"
});
/*Rectangle bar class styling*/
.bar {
fill: #0080FF
}
.bar:hover {
fill: #003366
}
/*Text class styling*/
.text {
fill: white;
font-family: sans-serif
}
/* Style the lines by removing the fill and applying a stroke */
.line {
fill: none;
stroke: #ffab00;
stroke-width: 3;
}
.overlay {
fill: none;
pointer-events: all;
}
/* Style the dots by assigning a fill and stroke */
.dot {
fill: #ffab00;
stroke: #fff;
}
.focus circle {
fill: none;
stroke: steelblue;
}
<script src="https://d3js.org/d3.v5.min.js"></script>
<svg class="v5chart" width="960" height="500"></svg>
在 d3 的文档中;
The first element in domain will be mapped to the first band, the second domain value to the second band, and so on. Domain values are stored internally in a map from stringified value to index; the resulting index is then used to determine the band. Thus, a band scale’s values must be coercible to a string, and the stringified version of the domain value uniquely identifies the corresponding band. If domain is not specified, this method returns the current domain.
但是在您的 xScale 函数中,您使用的是带有 Player 键的 dataArray 的映射值。我的意思是,如果你想从 xScale 函数中获得任何正确的数字,你必须将它与播放键一起使用,如 'John Doe'、'Jane Doe' 等
综上所述,如果将line函数改成这个,你会看到结果:
var lineFunction = d3.line()
.x(function (d, i) { return xScale(d.Player); /*return xScale(i)*/ })
.y(function (d, i) { return yScale(d.Average); })
.curve(d3.curveMonotoneX);
我猜,你想在这之后解决对齐问题。由你决定。