1

I'm trying to load the data from a csv into useState via a useEffect state. But I can't get it to work.

My csv contains data like this:

  Date             Value1   Value2 
  2020/7/20        1        4              
  2020/7/21        2        8 
  2020/7/22        3        10
  2020/7/23        4        12
  2020/7/24        5        67
  2020/7/25        6        10

And I'm trying to get the data in a useState via useEffect like this:

import * as d3 from 'd3';
import {useEffect, useState} from 'react';
import csvFile from '../data/Data.csv';


const Linechart = (props) => {

  const [data, setData] = useState([]); 

  useEffect(()=>{
     if (data.length > 0) {
       drawChart();
     } else {

      getCSVData();
    }
   ,[]);

    // gets csv data from csv
  const getCSVData = async () => {
    let tempData = [];
      await d3.csv(csvFile,

      function(d){
        tempData.push({date: d3.timeParse("%Y/%m/%d")(d.Date), value1: parseFloat(d.Value1), value2: parseFloat(d.Value2)}),    
      } 
    )
      setData(tempData);

      console.log("data is: ", data.date)
      console.log("value1 is: ", data.value1)
      console.log("value2 is: ", data.value2)
  }

For some reason it does not want to work. I get the following error:

attr.js:30 Error: <path> attribute d: Expected number, "MNaN,NaNLNaN,NaNL…".

It seems to get stuck at tempData.push. I have never used this .push (I'm very new to both React and Javascript). Can someone help me fix this maybe?

The data is used for a d3 visualization, here is the full code to create the linechart:

import * as d3 from 'd3';
import {useEffect, useState} from 'react';
 import csvFile from '../data/Data.csv';


const Linechart = (props) => {

  const [data, setData] = useState([]);

    const {width, height } = props;

  useEffect(()=>{
    if (data.length > 0) {
      drawChart();
    } else {

      getCSVData();
    }},[data]);

   console.log(data)

    // gets csv data from a csv
  const getCSVData = async () => {
    let tempData = [];
      await d3.csv(csvFile,

      function(d){

        tempData.push({date: d3.timeParse("%m/%d/%Y")(d.Date), value1: parseFloat(d.Value1), value2: parseFloat(d.Value2)});
      }

    )
    console.log(tempData)
      setData(tempData);
      console.log("data is: ",data.date)
  }

const drawChart = () => {

    // create the chart area
    const svg = d3.select('.svg-canvas')
  svg.selectAll("*").remove();

// Add X axis --> it is a date format
    var x = d3.scaleTime()
      .domain(d3.csv(data, function(d) { return d.date; }))
      .range([ 0, width ]);
      
    svg.append("g")
      .attr("transform", "translate(0," + height + ")")
      .call(d3.axisBottom(x));


    // Add Y axis
    var y = d3.scaleLinear()
      .domain([0, d3.max(data, function(d) { return + d.value1; })])
      .range([ height, 0 ]);
    svg.append("g")
      .call(d3.axisLeft(y));

    // set line coordinates
    const line = d3.line()
      .x(function(d) { return x(d.date) })
      
      .y(function(d) { return y(d.value1) })

    // Add the line
    svg.append("path")
      .datum(data)
      .attr("fill", "none")
      .attr("stroke", "steelblue")
      .attr("stroke-width", 1.5)
      .attr("d", line)
 }

return (
    <div>
     <svg className="svg-canvas" width="1000px" height="600px" />


    </div>
    )

}

export default Linechart;

The error comes from the drawChart function as it is not receiving the right data

4
  • wdym by stuck, can you please elaborate more ... Do you see any errors? Commented Oct 5, 2022 at 7:03
  • 2
    Create Minimal reproductive example. Without your code, we cannot tell you what you are doing wrong. stackoverflow.com/help/minimal-reproducible-example Commented Oct 5, 2022 at 7:07
  • @DecPK I added the full code now :) Commented Oct 5, 2022 at 7:50
  • I've copy/pasted your code into a running sandbox and there are no errors. codesandbox.io/s/… Commented Oct 5, 2022 at 7:53

2 Answers 2

1

You can not use .push() like that, you need to wrap all the values in a object and then push them to the tempData array. After that you will be able to set the state with the new array.

tempData.push( { date: d3.timeParse("%Y/%m/%d")(d.Date), value1: parseFloat(d.Value1), value2: parseFloat(d.Value2) } );
setData(tempData);  

Now you will have state which is going to be array with one item on the 0 index which is going to be object with properties.

[ 0: { date: ... , value1: ... , value2: ... } ]

After that when you need to access your data you have to loop over the array.

data.map((currentEl) => {
  console.log(currentEl)
  console.log(currentEl.date)
  console.log(currentEl.value1)
  console.log(currentEl.value2)
})

Another way yo do this is to set your state to object,

const [data, setData] = useState({date: '', value1: '', value2: ''});  

const tempData = { date: d3.timeParse("%Y/%m/%d")(d.Date), value1: parseFloat(d.Value1), value2: parseFloat(d.Value2) }  

setData(tempData);  
console.log(data.date)
console.log(data.value1)
console.log(data.value2)
Sign up to request clarification or add additional context in comments.

4 Comments

Hi! A yeah you mean the {} ? I added those, forgot them in my example. But I also added the whole code. I think my problem is more on how to use the useState data for my linechart
If you want to access the obj like this data.date you need object not array, because currently you need to access the data like data[0].date, or you need to .map() or .forEach() the array and get te current element
Ah thank you so much! Now I see it in the right way :) Would you know what I can use to use it in my chart? Should I use the .map() as well? Or is there a better way?
I'm not familiar with that type of charts that you are trying to render, also take a look at Drew Reese answear.
0

You have an issue with both your data and how you are parsing it.

  1. The data isn't comma delineated.
  2. The date format you are trying to use has the units in reverse order and the dates are not zero-padded.

The data should actually use comma separated columns:

Data.csv

Date,Value1,Value2
2020/7/20,1,4
2020/7/21,2,8
2020/7/22,3,10
2020/7/23,4,12
2020/7/24,5,67
2020/7/25,6,10

Ensure there is also no trailing whitespace at the end of each line.

The format you should use to parse the date is "%Y/%m/%d".

const getCSVData = async () => {
  const tempData = [];

  await d3.csv(
    csvFile,
    function (d) {
      tempData.push({
        date: d3.timeParse("%Y/%m/%d")(d.Date),
        value1: Number(d.Value1),
        value2: Number(d.Value2)
      });
    }
  );

  setData(tempData);
};

Edit react-javascript-saving-values-from-local-csv-into-usestate-useeffect

enter image description here

2 Comments

Hi Drew ! Thank you for your answer. I don't really understand your answer though. I'm saving it as a csv file (comma delimited) and the order of the date is the way that I saved it?
@user2133561 I was only going by what you provided as the "CSV" file in your post, which is quite literally not separated by any commas. I've only mentioned it and the whitespace since that is what I had to fix in the data you shared to get the d3.csv() call to work and parse the file.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.