Reputation: 582
I cannot find an example of this anywhere and I have spent weeks (on and off) trying to figure it out. Plain and simple, I want to graph data in a stack layout with the 'x' as a date and the 'y' as a numerical value using D3js. I was able to get just a stack working and I was able to get a bar chart working, but combining them has been a headache.
My most current iteration takes this example here [http://chimera.labs.oreilly.com/books/1230000000345/ch11.html#_stack_layout] and strips it down to the most basic it can be. Everything except the data itself (and I guess the colors) is hard coded to eliminate as many issues as possible. Below is the original 'dataset' and my various iterations of my own datasets trying to discover the root of the problem. At one point I had it graphing correctly (see JSBin link below) except it was not stacking properly. It seems as if the x and the y were feeding to graph it, but the y0 was not being set. The out errors have been minimal and not helpful in any manner.
JSBin to graph without properly stacking: http://jsbin.com/bekanowo/1/edit
var dataset = [
[
{ x: 0, y: 5 },
{ x: 1, y: 4 },
{ x: 2, y: 2 },
{ x: 3, y: 7 },
{ x: 4, y: 23 }
],
[
{ x: 0, y: 10 },
{ x: 1, y: 12 },
{ x: 2, y: 19 },
{ x: 3, y: 23 },
{ x: 4, y: 17 }
],
[
{ x: 0, y: 22 },
{ x: 1, y: 28 },
{ x: 2, y: 32 },
{ x: 3, y: 35 },
{ x: 4, y: 43 }
]
];
var backupArray = [
[{y: 50, x: 2014-06-15},{y: 40, x: 2014-06-16},{y: 30, x: 2014-06-18}],[{y: 30, x: 2014-06-19}],
[{y: 35, x: 2014-06-17}],
[{y: 45, x: 2014-06-15}],
[{y: 85, x: 2014-06-19},{y: 65, x: 2014-06-20},{y: 75, x: 2014-06-21},{y: 60, x: 2014-06-22}]
];
var staticArray = [
[{date: "2014-06-15", value: 50},{date: "2014-06-16", value: 40},{date: "2014-06-18", value: 30}],
[{date: "2014-06-15", value: 30}],
[{date: "2014-06-17", value: 35}],
[{date: "2014-06-15", value: 45}],
[{date: "2014-06-19", value: 85},{date: "2014-06-20", value: 65},{date: "2014-06-21", value: 75},{date: "2014-06-22", value: 60}]
];
parseDate = d3.time.format("%Y-%m-%d").parse
var staticArray2 = [
{ category: "test1", values: [{date: parseDate("2014-06-15"), value: 50},{date: parseDate("2014-06-16"), value: 40},{date: parseDate("2014-06-18"), value: 30}] },
{ category: "test1", values: [{date: parseDate("2014-06-15"), value: 30}] },
{ category: "test1", values: [{date: parseDate("2014-06-17"), value: 35}] },
{ category: "test1", values: [{date: parseDate("2014-06-15"), value: 45}] },
{ category: "test1", values: [{date: parseDate("2014-06-19"), value: 85},{date: parseDate("2014-06-20"), value: 65},{date: parseDate("2014-06-21"), value: 75},{date: parseDate("2014-06-22"), value: 60}] }
];
var staticArray3 = [
{ name: "test1", values: [{x: parseDate("2014-06-15"), y: 50},{x: parseDate("2014-06-16"), y: 40},{x: parseDate("2014-06-18"), y: 30}] },
{ name: "test2", values: [{x: parseDate("2014-06-15"), y: 30}] },
{ name: "test3", values: [{x: parseDate("2014-06-17"), y: 35}] },
{ name: "test4", values: [{x: parseDate("2014-06-15"), y: 45}] },
{ name: "test5", values: [{x: parseDate("2014-06-19"), y: 85},{x: parseDate("2014-06-20"), y: 65},{x: parseDate("2014-06-21"), y: 75},{x: parseDate("2014-06-22"), y: 60}] }
];
Below is the raw code (without the datasets). I didn't want to lose any of my sample datasheets so I just left them be as I iterated through tests and just set the current array a few lines in.
<script type="text/javascript">
//Width and height
var w = 500;
var h = 300;
//set test array
var dataset = staticArray3;
//Set up stack method
var stack = d3.layout.stack()
.offset("zero")
.y(function(d) { return d.values; });
//Set up scales
var xScale = d3.time.scale()
.domain([parseDate("2014-06-15"), d3.time.day.offset(parseDate("2014-06-22"), 1)])
.rangeRound([0, w], 0.05);
var yScale = d3.scale.linear()
.domain([0,100])
.range([0, h]);
//Easy colors accessible via a 10-step ordinal scale
var colors = d3.scale.category10();
//Create SVG element
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
// Add a group for each row of data
var groups = svg.selectAll("g")
.data(stack(dataset))
.enter()
.append("g")
.style("fill", function(d, i) { return colors(i); });
// Add a rect for each data value
var rects = groups.selectAll("rect")
.data(function(d) { return d; })
.enter()
.append("rect")
.attr("x", function(d) { return xScale(d.date); })
.attr("y", function(d) { return yScale(d.y0); })
.attr("height", function(d) { return yScale(d.value); })
.attr("width", 60);
</script>
Upvotes: 0
Views: 130
Reputation: 418
the problem might be that you do not use the stack-layout properly which leaves your dataset without the y0. the reason why it seems to work is that your code is drawing rects, starting from a missing y0 to the height of your values.
first, you should try to have a consistent dataset, meaning that each array should contain all the dates, just set the missing values to zero. and it seems you have to change "value" to "y":
var staticArray2 = [
[{date: parseDate("2014-06-15"), y: 50},{date: parseDate("2014-06-16"), y: 40},{date: parseDate("2014-06-17"), y: 0},{date: parseDate("2014-06-18"), y: 30},{date: parseDate("2014-06-19"), y: 0},{date: parseDate("2014-06-20"), y: 0},{date: parseDate("2014-06-21"), y: 0},{date: parseDate("2014-06-22"), y: 0}],
[{date: parseDate("2014-06-15"), y: 30},{date: parseDate("2014-06-16"), y: 0},{date: parseDate("2014-06-17"), y: 0},{date: parseDate("2014-06-18"), y: 0},{date: parseDate("2014-06-19"), y: 0},{date: parseDate("2014-06-20"), y: 0},{date: parseDate("2014-06-21"), y: 0},{date: parseDate("2014-06-22"), y: 0}],
[{date: parseDate("2014-06-15"), y: 0},{date: parseDate("2014-06-16"), y: 0},{date: parseDate("2014-06-17"), y: 35},{date: parseDate("2014-06-18"), y: 0},{date: parseDate("2014-06-19"), y: 0},{date: parseDate("2014-06-20"), y: 0},{date: parseDate("2014-06-21"), y: 0},{date: parseDate("2014-06-22"), y: 0}],
[{date: parseDate("2014-06-15"), y: 45},{date: parseDate("2014-06-16"), y: 0},{date: parseDate("2014-06-17"), y: 0},{date: parseDate("2014-06-18"), y: 0},{date: parseDate("2014-06-19"), y: 0},{date: parseDate("2014-06-20"), y: 0},{date: parseDate("2014-06-21"), y: 0},{date: parseDate("2014-06-22"), y: 0}],
[{date: parseDate("2014-06-15"), y: 0},{date: parseDate("2014-06-16"), y: 0},{date: parseDate("2014-06-17"), y: 0},{date: parseDate("2014-06-18"), y: 0},{date: parseDate("2014-06-19"), y: 85},{date: parseDate("2014-06-20"), y: 65},{date: parseDate("2014-06-21"), y: 75},{date: parseDate("2014-06-22"), y: 60}]];
then use
var stack = d3.layout.stack();
var dataset = stack(staticArray2);
and finally change your d.value
to
.attr("height", function(d) { return yScale(d.y); })
the output might look a bit strange because many of your values are zero, so some stacks start at the baseline, but as they are not "stack 0" they have a different - the corresponding - color.
see the jsbin here, i added a mouseover to log the values of the bars to the console: http://jsbin.com/bekanowo/9/
hope this helps.
Upvotes: 1