SpyTh SpyTh - 22 days ago 8
Javascript Question

d3 tsv/csv columns in accessor (row) function

Consider the following tsv file:

Code k1 k2
pf_1 0.2 0.3
pf_2 0.3 0.7
pf_3 0.2 0.4
pf_4 0.1 0.6
pf_5 0.8 0.9


I 've been trying to understand how the following code works but haven't found a clear answer:

d3.tsv("test.tsv")
.row(function(d, i, columns){ d.total = columns.length; return d;})
.get(function(d){ console.log(d);});


The specific questions I have are the following:


  • What is the underlying parse function that maps the third (columns) argument to the column names in the accessor (row) function?

  • Why do I need the row iterator (i) argument in the accessor function?


Answer

What is the underlying parse function that maps the third (columns) argument to the column names in the accessor (row) function?

The accessor function, also known as the row conversion function, is a function invoked for each row, and it takes 3 arguments (which will answer your second question further down):

  • The first argument is the row
  • The second argument is the index, starting at zero
  • The third argument is the column names array

This third argument is interesting, and it was introduced in D3 v4.x. I believe that it answers your first question:

When you load a CSV (or a TSV), d3.csv (or d3.tsv) creates an array property with the headers, named columns (take care with loops like a for...in loop, because it will include that property) . In the case of your example, it is:

columns: ["Code", "k1", "k2"]

And it lead us to your second question:

Why do I need the row iterator (i) argument in the accessor function?

You don't. The thing is that this piece of code uses the third argument, which is the columns property, and to get to the third we have to supply 2 arguments before that:

.row(function(d, i, columns){ d.total = columns.length; return d;}) 
//3rd argument---------^

So, what that code does is getting the value of columns.length, which is 3, and creating a new property to each object:

d.total = columns.length; return d;

So, the objects will end up like this:

{Code: "pf_1", k1: "0.2", k2: "0.3", total: 3}

With the new property total.