Home > Net >  Error: <path> attribute d: Expected number, "MNaN,36.393574100…
Error: <path> attribute d: Expected number, "MNaN,36.393574100…

Time:02-10

I am trying to build a simple line graph with d3.js and render it inside of a react component. Unfortunately, I get the following error:

Error: <path> attribute d: Expected number, "MNaN,36.393574100…"

The stackoverflow similar questions have unfortunately not been very helpful to me. My theory is I am not reading in the data object correctly (data.forEach) to my "d" attribute when I append the path to the chart. I have tried doing this both WITH and WITHOUT the parseDate function. When I do it WITHOUT it my dates look how they should in the console. If I include the parseDate function later on in the code while I am declaring my x axis and/or inside the x function of the path d attribute...nothing really changes. I'm also not entirely sure if my data object is nested correctly or not or if I should be serving the entire data object to the datum() function ....

Here is my code:

import * as d3 from "d3";
import React, { useRef, useEffect } from "react";

function LineBarChart({ width, height, data }) {

const ref = useRef();

useEffect(() => {
 d3.select(ref.current)
  .attr("width", width)
  .attr("height", height)
  // .style("border", "1px solid black");
  }, [height, width]);

 useEffect(() => {
  draw();
 }, [data]);

const draw = () => {

const parseDate = d3.timeFormat("%Y-%m-%d");

data.forEach(function (d) {
 d.dateM = d.dateM;
 // d.dateM = parseDate(d.dateM);
 d.closeM =  d.closeM;
 console.log("WHAT-DO-I-LOOK-LIKE", d.dateM)
});

// const dataNest = d3.nest()
//   .key((d) => d.dateM)
//   .key((d) => d.closeM)
//   .map(data);

const margin = 80;
const width = 1400 - 2 * margin;
const height = 800 - 2 * margin;

const svg = d3.select(ref.current);

const chart = svg
  .append("g")
  .attr("class", "linechart")
  .attr("transform", `translate(${margin}, ${margin})`);


 var x = d3.scaleTime()
  .domain(d3.extent(data, function(d) { return d.dateM; }))
  //.domain(d3.extent(data, function(d) { return parseDate(d.dateM); }))
  .range([ 0, width ]);

 chart.append("g")
  .attr("transform", "translate(0,"   height   ")")
  .call(d3.axisBottom(x));

 var y = d3.scaleLinear()
   .domain([0, d3.max(data, function(d) { return  d.closeM; })])
   .range([ height, 0 ]);

 chart.append("g")
  .call(d3.axisLeft(y));

 chart.append("path")
  .datum(data)
  .attr('class', 'lineChartClass')
  .attr("fill", "none")
  .attr("stroke", "steelblue")
  .attr("stroke-width", 1.5)
  .attr("d", d3.line()
    // .x(function(d) { return parseDate(d.dateM) })
    .x(function(d) { return x(d.dateM) })
    .y(function(d) { return y(d.closeM) })

  )

}; //draw

return (
 <div className="chartSixPointFive">
  <svg ref={ref}></svg>
 </div>

);
}

export default LineBarChart;

My React app uses Axios to hit a Flask endpoint. There isn't anything fancy going on here, I just return the linechart like so.

....
....
<LineBarChart width={1350} height={1000} data={data} />

I can include the full react code if necessary (although I don't think it's needed)

Here is what my data object looks like:

    "results": [
    {
        "date": "2022-02-07",
        "open": 172.860001,
        "high": 173.949997,
        "low": 170.949997,
        "close": 171.660004,
        "volume": 77045100,
        "adjClose": 171.660004
    },

    rinse & repeat ....
    
    ]

I appreciate ANY help I can get!

CodePudding user response:

d3.timeFormat formats a date object and returns a string. What you want is d3.timeParse instead, which will do the opposite: it will parse your strings into date objects, that can be used by the time scale:

const parseDate = d3.timeParse("%Y-%m-%d");

PS: the M command of the "d" attribute uses (as pretty much everything in every language) the coordinate pair x,y (horizontal/vertical). Thus, when you have the error:

MNaN,42...

...you know the problem is in your x scale, while the error:

M42,NaN...

...shows you the problem is in the y scale.

  • Related