Roger A. Leite
Roger A. Leite

Reputation: 396

How to change bars colors based on a data dimension?

First of all, here is a simple fiddle that I did in order to aid in my question:

jsfiddle.net/rogeraleite/xbd0zpzn/4

...based on the chart displayed on fiddle, the task that I am trying to do is:

turn into red the bars which the owners had at least one "approved_flag == 0" (for this data, Mike`s bar would became red).

It looks simple, but I still not able to do that =/.

Code I am using:

var experiments = [
    { Name: "Mike", amount: 26.9, approved_flag: 1 },
    { Name: "Mike", amount: 2.9, approved_flag: 1 },
    { Name: "Mike", amount: 14.9, approved_flag: 0 },
    { Name: "John", amount: 22.5, approved_flag: 1 },
    { Name: "John", amount: 13.5, approved_flag: 1 },
    { Name: "Firen", amount: 44.3, approved_flag: 1 },
    { Name: "Firen", amount: 24.3, approved_flag: 1 }    
];

var ndx = crossfilter(experiments);
var all = ndx.groupAll();

var nameDimension = ndx.dimension(function (d) { return d.Name; });

var nameGroup = nameDimension.group().reduceSum(function (d) { return d.amount; });

var chart1 = dc.barChart('#rowChart');

chart1.width(600)
    .height(250)
    .margins({ top: 10, right: 10, bottom: 20, left: 40 })
    .dimension(nameDimension)
    .group(nameGroup)
    .transitionDuration(500)
    .colors('teal')
    .elasticY(false)
    .brushOn(false)
    .valueAccessor(function (d) {
        return d.value;
    })
    .title(function (d) {
        return "\nNumber of Povetry: " + d.key;
    })
    .x(d3.scale.ordinal().domain(nameDimension.top(Infinity).map(function(d) {return d.Name})))
    .xUnits(dc.units.ordinal)
    .legend(dc.legend().x(45).y(20).itemHeight(8).gap(4));
dc.renderAll();

thanks in advance for helping me, --Roger

Upvotes: 3

Views: 70

Answers (1)

Gordon
Gordon

Reputation: 20150

You're essentially reducing two values for each group, so you'll need a custom reduction to do this. What's interesting is that you have to track whether another filter causes the last false approved_flag to be removed from a group. But this is really not more complex once you're using a custom reduction: we'll just keep a count of the number of false approved_flag.

It is probably easier with reductio, but here is the straight crossfilter way:

var nameGroup = nameDimension.group().reduce(
    function (p, v) { // add
        p.amount += v.amount
        if(!v.approved_flag)
            p.unapproved++;
        return p;
    },
    function (p, v) { // remove
        p.amount -= v.amount
        if(!v.approved_flag)
            p.unapproved--;
        return p;
    },
    function () { // initialize
        return {amount: 0, unapproved: 0};
    }
);

By default the bar chart only assigns colors based on the stacking layer. For this simple two-color case we can just short-circuit the colors scale and return the color name from the colorAccessor:

.colors(function(x) { return x; })
.colorAccessor(function(d) {
    return (!this.name && d.value.unapproved) ? 'red' : 'teal';
})

Fork of your fiddle with these additions here: http://jsfiddle.net/gordonwoodhull/6L2kryvq/17/

EDIT: updated fiddle and colorAccessor because first try was breaking the legend, which passes a layer instead of datum.

Upvotes: 2

Related Questions