3
votes

Currently this stacked bar chart is sorted from left to right based on the total of each bar. How would I also sort each individual bar so that instead of sorting each individual bar by the key (i.e. Under 5 years old is at the bottom and 65 years and over is at the top) it would sort each individual bar by the value (largest at the bottom and smallest at the top).

For example:

Currently the CA bar is stacked like this (from bottom to top)

CA,2704659,4499890,2159981,3853788,10604510,8819342,4114496

I would like it stacked like this (from bottom to top)

CA,10604510,8819342,4499890,4114496,3853788,2704659,2159981

Just to be clear, I need to be able to do this on the client side (i.e. changing the order or format of the original data is not an option).

1
You can use stack.order(), but this will affect the order for all bars. I don't think D3 allows you to sort each bar differently (unless you use separate stack layouts for each). - Lars Kotthoff
@LarsKotthoff I don't need to sort each individual bar differently. The sort order within a bar should be the same for all bars (ascending or descending). If you can show me an example of how to use stack.order() to achieve that I would greatly appreciate it. - diasks2
Oh hang on, this example isn't actually using the stack layout. That makes it easier I guess -- all you have to do is sort d.ages as you want it (inside the data.forEach loop). You could even do different orders for different bars! - Lars Kotthoff
@LarsKotthoff Could you show me a code example based on the bar chart I listed in the question? I'm having a hard time getting what you suggested to work. - diasks2

1 Answers

6
votes

The bar chart example you've linked to gets the order of the values directly from the CSV (through the domain of the colour scale). The actual stacking is done in this line:

d.ages = color.domain().map(function(name) { return {name: name, y0: y0, y1: y0 += +d[name]}; });

The stacking order depends on the order the names are returned by color.domain(). To change the order, all you need to do is sort the values you're getting there. To sort them, for each bar individually, by the values of the individual segments, you can use

var order = color.domain().map(function(d) { return d; })
                 .sort(function(a, b) { return +d[b] - +d[a]; });

This gets the names from the domain of the colour scale and then sorts them in descending order by the values, which are referenced in the sort function. This new array order is then used for the stacking:

d.ages = order.map(function(name) { return {name: name, y0: y0, y1: y0 += +d[name]}; });

The rest of the code remains unchanged. Complete demo here.