d3.js - framework - Consulta de filtro cruzado
jquery d3 (2)
¿Es posible filtrar un dataset de filtros cruzados que tiene una matriz como valor?
Por ejemplo, supongamos que tengo el siguiente conjunto de datos:
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"]
}
];
¿Hay alguna manera fácil de acceder a los libros etiquetados por una etiqueta en particular? ¿Y también los libros que tienen un autor en particular? La forma en que entiendo cómo usar filtro cruzado hasta ahora me hace hacer algo como esto:
var filtered_data = crossfilter(data);
var tags = filtered_data.dimension(function(d) {return d.tags});
var tag = tags.group();
Y luego cuando accedo a la agrupación (como así):
tag.all()
Entiendo esto:
[{key: ["clojure", "lisp"], value: 1},
{key: ["design patterns", "ruby"], value: 1},
{key: ["ruby"], value: 1}]
Cuando prefiero tener esto:
[{key: "ruby", value: 2},
{key: "clojure", value: 1},
{key: "lisp", value: 1},
{key: "design patterns", value: 1}]
He agregado comentarios al código a continuación. Imagen grande: use la función de reducir.
var data = ...
var filtered_data = crossfilter(data);
var tags = filtered_data.dimension(function(d) {return d.tags});
tags.groupAll().reduce(reduceAdd, reduceRemove, reduceInitial).value()
Observe cómo he usado groupAll () en lugar de group () b / c queremos que nuestras funciones de reducción (definidas a continuación) operen en un grupo en lugar de en 3 grupos.
Ahora las funciones de reducción deberían verse así:
/*
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 {};
}
Nunca he usado "filtro cruzado" (supongo que es una biblioteca JS). Aquí hay algunos métodos JS puros.
Esta...
data.filter(function(d) {
return d.authors.indexOf("Michael Fogus") !== -1;
})
devuelve esto:
[{bookname:"the joy of clojure", authors:["Michael Fogus", "Chris Houser"], tags:["clojure", "lisp"]}]
Esta...
var res = {};
data.forEach(function(d) {
d.tags.forEach(function(tag) {
res.hasOwnProperty(tag) ? res[tag]++ : res[tag] = 1
});
})
devuelve esto:
({clojure:1, lisp:1, ruby:2, ''design patterns'':1})
Para cualquiera de estos, puede aplicar d3.entries
para obtener su d3.entries
{key:"ruby", value: 2}
.