Is it possible to order the segments in a pie chart?

76 views
Skip to first unread message

ben palmer

unread,
Mar 11, 2021, 6:15:42 PM3/11/21
to dc-js user group

I wish to order the segments in a pie chart, based upon another variable in the dimension.

I have tried ordering the group the piechart uses but while the group is ordered correctly  when I console log it, the piechart continues to display the segments in the unordered sequence :-(

example of my ordering
var cashFlowGroup = cashFlowDim.group().reduceSum(function(d){ return d.balout }).order(function(d){ return d.amount;});

Thanks
Ben

Gordon Woodhull

unread,
Mar 11, 2021, 6:40:05 PM3/11/21
to dc-js-us...@googlegroups.com
Did you also set the ordering on the chart?


There are some weird redundancies and contradictions in the library due to its history.

Answering off the top of my head; I’m not sure if this is all you need. Glad to look into it further if this doesn’t work!


On Mar 11, 2021, at 6:16 PM, ben palmer <bent...@gmail.com> wrote:


--
You received this message because you are subscribed to the Google Groups "dc-js user group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to dc-js-user-gro...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/dc-js-user-group/41404de3-f728-45d2-b77f-9dc45c6593acn%40googlegroups.com.

ben palmer

unread,
Mar 11, 2021, 7:13:51 PM3/11/21
to dc-js-us...@googlegroups.com
thanks, no doubt I am doing something wrong but I get
dash.js:287 Uncaught (in promise) ReferenceError: pluck is not defined


 cashFlowChart
          .width(400)
          .height(400)
          .dimension(cashFlowDim)
          .group(cashFlowGroup)
          .ordering(pluck('amount'))
          .legend(dc.legend());

Gordon Woodhull

unread,
Mar 11, 2021, 7:24:49 PM3/11/21
to dc-js-us...@googlegroups.com
Rats. pluck() was removed because it’s not all that useful if you have arrow functions. But clearly we forgot to check the docs.

The equivalent in ES6 is

.ordering(({key}) => key)

In your case you want amount not key.

I’ll file an issue for the documentation!


On Mar 11, 2021, at 7:14 PM, ben palmer <bent...@gmail.com> wrote:



Gordon Woodhull

unread,
Mar 11, 2021, 7:33:19 PM3/11/21
to dc-js-us...@googlegroups.com
Er, it’s not removed yet but it’s called dc.pluck().

It will be removed in dc@5




On Mar 11, 2021, at 7:24 PM, Gordon Woodhull <gor...@woodhull.com> wrote:



ben palmer

unread,
Mar 11, 2021, 7:40:12 PM3/11/21
to dc-js-us...@googlegroups.com
Ahh cool, well the ordering arrow function is certainly ordering the chart, although not in the order I expected, rather alphabetically by label not by the amount value.

  Without ordering they are ordered by the segment size (sadly this is not the amount value as the segments are abs(amount)


ben palmer

unread,
Mar 11, 2021, 7:41:48 PM3/11/21
to dc-js-us...@googlegroups.com
dc.pluck('amount') does the same, ordered by label, alphabetically

Gordon Woodhull

unread,
Mar 11, 2021, 7:45:10 PM3/11/21
to dc-js-us...@googlegroups.com
Wtf. That makes no sense at all! 

I will have to work on an example for you tomorrow when I’m back at the computer.

It is definitely possible. Some things are a little convoluted, but most things are possible...


On Mar 11, 2021, at 7:42 PM, ben palmer <bent...@gmail.com> wrote:



ben palmer

unread,
Mar 11, 2021, 7:52:03 PM3/11/21
to dc-js-us...@googlegroups.com
thank you I would be very grateful, if I could order this graph I can remove two others from my dashboard :-)

Gordon Woodhull

unread,
Mar 12, 2021, 9:08:31 AM3/12/21
to dc.js user group
Okay, I worked up a demo.


I guess I must be missing part of your question, because it works as I would expect:

- with ordering commented out, it's alphabetical ordering clockwise from the top, because the default ordering by value fails on object values, leaving group.all()'s default key sorting
- with .ordering(({value: {value2}}) => value2) it sorts from least value2 to greatest 
- with .ordering(({value: {value2}}) => -value2) it sorts from greatest value2 to least 
- with .ordering(({value: {value1}}) => -value1) it sorts from greatest value1 to least (descending order by slice size)

Probably using -valueAccessor()(d) would be a better default than the current default -d.value which breaks on object values.

I wonder if maybe you were missing the group object reduction? The original values from the array are not available unless you expose them through the reduction, and like the first case, you'll end up with the default key ordering if values are not sortable.


ben palmer

unread,
Mar 13, 2021, 1:49:28 AM3/13/21
to dc-js-us...@googlegroups.com
Thank you so much, yes this worked for me too.
I was using 
var cashFlowGroup = cashFlowDim.group().reduceSum(function(d){ return d.balout });

for my grouping, not reduce.

You received this message because you are subscribed to a topic in the Google Groups "dc-js user group" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/dc-js-user-group/Ui_D_SQG7UU/unsubscribe.
To unsubscribe from this group and all its topics, send an email to dc-js-user-gro...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/dc-js-user-group/31ABB5BC-B8D1-45F5-A1E9-09954375F9A0%40woodhull.com.

ben palmer

unread,
Mar 15, 2021, 11:02:53 AM3/15/21
to dc-js-us...@googlegroups.com
Sorry to bother you again, but I have a follow on question,

Can I select different colour ranges (arrays) based upon the ordering key, for example green range of colours for positive numbers, red range for negative?

I have managed to get two colours, but not two ranges of multiple colours :-(


.colors(d3.scaleOrdinal().domain(["positive", "negative"])
                         .range(['#f2ffe6','#cc2900']))
.colorAccessor(function (d, i){  return (d.value.order>0)?"positive":"negative";})

thank you
Ben

Gordon Woodhull

unread,
Mar 15, 2021, 11:16:21 AM3/15/21
to dc.js user group
Sure. That sounds like a diverging scale, but there are many options in d3-scale so it's worth exploring.

Using the previous example, with white for the zero point in the middle:

  .colorAccessor(({value: {value2}}) => value2)
  .colors(d3.scaleDiverging([-10,0,10], ['red','white','green'], d3.interpolateSpectral))





ben palmer

unread,
Mar 15, 2021, 11:45:39 AM3/15/21
to dc-js-us...@googlegroups.com
thank you, that works, I will investigate further.

ben palmer

unread,
Mar 16, 2021, 8:34:18 PM3/16/21
to dc-js-us...@googlegroups.com
Hi I have had a play, but I need a way to update the colour range based on filter, or set a hard change at when the value crosses zero. Problem is as you use filters displayed range can get quite small so all similar coloured, were I really want a hard change of colour at 0.

(( see attached ))
Full range
Screen Shot 2021-03-17 at 11.10.06 am.png

Filtered
Screen Shot 2021-03-17 at 11.11.01 am.png

Gordon Woodhull

unread,
Mar 16, 2021, 9:01:29 PM3/16/21
to dc-js-us...@googlegroups.com
Looking good!

A good place to set the domain of any scale is the preRedraw event handler (and preRender if desired).

Setting the domain at that point has exactly the same effect as the elastic setting available for some scales (but not color).

You should be able to find plenty of examples for preRedraw with a quick search. Pair it with d3.extent and it should write itself, but lmk if you run into trouble.


On Mar 16, 2021, at 8:35 PM, ben palmer <bent...@gmail.com> wrote:


Hi I have had a play, but I need a way to update the colour range based on filter, or set a hard change at when the value crosses zero. Problem is as you use filters displayed range can get quite small so all similar coloured, were I really want a hard change of colour at 0.

(( see attached ))
Full range
<Screen Shot 2021-03-17 at 11.10.06 am.png>


Filtered
<Screen Shot 2021-03-17 at 11.11.01 am.png>

On Tue, Mar 16, 2021 at 2:45 AM ben palmer <bent...@gmail.com> wrote:
thank you, that works, I will investigate further.

On Tue, Mar 16, 2021 at 2:16 AM Gordon Woodhull <gor...@woodhull.com> wrote:
Sure. That sounds like a diverging scale, but there are many options in d3-scale so it's worth exploring.

Using the previous example, with white for the zero point in the middle:

  .colorAccessor(({value: {value2}}) => value2)
  .colors(d3.scaleDiverging([-10,0,10], ['red','white','green'], d3.interpolateSpectral))

<PastedGraphic-1.png>

ben palmer

unread,
Mar 17, 2021, 12:28:24 AM3/17/21
to dc-js-us...@googlegroups.com
Thank you, you are being a great help, thinking about it, 

I am displaying a number of graphs where items are grouped based upon the value of one of the data fields.

It would be great for consistency if I could associate a colour with each value, embed while doing the initial data clean up pass.

Can the colour be set on each segment / bar component based upon a data field?

Thanks
Ben

Gordon Woodhull

unread,
Mar 17, 2021, 10:05:28 AM3/17/21
to dc.js user group
Glad to help.

It sounds like you are talking about other charts, with categorical domains and ordinal scales for applying colors. Certainly the same ordinal scale can be used across multiple charts to apply the same colors for the same categories.

Is that what you're asking?



Reply all
Reply to author
Forward
0 new messages