Florian
Florian

Reputation: 311

Crossfilter and D3: Filter by group AND dimension

I try to use crossfilter to filter my data at the same time on both a dimension and a group. Say, I want to be able to filterExact on my "byCylinders" dimension, and at the same time filter on the value of my groupByBrand group (which reduce-counts cars by brand name). (both checkboxes checked).

See code: http://jsbin.com/xajuc/2/watch?js,output

The problem I see is that I don't get both filters recognized at once, or I don't understand how to bind d3.data() correctly.

I understand that I could create a new "ad-hoc" dimension, but as dimensions are expensive, this might not be the best way to do it..

Any ideas?

Upvotes: 1

Views: 2107

Answers (2)

Gordon
Gordon

Reputation: 20120

The problem isn't with your use of crossfilter, but your d3 display. Since you aren't using crossfilter for your brand filtering, it should be okay to use that dimension for fetching results (it wouldn't observe any dimension.filter on that same dimension, however).

The problem is that you don't have an update step for the bins that changed but were not removed. Crossfilter does not automatically remove bins with 0 items, so the actual number of bins won't change in response to your byCylinders.filter, only the size. Thus there are no enters or exits when just clicking the cylinders checkbox - only the other filter actually removes bins.

So by adding an update step after the insert, you can see the numbers change:

 var result = d3.select("body")
      .select("div#result")
      .selectAll("div")
      .data(resultData);
  result.enter()
      .append("div");
  result
      .text(function(d){
          return d.key + " : " + d.value + " cars found";});

This takes advantage of the fact that the items in .enter() become available for updates immediately after they are processed.

http://jsbin.com/qesafu/2/edit

Upvotes: 1

squishy
squishy

Reputation: 374

You can bring in your data as .json, zip the various data elements, and pass .data() the entire data set. I think the following could apply to your filters as well. I will explain this like you are bringing in your data (not necessarily filtered) as a whole. Hopefully this will shine light on how .data() can be utilized with associated data in d3.

data.json example:

{
    "property1":[0, 0, 0, 0],
    "property2":['name1', 'name2', 'name3', 'name4']
}

Bring in the data as .json:

d3.json("data.json", function(data) { 

    // zip the two (or more) attributes of your data 
    data = d3.zip(data.property1, data.property2).map(function(d) { 
        property1 = +d[0];
        property2 = +d[1];

        // return object for each property
        return {prop1: property1, prop2: property2};
    });

}

And then .data() can get that zip:

.data(data)

You can call just one of the data properties at a time:

// histogram example
d3.layout.histogram()
    .bins()
    .value( function(d) { return d.attr1; })
    (data)

Do you see how .value returns just one the properties of the zip? But the other property is still associated. You could have multiple properties, use a few for whatever computations you may be doing, and then use the others as metadata FOR those data properties because they are all zipped together in a nice little bundle for you.

Another option is passing in one array / data to .data() and using the index for the other.

Both options outlined here:

d3 array input line graph example

With a detailed example of the former here:

http://bl.ocks.org/patrickberkeley/9162034

I think these concepts are what you are after. Let me know if I am wrong.

Upvotes: 0

Related Questions