Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Crossfilter query

Is it possible to filter a crossfilter dataset which has an array as the value?

For example, say I have the following dataset:

var data = [
  {
    bookname: "the joy of clojure",
    authors: ["Michael Fogus", "Chris Houser"],
    tags: ["clojure", "lisp"]
  },
  {
    bookname: "Eloquent Ruby",
    authors: ["Russ Olsen"],
    tags: ["ruby"]
  },
  {
    bookname: "Design Patterns in Ruby",
    authors: ["Russ Olsen"],
    tags: ["design patterns", "ruby"]
  }
];

Is there an easy way to access the books which are tagged by an particular tag? And also the books which have a particular author? The way I understand how to use crossfilter so far has me doing something like this:

var filtered_data = crossfilter(data);
var tags = filtered_data.dimension(function(d) {return d.tags});
var tag = tags.group();

And then when I access the grouping (like so):

tag.all()

I get this:

[{key: ["clojure", "lisp"], value: 1}, 
 {key: ["design patterns", "ruby"], value: 1}, 
 {key: ["ruby"], value: 1}]

When I would rather have this:

[{key: "ruby", value: 2}, 
 {key: "clojure", value: 1}, 
 {key: "lisp", value: 1},
 {key: "design patterns", value: 1}]
like image 625
Han Avatar asked Aug 20 '12 20:08

Han


People also ask

What is Crossfilter in DAX?

CROSSFILTER DAX Function (Relationships management)Specifies cross filtering direction to be used in the evaluation of a DAX expression. The relationship is defined by naming, as arguments, the two columns that serve as endpoints.

What is a Crossfilter?

Use a cross filter to fine-tune your results by including or excluding records from related objects and their fields, without having to write formulas or code. You can apply cross filters by themselves, or in combination with field filters.

What is Crossfilter in JavaScript?

- [Instructor] Crossfilter is a JavaScript library that allows you to filter and group data on the fly. It's particularly useful with web-based dashboards when you want interaction with one chart to update what's shown on all the other charts. In fact, Crossfilter powers another JavaScript library called dc.


2 Answers

I've added comments to the code below. Big picture: use reduce function.

var data = ...
var filtered_data = crossfilter(data);
var tags = filtered_data.dimension(function(d) {return d.tags});

tags.groupAll().reduce(reduceAdd, reduceRemove, reduceInitial).value()

Notice how I've used groupAll() instead of group() b/c we want our reduce functions (defined below) to operate on one group rather than 3 groups.

Now the reduce functions should look like this:

/*
 v is the row in the dataset

 p is {} for the first execution (passed from reduceInitial). 
 For every subsequent execution it is the value returned from reduceAdd of the prev row
*/
function reduceAdd(p, v) {
  v.tags.forEach (function(val, idx) {
     p[val] = (p[val] || 0) + 1; //increment counts
  });
  return p;
}

function reduceRemove(p, v) {
   //omitted. not useful for demonstration
}

function reduceInitial() {
  /* this is how our reduce function is seeded. similar to how inject or fold 
   works in functional languages. this map will contain the final counts 
   by the time we are done reducing our entire data set.*/
  return {};  
}
like image 123
numan salati Avatar answered Sep 21 '22 10:09

numan salati


I've never used "crossfilter" (I'm assuming this is a JS library). Here are some pure JS methods though.

This...

data.filter(function(d) {
  return d.authors.indexOf("Michael Fogus") !== -1;
})

returns this:

[{bookname:"the joy of clojure", authors:["Michael Fogus", "Chris Houser"], tags:["clojure", "lisp"]}]

This...

var res = {};
data.forEach(function(d) {
  d.tags.forEach(function(tag) {
    res.hasOwnProperty(tag) ? res[tag]++ : res[tag] = 1
  });
})

returns this:

({clojure:1, lisp:1, ruby:2, 'design patterns':1})

To either of these, you can apply d3.entries to get your {key:"ruby", value: 2} format.

like image 42
ZachB Avatar answered Sep 20 '22 10:09

ZachB