Currently, I have an area graph that displays the areas of several paths of data. However, I'm looking for a way to convert this to a stacked area chart. Basically, I want the datasets to be stacked on top of each other so that they are visible and do not get hidden by other larger areas.
I've found two examples: http://bl.ocks.org/mbostock/3885211 and http://bl.ocks.org/mbostock/3020685. The problem I have is that my data is in a very different format and I'm also unsure of how d3 is actually making this work. Conceptually, I'm having a difficult time understanding what d3 is doing behind the scenes. My understanding is that it is computing the differences between the last layer added but it seems like that could be done without using stacks.
My data is structured like this:
// datasets { data1: Array[10], data2: Array[10], data3: Array[10] }
// data1 [{value: 2340234, year: 1945}...]
And the drawing function is this:
function draw(series) {
var data1 = [];
var data2 = [];
var data3 = [];
var prop = 0;
for (prop in series) {
var current = series[prop];
data1.push({value: current.data1, year: current.year});
data2.push({value: current.data2, year: current.year});
data3.push({value: current.data3, year: current.year});
}
var datasets = {
data1: data1,
data2: data2,
data3: data3
};
// updated
var layers = [datasets.data1, datasets.data2, datasets.data3];
var height = 800;
var width = window.innerWidth - 100;
var x = d3.time.scale()
.range([0, width]);
var y = d3.scale.linear()
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
// updated
var stack = d3.layout.stack()
.values( function(d) { return d.values; });
/
var stacked = stack(layers.map( function(layer) {
return {
values: layer.map( function(d) {
return { year: new Date(d.year, 0), y: +d.value};
})
};
}));
var area = d3.svg.area()
.x( function(d) {
console.log( x(d.year) + ' is the result of x(d.year)' )
return x(d.year);
})
// d.year is defined correctly
.y0(height)
.y1( function(d) {
console.log( y(d.value) + ' is the result of y(d.value)' )
return y(d.value);
});
// d is Object {year: Sat Jan 01 2005 00:00:00 GMT-0800 (PST), y: 47390331, y0: 0}
// here y(d.value) returns NaN for some reason
var svg = d3.select('body').append("svg")
.append("g")
.attr("transform", "translate(" + 120 + "," + 30 + ")");
// Calculate max value
var maxY = 0;
var minY = 0;
series.forEach( function(object) {
for (var key in object) {
if (object[key] > maxY) {
maxY = object[key];
}
}
});
// Calculate min value
series.forEach( function(object) {
for (var key in object) {
if (object[key] < minY) {
minY = object[key];
} else if (minY === 0) {
continue;
}
}
});
var minYear = new Date("1945");
var maxYear = new Date("2015");
x.domain([minYear, maxYear]);
y.domain([minY, maxY]);
svg.append("path").data(stacked)
.attr('d', function(d) { return area(d.values); });
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
}
What is the best way to convert this into a stacked area chart?
Edit
Fixed. Solution included calculating area like seen in the example:
var area = d3.svg.area()
.x(function(d) { return x(d.year); })
.y0(function(d) { return y(d.y0); })
.y1(function(d) { return y(d.y0 + d.y); });