Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to handle layers with missing data points in d3.layout.stack()

Tags:

I'm using d3.stack to create a stacked area chart but I get an error if I have don't have an equal number of items in each layer. I'm starting with an array of data like this:

[      {key:'Group1',value,date},      {key:'Group1',value,date},      {key:'Group1',value,date},      {key:'Group2',value,date},      {key:'Group2',value,date}   ] 

and after I run it through nest() and stack() I end up with this format, as expected:

[      {key: 'Group1',       values: [ {key,value,date}, {key,value,date}, {key,value,date} ] },      {key: 'Group2',       values: [ {key,value,date}, {key,value,date} ]  }   ] 

I have slightly modified a stacked area sample to demonstrate the issue in this jsFiddle: http://jsfiddle.net/brentkeller/rTC3c/2/

If you remove any one of the data points in the sourceData array you'll see the error message "Cannot read property '1' of undefined " in the console.

Is there a way to have d3.stack just assume zero values for the missing data points? If not, is there an elegant solution to fill in the missing values?

like image 734
Brent Keller Avatar asked Feb 05 '13 17:02

Brent Keller


1 Answers

This isn't d3 specific but rather a general solution for filling in the gaps in a array of keyed data. I modified your jsfiddle here with the following function:

function assignDefaultValues( dataset ) {     var defaultValue = 0;     var keys = [ 'Group1' , 'Group2', 'Group3' ];     var hadData = [ true, true, true];     var newData = [];     var previousdate = new Date();     var sortByDate = function(a,b){ return a.date > b.date ? 1 : -1; };      dataset.sort(sortByDate);     dataset.forEach(function(row){         if(row.date.valueOf() !== previousdate.valueOf()){             for(var i = 0 ; i < keys.length ; ++i){                 if(hadData[i] === false){                     newData.push( { key: keys[i],                                     value: defaultValue,                                     date: previousdate });                 }                 hadData[i] = false;             }             previousdate = row.date;         }         hadData[keys.indexOf(row.key)] = true;      });     for( i = 0 ; i < keys.length ; ++i){         if(hadData[i] === false){             newData.push( { key: keys[i], value: defaultValue,                              date: previousdate });         }     }     return dataset.concat(newData).sort(sortByDate); } 

It walks through the given dataset and, whenever it comes across a new date value, assigns a default value to any keys that have not yet been seen.

like image 199
Chris G Avatar answered Sep 19 '22 17:09

Chris G