Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Stacked Area in D3.js

I'm using D3.js and I'm having trouble setting up a stacked layout for an area chart with multiple series. I have two possible structures of my data (if that helps). One is the raw data fed to the script, in this structure:

var data = [{key: 'Group1', value: 37, date: '04/23/12'},
           {key: 'Group2', value: 12, date: '04/23/12'},
           {key: 'Group3', value: 46, date: '04/23/12'},
           {key: 'Group1', value: 32, date: '04/24/12'},
           {key: 'Group2', value: 19, date: '04/24/12'},
           {key: 'Group3', value: 42, date: '04/24/12'},
           {key: 'Group1', value: 45, date: '04/25/12'},
           {key: 'Group2', value: 16, date: '04/25/12'},
           {key: 'Group3', value: 44, date: '04/25/12'},
           {key: 'Group1', value: 24, date: '04/26/12'},
           {key: 'Group2', value: 52, date: '04/26/12'},
           {key: 'Group3', value: 64, date: '04/26/12'}]

Second is a nested structure, created using this code:

 pData = d3.nest()
            .key(function(d) { return d.key; })
            .map(data);

Resulting in this structure:

pData = {Group1: [{date: 04/23/12, key: "Group1", value: 37}, 
                  {date: 04/24/12, key: "Group1", value: 32}, 
                  {date: 04/25/12, key: "Group1", value: 45},
                  ...],
         Group2: [{date: 04/23/12, key: "Group2", value: 12},
                  {etc, etc, etc}],
         GroupX: [...] }

My questions is: How do I setup a d3.layout.stack() generator, using one of the above data structures (or some variation), to create a stacked structure for my data such that I can pass it to an area generator similar to this:

var areaGenerator = d3.svg.area()
    .interpolate('monotone')
    .x(function(d) { return x(d.date); })
    .y0(h)
    .y1(function(d) { return y(d.value); });
like image 227
mbeasley Avatar asked Jun 28 '12 14:06

mbeasley


1 Answers

You must feed an array of layers to the stack layout, so the first thing to change is to use nest.entries rather than nest.map. This returns an array of objects with a key field (such as "Group1") and a values array which contains the associated records. You would then specify a stack.values accessor so that the stack layout can access the values array for each layer.

You will also need to define suitable x and y accessors to the stack layout so that it can understand your input data: the x-accessor should return d.date, and the y-accessor should return d.value. You will also need to convert your date strings to Dates; you can use d3.time.format to help with this. For example:

var format = d3.time.format("%m/%d/%y");
data.forEach(function(d) { d.date = format.parse(d.date); });

Lastly, change your area definition so that the baseline y0 is defined as y(d.y0) and the topline y1 is defined as y(d.y0 + d.y).

Here's a working example:

  • http://bl.ocks.org/3020685
like image 60
mbostock Avatar answered Oct 08 '22 06:10

mbostock