D3.js Cannot read property 'length' of undefined
Your mistake is assuming that calling d3.csv(...)
returns your CSV data.
d3.csv
makes an AJAX call to load your data and then calls a callback function when that data has been loaded. Your code continues running while the data loads in the background. When you write var data = [d3.csv(...)]
, data
doesn't contain the data loaded from your CSV file, it contains only a d3 object, and you cannot plot that.
Instead, your call to d3.csv
should look something like the following:
d3.csv("refugee_data.csv", function(d) {
return {
date: d.Year + "/" +d.Month,
origin: d.Origin,
asylum: d.Asylum,
value: +d.Value
};
}, function(error, rows) {
console.log(rows);
render(rows);
});
where render
is a function that d3 will call to draw your graph when the data has finished loading.
I created a render
function that contained the contents of your code from the line var w = 800;
to the lines beginning var y = ...
, followed by the contents of the plot
function. I also replaced this.selectAll
with svg.selectAll
, and remove the use of plot.call
. The render
function I wrote ended up as follows:
function render(data) {
var w = 800;
var h = 450;
var margin = {
top: 58,
bottom: 100,
left: 80,
right: 40
};
var width = w - margin.left - margin.right;
var height = h - margin.top - margin.bottom;
var svg = d3.select("body").append("svg")
.attr("id", "chart")
.attr("width", w)
.attr("height", h);
var dateParser = d3.time.format("%Y/%B").parse;
var x = d3.time.scale()
.domain(d3.extent(data, function(d){
var date = dateParser(d.date);
return date;
}))
.range([0,width]);
var y = d3.scale.linear()
.domain([0, d3.max(data, function(d){
return d.value;
})])
.range([height,0]);
//enter()
svg.selectAll(".point")
.data(data)
.enter()
.append("circle")
.classed("point", true)
.attr("r", 2);
//Update
svg.selectAll(".point")
.attr("cx", function(d){
var date = dateParser(d.date);
return x(date);
})
.attr("cy", function(d){
return y(d.value);
})
//Exit()
svg.selectAll(".point")
.data(data)
.exit()
.remove();
}
After making these changes I was able to see your graph working.
basedian
Newb and designer. IxD and Interface. I'm interested in coding and design.
Updated on June 04, 2022Comments
-
basedian almost 2 years
I'm pretty new to d3.js and to web too. I wanted to ue a csv file to plot a line graph but I got some errors I can't really fix:
Here is the code:
body,html{ margin: 0; padding: 0; font-family: "Arial", sans-serif; font-size: 0.95em; text-align: center; } #chart{ background-color: #F5F2EB; border: 1px solid #CCC; } .bar{ fill: purple; shape-rendering: crispEdges; } .bar-label{ fill: black; text-anchor: middle; font-size: 18px; } .axis path, .axis line{ fill: none; stroke: #000; shape-rendering: crispEdges; } .gridline path, .gridline line{ fill: none; stroke: #ccc; shape-rendering: crispEdges; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Learning D3</title> <link rel="stylesheet" href="main.css"> <script type="text/javascript" src="d3.min.js"></script> </head> <body> <!--Place all DOM elements here --> <script> var data= [ d3.csv("refugee_data.csv", function(d) { return { /*year: new Date(+d.Year, 0, 1), // convert "Year" column to Date make: d.Make, model: d.Model, length: +d.Length // convert "Length" column to number*/ date: d.Year + "/" +d.Month, origin: d.Origin, asylum: d.Asylum, value: +d.Value }; }, function(error, rows) { console.log(rows); }) ]; var w = 800; var h = 450; var margin = { top: 58, bottom: 100, left: 80, right: 40 }; var width = w - margin.left - margin.right; var height = h - margin.top - margin.bottom; var svg = d3.select("body").append("svg") .attr("id", "chart") .attr("width", w) .attr("height", h); var dateParser = d3.time.format("%Y/%B").parse; var x = d3.time.scale() .domain(d3.extent(data, function(d){ var date = dateParser(d.date); return date; })) .range([0,width]); var y = d3.scale.linear() .domain([0, d3.max(data, function(d){ return d.value; })]) .range([height,0]); function plot(params){ //enter() this.selectAll(".point") .data(params.data) .enter() .append("circle") .classed("point", true) .attr("r", 2); //Update this.selectAll(".point") .attr("cx", function(d){ var date = dateParser(d.date); return x(date); }) .attr("cy", function(d){ return y(d.value); }) //Exit() this.selectAll(".point") .data(params.data) .exit() .remove(); } plot.call(chart, { data: data }) </script> </body> </html>
And this ist my a part of my csv, pretty basic so I don't get why it does not work.
Asylum,Origin,Year,Month,Value
Germany,Afghanistan,2014,January,981 Germany,Afghanistan,2014,February,781 Germany,Afghanistan,2014,March,675 Germany,Afghanistan,2014,April,673 Germany,Afghanistan,2014,May,523 Germany,Afghanistan,2014,June,621 Germany,Afghanistan,2014,July,752 Germany,Afghanistan,2014,August,743 Germany,Afghanistan,2014,September,922
I assume it is a really stupid mistake can you please help me out?
-
basedian over 8 yearsThank you, it worked. Is there some besides d3.keys to filter some entries of the csv? I want to filter the origin countries, like afghanistan an syria for interavtive purposes. In other terms I'd like to hover with the mous over the points to get the origin country. This is the source to get an idea of the real data
-
Luke Woodward over 8 years@basedian: if you have a separate question, the thing to do is to ask a separate question. This is something I see that you have now done.