Adding a filter in dc.js / Crossfilter not updating the chart

DannyLane picture DannyLane · Jul 16, 2013 · Viewed 12.9k times · Source

jsFiddle: http://jsfiddle.net/PYeFP/

I have a bar chart set up that graphs a users number of trips by day

        tripVolume = dc.barChart("#trip-volume")
               .width(980) // (optional) define chart width, :default = 200
               .height(75) // (optional) define chart height, :default = 200
               .transitionDuration(0) // (optional) define chart transition duration, :default = 500
               .margins({ top: 10, right: 50, bottom: 30, left: 40 })
               .dimension(tripsByDateDimension) // set dimension
               .group(tripsByDateGroup) // set group
               // (optional) whether chart should rescale y axis to fit data, :default = false
               .elasticY(false)
               // (optional) whether chart should rescale x axis to fit data, :default = false
               .elasticX(false)
               // define x scale
               .x(d3.time.scale().domain([tripsByDateDimension.bottom(1)[0].startDate, tripsByDateDimension.top(1)[0].startDate ]))
               // (optional) set filter brush rounding
               .round(d3.time.day.round)
               // define x axis units
               .xUnits(d3.time.days)
               // (optional) whether bar should be center to its x value, :default=false
               .centerBar(true)
               // (optional) render horizontal grid lines, :default=false
               .renderHorizontalGridLines(true)
               // (optional) render vertical grid lines, :default=false
               .renderVerticalGridLines(true)
               .brushOn(false);

The graph displays fine but I would like to filter it using some jQuery controls. When the user selects the date I am trying to add a filter to the chart, the filter gets added but the chart does not change, even if I redraw() or render().

This is how the crossfilter is setup:

tripsCx = crossfilter(data.rows);
var allTripsGroup = tripsCx.groupAll();

var tripsByDateDimension = tripsCx.dimension(function (d) { return d.startDate; });
var tripsByDateGroup = tripsByDateDimension.group(d3.time.day);

The following are some of the methods I have used to try to apply a filter:

This should use the filterRange:

d.filter(d.dimension().top(20)[19], d.dimension().top(20)[0]);

FilterFunction:

d.filter(function (d) {
    return d.getTime() > start.valueOf() && d.getTime() < end.valueOf();
});

FilterExact:

d.filter(d.dimension().top(20)[0]);

I also tried bypassing the chart and applying the filter directly on the dimension:

d.dimension().filterFunction(function (d) {
  return d.getTime() > start.valueOf() && d.getTime() < end.valueOf()
});

Nothing I have done causes the chart to change.

I am beginning to think that I have the wrong expectation of what the filter function should do?

How can I manually filter the data in the dimension to have the chart updated? I don't want to use a brush. I will be filtering the data based on different criteria, I'm just trying to get the simple case working first.

I've spent a couple of days on this now and I'm at a loss as to what to try next.

Any help would be greatly appreciated.

Answer

Peter picture Peter · Jul 16, 2013

Have you tried to reset your x property of the graph after setting the crossfilter filter

I have a somewhat similar case and what I do after each action that changes the filtered values is something along the lines of

.x(..).dimension(...).group(...)

after creating/setting the filters

Tried to do something like that

$('#filter').on('click', function(){
    var minDate = tripsByDateDimension.top(5)[4].startDate;
    var maxDate = tripsByDateDimension.top(5)[0].startDate;
    console.log(tripVolume.filters());


    tripVolume.filter([minDate, maxDate]);
    tripVolume.x(d3.time.scale().domain([minDate,maxDate]));

    console.log(tripVolume.filters());

    dc.redrawAll()
});

http://jsfiddle.net/PYeFP/5/

Better answer per the discussion in the comment is to add the filter to the dimension, not the chart

Finally, one needs to realize what is mentioned in https://github.com/square/crossfilter/wiki/API-Reference#group-map-reduce

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 group by total only observes the filter by type.

(also see https://groups.google.com/d/msg/dc-js-user-group/UFxvUND7hmY/btbAjqIIzl8J)