duncdrum duncdrum - 3 months ago 23
Javascript Question

Why does this vanilla js function return different results in d3v3 and d3v4

This is a MWE based on some templates going from v3 to v4 of the amazing d3.js.

The data is in csv file, both examples load the same file (its clean):

day,movie1,movie2,movie3,movie4,movie5,movie6
1,20,8,3,0,0,0
2,18,5,1,13,0,0
3,14,3,1,10,0,0
4,7,3,0,5,27,15
5,4,3,0,2,20,14
6,3,1,0,0,10,13
7,2,0,0,0,8,12
8,0,0,0,0,6,11
9,0,0,0,0,3,9
10,0,0,0,0,1,8


here is MWE in question:

d3.csv("../data/source/movies.csv", function (error, data) {
dataViz(data)});

function dataViz(incData) {
expData = incData;
stackData =[];

for (x in incData[0]) {
if (x != "day") {
var newMovieObject = {
name: x, values:[]
};
for (y in incData) {
newMovieObject
.values
.push({
x: parseInt(incData[y][ "day"]),
y: parseInt(incData[y][x])
})
}
stackData
.push(newMovieObject);
}}}


Now in v3 the
stackData
array has 6 objects with 10 values each e.g.:

{name: "movie1" values:[
{x: 1, y:20} //0
...
{x:10, y:0} //9
]


}


In v4 for however I get an array with 6 objects with 11 values each, the last one annoyingly being:

{name: "movie1" values:[
{x: 1, y:20} //0
...
{x:10, y:0} //9
{x: NaN, y: NaN} //10 *ouch*
]


}


As a js noob, I don't understand why this vanilla JS function returns different results, and what to do about it? Any help would be greatly appreciated.

Answer

The reason for this difference is that D3 v4.x creates an additional object named columns when it parses the CSV (look at the documentation), being the last object in your data array.

So, for instance, given your data:

day,movie1,movie2,movie3,movie4,movie5,movie6
1,20,8,3,0,0,0
2,18,5,1,13,0,0
...

D3 creates, after the "normal" objects, this additional object (technically speaking, an additional property to the array):

columns: ["day", "movie", "movie2", "movie3", "movie4", "movie5", "movie6"]

Which you can call using data.columns.

The problem you're facing now is that when you iterate over this object you get a lot of NaN.

Solution: you can simply avoid iterating over columns or removing it from your data (if you want, but not recommended). There are several ways for removing an property from an array in JavaScript, the simpler way being this:

delete incData.columns;

To check this columns property, simply console.log(data) using D3 v3 and v4, comparing the results.