3

I followed the following SA question to build a stacked bar chart using <path> instead of <rect>, so I can style the top bar part to have a rounded corner.

How to Make a bar chart with rounded corners with extended grid in d3.js?

Here is a code pen with my code showing my code and the wrong effect: https://codepen.io/Yeronimo/pen/jOPWBGL

The problem is that the stacked bars align at the top.

I have tried many changes to the bar function and the calling "attr d" function, but I seem to be only making things worse. Any help would be appreciated.

And here a poorly shopped image of what it should look like. So the idea is that the bars have the correct height and correct order in my current code, just that they should be aligning at the bottom. In the image the rounded corners got lost, but they are visible in the pen.

Bars nicely at the bottom

Yeronimo
  • 1,731
  • 15
  • 28
  • the top left corner of the svg is pixel coordinate `0,0`. First, invert the range like `range([height,0])`. Then, to start your bar's path at the x-axis, the y-coordinate is not `0` but the `height` or perhaps it's same as the x-axis. Then you draw a line "up" to the "range" value of the `yscale(d[1])`. – varontron Feb 14 '20 at 02:11

1 Answers1

4

Change the base y of the bars from yscale(d[1]) to yscale(0) like the following:

return bar((xscale(xlabels[i]) + (xscale.bandwidth() / num_groups) * gnum) + 5,
            yscale(0),
            14,
            yscale(d[1]), s);

Now the bars will be upright. But don't be fooled. The stacks that appear on the graph are not correct, and do not reflect the data properly. That is because the h parameter in the bar function is the height of the bar, and d[1] is, in fact, y - h. So the bar function needs to be corrected.

function bar(x, y, w, y1, r, f) {
    // Flag for sweep:
    if (f == undefined) f = 1;
    // x coordinates of top of arcs
    var x0 = x + r;
    var x1 = x + w - r;
    // y coordinates of bottom of arcs
    var y0 = y1 + r;
    // just for convenience (slightly different than above):
    var l = "L", a = "A";

    var parts = ["M", x, y, l, x, y0, a, r, r, 0, 0, f, x0, y1, l, x1, y1, a, r, r, 0, 0, f, x + w, y0, l, x + w, y, "Z"];
    return parts.join(" ");
}

The same effect can be achieved by calling the original bar with yscale(0) - yscale(d[1]), but this will create unnecessary redundancy. Now the bars are in their correct sizes.

However, the shorter bars are now hidden behind the longer ones in each stacks. So the draw order of the bars need to be reversed. Alter the datasets as such, performing stack.reverse() for each stack.

var datasets = [
            d3.stack().keys(['LKV', 'SROI', 'NoRisk'])(data).reverse(),
            d3.stack().keys(['LKV1', 'SROI1', 'NoRisk1'])(data).reverse(),
            d3.stack().keys(['LKV2', 'SROI2', 'NoRisk2'])(data).reverse()
        ];

That's it. Here's my version.

Hurried-Helpful
  • 1,850
  • 5
  • 15