arjun010
arjun010

Reputation: 139

inverting a stacked bar chart in d3.js

I was trying to understand d3 layouts and was making a simple stacked bar chart with only one stack. My current code is as below:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <script type="text/javascript" src="d3/d3.js"></script>
        <style type="text/css">
        </style>
    </head>
    <body>
        <script type="text/javascript">

            var w = 500;
            var h = 300;


            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 stack = d3.layout.stack();

            stack(dataset);

            //Setting up scales
            var xScale = d3.scale.ordinal()
                .domain(d3.range(dataset[0].length))
                .rangeRoundBands([0, w], 0.05);

            var yScale = d3.scale.linear()
                .domain([0,             
                    d3.max(dataset, function(d) {
                        return d3.max(d, function(d) {
                            return d.y0 + d.y;
                        });
                    })
                ])
                .range([0,h]);

            var colors = d3.scale.category10();

            var svg = d3.select("body")
                        .append("svg")
                        .attr("width", w)
                        .attr("height", h);

            // Adding a group for each row of data
            var groups = svg.selectAll("g")
                .data(dataset)
                .enter()
                .append("g")
                .style("fill", function(d, i) {
                    return colors(i);
                });

            // Adding a rect for each data value
            var rects = groups.selectAll("rect")
                .data(function(d) { return d; })
                .enter()
                .append("rect")
                .attr("x", function(d, i) {
                    return xScale(i);
                })
                .attr("y", function(d) {
                    return yScale(d.y0);
                })
                .attr("height", function(d) {
                    return yScale(d.y);
                })
                .attr("width", xScale.rangeBand());

        </script>
    </body>
</html>

This leads to the bar coming downwards (I understand that this is because of how SVG positions i.e. 0,0 at the top left.) I simply want to invert my chart and have the bar going up. I tried reversing the yScale range and also the obvious solution of setting the "y" of the rect to (h-d.yo). Neither of them have worked and I am really confused as to where I am going wrong. Any help with this would be appreciated.

Upvotes: 1

Views: 711

Answers (1)

Mike Precup
Mike Precup

Reputation: 4228

You can change the y value of the rects to be

return h - yScale(d.y0) - yScale(d.y);

instead of

return yScale(d.y0); 

You were on the right track with h - yScale(d.y0), but doing that would mean the height should be -yScale(d.y), since we flipped the whole bar. The height's negative because what used to be the top edge is now the bottom edge, so we're calculating it from the wrong edge. We need to subtract out the height to get us to the other edge, so that we can have a positive height again.

Upvotes: 1

Related Questions