doulou
doulou

Reputation: 35

DC.JS/Crossfilter: Percentage on y-axis of a bar chart with linear x-axis?

I want to display percentages on the y-axis of a dc.js barchart that can dynamically change when filtering the chart itself or some other charts.

Here is my case:

var ndx = crossfilter(dataCsvInitial);
var all = ndx.groupAll();
var accCredLimDim = ndx.dimension(function(d) { return d.acct_curr_crlimit;});

Then, I group by bins:

var value_range_credlim = maxCredLim - minCredLim;  // defined earlier...
var nb_of_bins_credlim = 50,
    bin_width_credlim = value_range_credlim/nb_of_bins_credlim;
var accCredLimGrp = accCredLimDim.group(function(d) {return Math.floor(d/bin_width_credlim)*bin_width_credlim;});

And draw my bar chart:

 var creditBar = dc.barChart("#creditDistrib");
        creditBar
            .width(600)
            .height(250)
            .margins({top: 10, right: 50, bottom: 30, left: 50})
            .dimension(accCredLimDim)
            .group(accCredLimGrp)
            .transitionDuration(500)
            .x(d3.scaleLinear().domain([minCredLim, maxCredLim]))
            .xUnits(function(){return nb_of_bins_credlim;})
            .elasticY(true)
            .brushOn(true)
            .xAxisLabel("Credit Limit")

I succeeded to do what I want initially just by customizing the yAxis().tickFormat() attribute of the bar chart, by dividing the tick value by the total number of rows being filtered at the moment:

    creditBarChart.yAxis().tickFormat(function (d) {
            return 100*d/all.value() + '%';
        });

And I recompute these ticks every time a transition is being made, because my y-axis is elastic:

        creditBar
            .on("pretransition", function(){

            creditBar.yAxis().tickFormat(function (d) {
                if (!creditBar.hasFilter()){
                    return Math.trunc(100*d/all.value()) + '%';
                }
            });
        });

As you can see, I don't update the ticks when the bar chart is being filtered. Indeed, when it is filtered I want the ticks to remain unchanged, as the y-axis should not change. However, because I am dividing the tick value by all.value() this rule cannot work when filtering the bar chart itself. The displayed percentages are obviously wrong.

This question is quite close to solving my problem: link but it is applicable only for categorical bar chart...

How can I display percentages on the y-axis ticks, that can change of values when filtering other charts and also when filtering the chart itself? Is there a sort of all.value() that would be computed excluding the effect of filtering a specified chart?

Thanks!

Upvotes: 1

Views: 138

Answers (1)

Gordon
Gordon

Reputation: 20120

Since you want the groupAll not to observe the filter on this chart, you should use the chart dimension's groupAll not the one on the crossfilter object. From the docs:

Note: a grouping intersects the crossfilter's current filters, except for the associated dimension's filter. Thus, group methods consider only records that satisfy every filter except this dimension's filter. So, if the crossfilter of payments is filtered by type and total, then groupAll by total only observes the filter by type.

That's kind of a mouthful, but I hope the intention is clear.

var accCredLimDim = ndx.dimension(function(d) { return d.acct_curr_crlimit;});
var all = accCredLimDim.groupAll();

Once you do that, you don't have to put an if statement in your tickFormat definition:

creditBar
    .on("pretransition", function(){
        creditBar.yAxis().tickFormat(function (d) {
            return Math.trunc(100*d/all.value()) + '%';
        });
    });

The if statement was incorrect for a couple of reasons. First, there could be a filter on this chart and also filters on the other charts. Second, any accessor you call, like tickFormat, needs to return a value every time it is called. But this would return undefined if there was any filter on this chart, because that is the default return value in JS.

Upvotes: 1

Related Questions