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
CodePudding user response:
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)
CodePudding user response:
You have an issue with both your data and how you are parsing it.
- The data isn't comma delineated.
- 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);
};