Reputation: 45
I'm using a D3 V3 stacked bar like in this plunker:
http://plnkr.co/edit/rjO5vgYyeytTJjuv4emB?preview
My question is how would i render a stacked bar using this multiple measure method with some negative values, i.e. if the rect is negative then have it below the y-axis zero line and combine this with rects with positive values rendering above the y-axis zero line?
I've tried changin the rect y and height like:
//adding the rect for group chart
state.selectAll("rect")
.data(function(d) { return d.group; })
.enter().append("rect")
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(Math.max(0, d.y1)); })
.attr("height", function(d) { return Math.abs((y(d.y0) - y(d.y1))-y(0)); })
.style("fill", function(d) { return color(d.name); });
I've been trying but I'm a D3 noob so advice would be very welcome.
Thanks
Dom
Upvotes: 0
Views: 367
Reputation: 45
your solution didn't work but your suggestion about altering the data object was a good one, in the end I changed the data object like:
//get group and total for stack
vars.data.forEach(function (d) {
var y0 = 0;
var y0n = 0;
d.group = color.domain().map(function (name) {
return {
name: name,
yt: d[name] < 0 ? 1 : 0,
y0: y0,
y1: (y0 += +Math.max(0, d[name])),
y0n: y0n,
y1n: (y0n += +Math.min(0, d[name])),
dimension: d.dimension,
qElemNumber: d.qElemNumber,
};
});
d.total = d.group[d.group.length - 1].y1;
d.totaln = d.group[d.group.length - 1].y1n;
});
so I created y0n and y1n for negative values and yt as an indicator that shows if the value is negative or not, then you can apply the y and height like:
.attr("y", function (d) {
if (d.yt === 1) {
return y(d.y0n);
}
return y(d.y1); //NEGFIX NEEDED
})
.attr("height", function (d) {
if (d.yt === 1) {
return Math.abs(y(d.y0n) - y(d.y1n));
}
return y(d.y0) - y(d.y1); //NEGFIX NEEDED
})
hopefully thi will help anyone looking for a similar fix :)
cheers
Dom
Upvotes: 0
Reputation: 338
A great idea would be to store the actual heights in the data object even if the values are negative.
This may be the solution that you need:
var y = d3.scale.linear()
.rangeRound([height/2, 0]);
state.selectAll("rect")
.data(function(d) {
return d.group;
})
.enter().append("rect")
.attr("width", x.rangeBand())
.attr("y", function(d) {
if(d.y1 < 0){
return y(d.y0)
}
return y(d.y1);
})
.attr("height", function(d) {
return Math.abs(y(d.y0) - y(d.y1));
})
.style("fill", function(d) {
return color(d.name);
});
Upvotes: 0