D3: Binding Multi-Dimensional Arrays and Deep Nested Data

The easiest way to work with D3 data arrays is to create simple arrays. For example, to create a stacked array, represent each stack in a stacked bar by the a comma separated value in a row per bar.

state, males, females
CT, 125, 135
NY, 240, 250

But if you are retrieving data from an open data API via REST for instance or if you want to use dynamic data visualizations where the visualization depends on user input, it is easier to use the built-in d3.nest function. For example, the following data comes from http://www.clinicaltrials.gov and is formatted as a .csv file:

"nct_id","gender","status","phase","city","state","minimum_age","maximum_age"
"NCT00000102","Both","Completed","Phase 1/Phase 2","Charleston","South Carolina","14 Years","35 Years",
"NCT00000104","Female","Completed","N/A","Minneapolis","Minnesota","N/A","N/A",
"NCT00000105","Male","Completed","Phase 3","Charleston","South Carolina","10 Years","14 Years",

If you use a simple nested array with one level of parent-child structure, it is straightforward to bind data to your elements.

var data1 = d3.nest()
  .key(function(d) { return d.state; }).sortKeys(d3.ascending)
  .entries(data);

Using the d3.nest() function with a single key generates the following data array structure.

[{
"key":"South Carolina",
"values":[{
  "nct_id":"NCT00000102",
  "gender":"Both",
  "status":"Completed"
},{
  "nct_id":"NCT00000105",
  "gender":"Male",
  "status":"Completed"
}]
},{
"key":"Minnesota",
"values":[{
  "nct_id":"NCT00000104",
  "gender":"Female",
  "status":"Completed"
}
}]

To create a div list of all 52 states in the data file (including “Washington DC”), write the following.

var log = body1.selectAll("div")
  .data(data1)
  .enter()
  .append("div")
  .html(function(d,i){return (i+1)+". "+d.key;});

When you create a multidimensional nested array using the d3.nest() function with multiple keys, accessing data becomes less obvious.

var data1 = d3.nest()
  .key(function(d) { return d.state; }).sortKeys(d3.ascending)
  .key(function(d) { return d.gender; }).sortKeys(d3.ascending)
  .rollup(function(d) { return d.length; })
  .entries(data);

Using the d3 code above with multiple keys in the d3.nest() function and a rollup function to generate a count(*) property, generates the following multi-dimensional array:

[{
  "key":"South Carolina",
  "values":[{
    "key":"Both",
    "values": 143
  },{
    "key":"Male",
    "values": 124
  }]
},{
  "key":"Minnesota",
  "values":[{
    "key":"Female",
    "values": 316
  }]
}]

Let’s generate a div list of all studies per gender per state.

To create this list, write the following code.

var log = body1
  .selectAll("div")
    .data(data1)
    .enter()
    .append("div")
    .html(function(d,i){return (i+1)+". "+d.key+" ("+d3.sum(d.values, function(d){ return d.values;})+")";})
    .style("background-color","lightgray")
  .selectAll("div")
    .data(function(d1){return d1.values;})
    .enter()
    .append("div")
    .html(function(d2){return "gender:"+d2.key+", studies:"+d2.values;})
    .style("background-color","white");

Note that in the second data property, the following div elements are bound to the second level in the nested array.

2 thoughts on “D3: Binding Multi-Dimensional Arrays and Deep Nested Data

  1. linda

    Not sure why you would do this:

    .html(function(d,i){return (i+1)+”. “+d.key;});

    instead of

    .html(function(d,i){return (“”+d.key;});

    inside an ordered list tag.

    My way allows you to style the list. You can also add classes to the li tag if you want certain states to look different.

    Reply
  2. linda

    I was afraid of that. My tags got lost. So I’ll just explain. Use list item li tags for each datum and wrap inside an ordered list ol tag.

    Reply

Leave a Reply to linda Cancel reply

Your email address will not be published. Required fields are marked *