dc.js - Stacked bar chart with empty bin filter displaying in strange way

1.2k views Asked by At

I'm trying to have a stacked bar chart and remove empty bins, the bar chart doesn't seem to display properly. It's adding whitespace within the bars themselves. The filtering is working fine.

Probably best explained by having a look at this fiddle -

http://jsfiddle.net/northside45/xdcvr2kf/

My filters look like this

var personDim = ndx.dimension(function (d) {return d.person;});
var personDimGroup = personDim.group().reduceSum(function (d) { return d.amount; });
var personDimGroup2 = personDim.group().reduceSum(function(d) {return d.amount2;});    
var personDimGroup_filtered_group = remove_empty_bins(personDimGroup);
var personDimGroup2_filtered_group = remove_empty_bins(personDimGroup2);

Have I done something wrong?

2

There are 2 answers

1
Gordon On BEST ANSWER

Wow, that is pretty awful behavior. What is going on here is that the stack mixin doesn't like having different a different set of X values for each stack. The chart displays fine if remove_empty_bins is not used (as demonstrated by @Cyril's answer, which just disables it).

It's a more difficult problem to remove empty bins across a set of groups and make them all have the same bins. The problem isn't really demonstrated by this data set, because all the bins are used by at least one group, and the remove_empty_bins isn't helpful here, but I think I get what you're looking for.

I think the "easiest" thing to do is to create a combined group with all the data and then use accessors for the stacks:

function combine_groups() {
    var groups = Array.prototype.slice.call(arguments);
    return {
        all: function() {
            var alls = groups.map(function(g) { return g.all(); });
            var gm = {};
            alls.forEach(function(a, i) {
                a.forEach(function(b) {
                    if(!gm[b.key]) {
                        gm[b.key] = new Array(groups.length);
                        for(var j=0; j<groups.length; ++j)
                            gm[b.key][j] = 0;
                    }
                    gm[b.key][i] = b.value;
                });
            });
            var ret = [];
            for(var k in gm)
                ret.push({key: k, value: gm[k]});
            return ret;
        }
    };
}

var combined = combine_groups(personDimGroup_filtered_group, personDimGroup2_filtered_group);

barChart
    .width(500)
    .height(250)
    .dimension(personDim)
    .group(combined, "1", function(d) { return d.value[0]; })
    .stack(combined, "2", function(d) { return d.value[1]; })
    .elasticY(true)
    .elasticX(true)
    .xUnits(dc.units.ordinal)
    .x(d3.scale.ordinal());    

Working fork of your fiddle: http://jsfiddle.net/gordonwoodhull/uwczq9n1/5/

4
Cyril Cherian On

The problem is because in data philip has amount =0. Inside your function, you filter records who have value = 0

function remove_empty_bins(source_group) {
    return {
        all:function () {
            return source_group.all().filter(function(d) {
                return value !=0 ;
            });
        }
    };
} 

Thus the function personDimGroup_filtered_group.all() should return 3 values each for philip,steve and robert but it returns 2 i.e. steve and robert because for philip the value is 0, so the stackbarchart break.

The code should have been:

function remove_empty_bins(source_group) {
    return {
        all:function () {
            return source_group.all().filter(function(d) {
                return true;
            });
        }
    };
}

Working fiddle is here: http://jsfiddle.net/cyril123/xdcvr2kf/4/