Search code examples
c3.jsdonut-chart

Conditional colors based on data on Donut chart with C3js


I'd like to know how to create a donut chart in which colors of particular slices are dependent on the data. I managed to achieve this fairly easily in bar charts, using:

color: function (color, d) {

if (d.value < 25) {
 return "#f00";
}

but I can't figure out the donut.

What I mean:

  • There are only two slices (and two data groups), A and B, and each only has 1 value, e.g. A = 35 and B = 65, i.e, just two columns

  • B slice should always have a constant color, e.g. "gray" regardless of its value

  • A slice and its color should be depended on A values, e.g. if value > 50, then color is red, if value > 75, then color is orange, and so on.

For example: A is 45 and B is 55. A slice is red. B is gray. Input data changes (i.e. the chart is refreshed). A is now 60 and B is 40. B is still gray (it always is), but A should be now orange. Input data changes. A is 90, B is 10. B is gray. A is green, and so on.

Many thanks for any help! \o/


Solution

  • I thought this would be simple, but I can't get a handle on the chart object within the color function and 'this' is always either the Window object or undefined.

    This is what i did manage and it involves using an external variable as a cache:

    Basically color gets called with 2 arguments, the first is always the existing colour, and the second can either be the id of the data, or a larger data object including the value for that donut sector. I use the second case to fill in a value to the cache which gets used when the first case is encountered.

    var temp = {};
    var chart = c3.generate({
        data: {
            columns: [
                ['data1', 30],
                ['data2', 120],
            ],
            color: function (color, d) {
                console.log (arguments, this, chart);
                if (d.values) {
                    var id = d.id;
                    var newColour = d.values[0].value > 40 ? "red" : "blue";
                    temp[id] = newColour;
                }
                return temp[d] || color;
            },
            type : 'donut',
        },
        donut: {
            title: "Iris Petal Width"
        }
    });
    

    Copy it into https://c3js.org/samples/chart_donut.html to see it running


    Answer 2

    Actually, another (undocumented) way to do it is like this:

    color: {
        pattern: ['red', 'green', 'blue', 'orange', 'turquoise'], // colors for values
        threshold: {
            values: [30, 60, 90, 100, 150]
        }
    }
    

    A sector takes on the colour in the pattern array at the index of the first threshold value it is less than (e.g. 59 is less than 60 so that value would be green)

    This does stuff up static colours for certain data series though, and any way of doing a continuous colour scale if you ever wanted that