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
Stack does really what it says, stacking graphs, so you as user are responsible for providing the data in the correct format. This makes sense if you think about it, because stack is basically data format agnostic. It provides a great deal of flexibility, with the only restriction that for each layer it can access the same number of points. How would it determine which points are missing? Given that the first layer had five points and the second layer has ten points, is the first layer missing five points? Or are both layer missing points because a third layer contains even more points. And then if points are missing, which ones? At the beginning, at the end, somewhere in the middle? Again there is no sensible way for a stack implementation to figure this out (unless it would force very rigid data structures).
So, but is there nothing you can do? I think you can. I can't give you a full implementation but can give you some pointers in the right direction. We start here:
var stack = d3.layout.stack()
.offset("zero")
.values(function(d) { return d.values; })
Here you just return the values, which in your example will be the result of the nest operator. So at this point you have the ability to "fix" the values.
The first thing you need to do is determining the maximum number of observations.
var nested = nest.entries(data);
var max = nested.reduce(function(prev, cur) {
return Math.max(prev, cur.values.length);
}, 0);
Now the tricky part. Once you know the maximum number of elements, you'll need to adjust the function that is passed to values. Here you'll have to make assumptions on the data. From you question I understand that for some groups values are missing. So there are two possibilities. Either you assume that the group with the maximum number of elements contains all items in the range or you assume a certain range and check all groups if they contain values for each "tick" in your range. So if your range is a date range (as in your example) and you expect for every day (or what ever interval for that matter) a measurement, you'll have to walk the items in the group and fill the gaps yourself. I'll try to give an (untested) example for a numerical range:
// define some calculated values that can be reused in correctedValues
var range = [0, 1];
var step = 0.1;
function correctedValues(d) {
var values = d.values;
var result = [];
var expected = 0;
for (var i = 0; i < values.length; ++i) {
var value = values[i];
// Add null-entries
while (value.x > expected) {
result.push({x: expected, otherproperties_you_need... });
expected += step;
}
result.push(value); // Now add the real data point.
expected = value.x;
}
// Fill up the end of of the array if needed
while(expected < range[1]) {
result.push({x: expected, otherproperties_you_need... });
expected += step;
}
return result;
}
// Now use our costom function for the stack
var stack = d3.layout.stack()
.offset("zero")
.values(correctedValues)
...
As said, this part is untested and not directly solving your problem (as I'm using a numerical range) but I think it should give you an idea on how to solve your problem (and what the actual source of your problem is).