Why does this vanilla js function return different

2019-07-23 00:20发布

问题:

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.

回答1:

The reason for this difference is that D3 v4.x creates an additional property named columns to the data array when it parses the CSV (look at the documentation).

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 right now is that when you use a for...in loop you end up iterating this property as well, getting a lot of NaN.

Solution: you can simply avoid iterating over columns or, if you don't need it, you can remove it from your data. 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.