Reputation: 4126
I am trying to follow this example: http://bl.ocks.org/mbostock/3886208
In my application I have to show a stacked bar chart where I can see for example how many different animals specific user bought.
Here is my object:
[["PersonName1", 10, 10],["PersonName2", 4, 16]];
First property is name, second is animal type 1, and third is animal type 2.
I've got stuck in this foreach loop:
data.forEach(function(d) {
var y0 = 0;
d.ages = color.domain().map(function(name) {
return {name: name, y0: y0, y1: y0 += +d[name]};
});
d.total = d.ages[d.ages.length - 1].y1;
});
What exactly do the code lines below do?
d.ages = color.domain().map(function(name) {
return {name: name, y0: y0, y1: y0 += +d[name]};
});
I can't exactly figure out how to do the same thing with my objects.
I've tried to do something like this:
scope.data.forEach(function(d) {
var y0 = 0;
d.animals = color.domain().map(function(name) {
return {name: d[0], y0: y0, y1: y0 += +d[1]};
});
d.total = d.animals[d.animals.length - 1].y1;
});
But d.animals is always empty.
And i have to use it later on in:
state.selectAll("rect")
.data(function(d) { return d.animals; })
.enter()
.append("rect")
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.y1); })
.attr("height", function(d) { return y(d.y0) - y(d.y1); })
.style("fill", function(d) { return color(d.name); });
Any ideas?
Upvotes: 1
Views: 2413
Reputation: 27544
That particular bit of code is just a rather confusing way of converting all the values in the row into an array of cumulative values. It depends on the previous line of code, where the domain of the color scale is defined as all the keys from the first data object (i.e., all the column names in the csv file) except for "State". It then maps this array of column names to an array of objects, each of which contains the column name, the total of all previous values (y0
), and the new total created by adding the corresponding data value (extracted from the data-row object with data[name]
) to the old total. In addition to being assigned to the y1
property of the object in the ages
array, the new total is assigned to the y0
variable so that it carries over for mapping the next value in the array.
This wasn't working for you, because your data rows are represented as arrays, not as key:value objects created from reading a csv file. So you aren't able to create an array of column names, and you aren't able to use those names to access the data. You'll have to create the sub-arrays yourself, using array index numbers to access the different data values.
If that's still confusing, I would recommend you look at this or this example, which both use the d3 stack layout object to calculate the top and bottom positions of the stacked bars.
Regardless of how you do the calculation, the end goal is to create a sub-array for each of your data rows, containing objects for each of the values that you want to stack. Each object needs to have a y0
value representing the total of all previous values in the stack (i.e., the bottom of the bar), and a y1
value representing the total of that bar and all the previous ones (i.e., the top of the bar).
You could just save the height of the bar instead of one of these values, but the stack layout creates the y0/y1 structure, since it is easy to use with stacked area graphs. An area is defined by the position of the lines, not by the height.
Upvotes: 2