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);

我猜,你想在这之后解决对齐问题。由你决定。