有没有办法告诉crossfilter将数组的元素视为单独的logging,而不是将整个数组视为单个键?

我有数据集,其中一些字段值是数组,我想使用crossfilter和d3.js或dc.js来显示数据集中每个值的数量的直方图。

这是一个例子:

var data = [ {"key":"KEY-1","tags":["tag1", "tag2"]}, {"key":"KEY-2","tags":["tag2"]}, {"key":"KEY-3","tags":["tag3", "tag1"]}]; var cf = crossfilter(data); var tags = cf.dimension(function(d){ return d.tags;}); var tagsGroup = tags.group(); dc.rowChart("#chart") .renderLabel(true) .dimension(tags) .group(tagsGroup) .xAxis().ticks(3); dc.renderAll(); 

和JSFiddle http://jsfiddle.net/uhXf5/2/

当我运行这个代码时,它产生如下的graphics:

graph1

但是我想要的是这样的:

在这里输入图像描述

为了使事情变得更复杂,能够点击任何行并通过被点击的标签来过滤数据集将是非常棒的。

任何人有任何想法如何实现?

谢谢,Kostya

解决它自己,这里的工作代码小提琴http://jsfiddle.net/uhXf5/6/

这里是代码,以防有人遇到类似的问题:

 function reduceAdd(p, v) { v.tags.forEach (function(val, idx) { p[val] = (p[val] || 0) + 1; //increment counts }); return p; } function reduceRemove(p, v) { v.tags.forEach (function(val, idx) { p[val] = (p[val] || 0) - 1; //decrement counts }); return p; } function reduceInitial() { return {}; } var data = [ {"key":"KEY-1","tags":["tag1", "tag2"], "date":new Date("10/02/2012")}, {"key":"KEY-2","tags":["tag2"], "date": new Date("10/05/2012")}, {"key":"KEY-3","tags":["tag3", "tag1"], "date":new Date("10/08/2012")}]; var cf = crossfilter(data); var tags = cf.dimension(function(d){ return d.tags;}); var tagsGroup = tags.groupAll().reduce(reduceAdd, reduceRemove, reduceInitial).value(); // hack to make dc.js charts work tagsGroup.all = function() { var newObject = []; for (var key in this) { if (this.hasOwnProperty(key) && key != "all") { newObject.push({ key: key, value: this[key] }); } } return newObject; } var dates = cf.dimension(function(d){ return d.date;}); var datesGroup = dates.group(); var chart = dc.rowChart("#chart"); chart .renderLabel(true) .dimension(tags) .group(tagsGroup) .filterHandler(function(dimension, filter){ dimension.filter(function(d) {return chart.filter() != null ? d.indexOf(chart.filter()) >= 0 : true;}); // perform filtering return filter; // return the actual filter value }) .xAxis().ticks(3); var chart2 = dc.barChart("#chart2"); chart2 .width(500) .transitionDuration(800) .margins({top: 10, right: 50, bottom: 30, left: 40}) .dimension(dates) .group(datesGroup) .elasticY(true) .elasticX(true) .round(d3.time.day.round) .x(d3.time.scale()) .xUnits(d3.time.days) .centerBar(true) .renderHorizontalGridLines(true) .brushOn(true); dc.renderAll(); 

上面的例子是一个很好的方法。 尽pipe如此,你可以更进一步。 在上面的解决scheme中,它只会根据您所做的第一个select进行过滤。 任何后续的select都将被忽略。

如果你想让它响应所有的select,你可以创build一个filterHandler,如下所示:

  barChart.filterHandler (function (dimension, filters) { dimension.filter(null); if (filters.length === 0) dimension.filter(null); else dimension.filterFunction(function (d) { for (var i=0; i < d.length; i++) { if (filters.indexOf(d[i]) >= 0) return true; } return false; }); return filters; } ); 

在这里工作示例: http : //jsfiddle.net/jeffsteinmetz/cwShL/

我想尝试为Jeff和Kostya列出的方法提供一些背景。

您会注意到tagsGroup使用groupAll,而不像典型的组方法。 Crossfilter告诉我们“返回的对象类似于标准的分组,除了它没有top或order方法,而是使用value来检索所有匹配logging的reduce值。 Kostya调用“.value()”方法来检索代表整个组的单个对象。

 var tagsGroup = tags.groupAll().reduce(reduceAdd, reduceRemove, reduceInitial).value(); 

这个对象不适合dc.js,因为dc.js期望组对象具有all方法。 Kostya修补这个对象,使其具有如下所示的“全部”方法:

 // hack to make dc.js charts work tagsGroup.all = function() { var newObject = []; for (var key in this) { if (this.hasOwnProperty(key) && key != "all") { newObject.push({ key: key, value: this[key] }); } } return newObject; } 

这将使用一个简单的dc.js图表​​,但不能使用所有的dc.jsfunction,因为不是所有的组function都存在。 例如,您将无法在图表上使用“cap”方法,因为cap方法期望组对象具有“top”方法。 你也可以修补顶部的方法,如下所示:

 topicsGroup.top = function(count) { var newObject = this.all(); newObject.sort(function(a, b){return b.value - a.value}); return newObject.slice(0, count); }; 

这将使您的图表使用上限方法:

 barChart .renderLabel(true) .height(200) .dimension(topicsDim) .group(topicsGroup) .cap(2) .ordering(function(d){return -d.value;}) .xAxis().ticks(3); 

更新的示例可在http://jsfiddle.net/djmartin_umich/m7V89/#base中find

杰夫的答案确实有效,但是没有必要跟踪“发现”variables,或者如果find某个项目,就继续循环。 如果X在[X,Y,Z]中,则已经将迭代次数减less了1/3。

 else dimension.filterFunction(function (d) { for (var i=0; i < d.length; i++) { if (filters.indexOf(d[i]) >= 0) return true; } return false; }); 

或者,您可以修补dc.js filterFunction方法,并处理所有情况。

现在这更容易,因为crossfilterdc支持数组的尺寸。 请参阅此问题的上下文和示例: 在dc.js / crossfilter中使用数组