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

1

6

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.

Golgotha answered 16/7, 2013 at 10:47 Comment(0)
O
9

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)

Outpost answered 16/7, 2013 at 11:10 Comment(5)
Thanks, I commented out the line where you apply the filter in the updated jsfiddle and the graph still changed. Changing the X axis scale seems to work on the bar chart but I don't think it filters the underlying data. I'm specifically asking about filters as I want it to work with all the dc js charts. Another problem with the x axis is that I can't do more complicated filters like the filterFunction would provide. Thanks for the answer though.Golgotha
I see what you mean. Let me try again :). Adding the filter to the dimension, not to the chart does seem to make a difference. Does jsfiddle.net/PYeFP/8 work for you?Outpost
That is a bit helpful in that I can see that a filter is possible of updating a chart. The problem is that there is an extra dimension created, it doesn't answer why I can't filter on my startDate object. I have updated the fiddle with a filter function, in the logs you can see that the number of elements goes from 13 to 9, but the graph doesnt update. jsfiddle.net/PYeFP/9Golgotha
OK, I'm really lost now. Updating the filter on a different dimension will update the graph, but not if you update the dimension that the graph was setup with? jsfiddle.net/PYeFP/10Golgotha
The answer came from the dc js usergroup: groups.google.com/d/msg/dc-js-user-group/UFxvUND7hmY/… Thanks for the help, upi gave me some valuable pointers. If you update your answer with the attached info, I'll accept.Golgotha

© 2022 - 2024 — McMap. All rights reserved.