DominicA
DominicA

Reputation: 45

D3 V3 Stacked Bar Negative Values

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

Answers (2)

DominicA
DominicA

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

Romit
Romit

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

Related Questions