-->

Apply Filter from one Crossfilter dataset to anoth

2019-05-18 05:43发布

问题:

I have two datasets that have similar columns/dimensions but are grouped differently by row and contain different measures.

Ex:

Dataset 1

Year   Category   SubCategory    Value01    Value02
2000   Cars       Sport          10         11
2000   Cars       Family         15         16
2000   Boats      Sport          20         21
2000   Boats      Family         25         26
...

Dataset 2

Year   Category    ValueA     ValueB
2000   Cars        100        101
2000   Boats       200        201
...

Dataset 1 has its own crossfilter object, Dataset 2 has a separate crossfilter object. I have multiple dc.js charts, some tied to the dataset 1, some to dataset 2.

When a dc.js chart filters dataset 1 on a column/dimension that also exists in dataset 2, I want to apply that same filter to dataset 2. How can this be achieved?

回答1:

I don't think there is any automatic way to do this in crossfilter or dc.js. But if you're willing to roll your own dimension wrapper, you could supply that instead of the original dimension objects and have that forward to all the underlying dimensions.

EDIT: based on @Aravind's fiddle below, here is a "dimension mirror" that works, at least for this simple example:

function mirror_dimension() {
    var dims = Array.prototype.slice.call(arguments, 0);
    function mirror(fname) {
        return function(v) {
            dims.forEach(function(dim) {
                dim[fname](v);
            });
        };
    }
    return {
        filter: mirror('filter'),
        filterExact: mirror('filterExact'),
        filterRange: mirror('filterRange'),
        filterFunction: mirror('filterFunction')
    };
}

It's a bit messy using this. For each dimension you want to mirror from crossfilter A to crossfilter B, you'll need to create a mirror dimension on crossfilter B, and vice versa:

// Creating the dimensions
subject_DA = CFA.dimension(function(d){ return d.Subject; });
name_DA = CFA.dimension(function(d){ return d.Name; });
// mirror dimensions to receive events from crossfilter B
mirror_subject_DA = CFA.dimension(function(d){ return d.Subject; });
mirror_name_DA = CFA.dimension(function(d){ return d.Name; });

subject_DB = CFB.dimension(function(d){ return d.Subject; });
name_DB = CFB.dimension(function(d){ return d.Name; });
// mirror dimensions to receive events from crossfilter A
mirror_subject_DB = CFB.dimension(function(d){ return d.Subject; });
mirror_name_DB = CFB.dimension(function(d){ return d.Name; });

Now you tie them together when passing them off to the charts:

// subject Chart
subjectAChart
    .dimension(mirror_dimension(subject_DA, mirror_subject_DB))
    // ...

// subject Chart
subjectBChart
    .dimension(mirror_dimension(subject_DB, mirror_subject_DA))
    // ...

nameAChart
    .dimension(mirror_dimension(name_DA, mirror_name_DB))
    // ...

nameBChart
    .dimension(mirror_dimension(name_DB, mirror_name_DA))
    // ...

Since all the charts are implicitly on the same chart group, the redraw events will automatically get propagated between them when they are filtered. And each filter action on one crossfilter will get applied to the mirror dimension on the other crossfilter.

Maybe not something I'd recommend doing, but as usual, it can be made to work.

Here's the fiddle: https://jsfiddle.net/gordonwoodhull/7dwn4y87/8/



回答2:

@Gordon's suggestion is a good one.

I usually approach this differently, by combining the 2 tables into a single table (add ValueA and ValueB to each row of Data Set 1) and then using custom groupings to only aggregate ValueA and Value B once for each unique Year/Category combination. Each group would need to keep a map of keys it has seen before and the count for each of those keys, only aggregating the value of ValueA or ValueB if it is a new combination of keys. This does result in complicated grouping logic, but allows you to avoid needing to coordinate between 2 Crossfilter objects.

Personally, I just find complex custom groupings easier to test and maintian than coordination logic, but that's not the case for everyone.