2013-07-08 25 views
35

我有一些數據集,其中一些字段值是數組,我希望使用crossfilter和d3.js或dc.js來顯示每個數據集中存在多少次這些值的直方圖。有沒有辦法告訴crossfilter將數組的元素視爲單獨的記錄,而不是將整個數組視爲單個鍵?

下面是一個例子:

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/

當我運行的代碼,它產生的圖形是這樣的:

graph1

但我想是這樣的:

enter image description here

爲了使事情變得更加複雜,能夠點擊任何行並通過點擊標記過濾數據集將會非常棒。

任何人有任何想法如何實現這一目標?

感謝, 克斯特亞

回答

32

解決它自己,這裏的撥弄工作代碼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(); 
+0

jsfiddle你提供的是相當混亂,並與大量minifyied JavaScript。但是,謝謝,這當然是需要的。 – skmasq

+0

我不得不將最新版本的crossfiler和dc.js加入小提琴中,以使其發揮作用。也許有更好的方法來添加這些外部資源。這是我第一次使用JS小提琴 –

+0

真棒回答!你救了我! – dvreed77

20

上面的例子是一個偉大的做法。儘管如此,你可以採取一步。 在上面的解決方案中,它只會根據您所做的第一個選擇進行過濾。任何後續選擇都將被忽略。

如果你想讓它選擇的所有內容作出迴應,您可以按如下創建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/

+0

根據馬特的建議進行了更新。接得好。 –

+3

交叉過濾器的鏈接打破了你的小提琴。如果將其更新爲cdn,則可以運行:http://cdnjs.cloudflare.com/ajax/libs/crossfilter/1.3.7/crossfilter.js –

+0

傑夫上的斑點。這是[我的這個實現](https://jsfiddle.net/geotheory/ku9qd1Lx/)。 – geotheory

7

傑夫的答案的工作,但也沒有必要跟蹤「發現」變量或在找到某個項目時繼續循環。如果X在[X,Y,Z]中,這已經減少了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,並且將處理所有案件。

+2

也許現在刪除這個答案,上面的答案已經集成了你建議的改變?你會(當之無愧)保留你的代表。 –

15

我想嘗試爲Jeff和Kostya列出的方法提供一些背景。

您會注意到tagsGroup使用groupAll而不像典型的組方法。 Crossfilter告訴我們「返回的對象與標準分組類似,只是它沒有頂層或排序方法,而是使用值來檢索所有匹配記錄的排序值。」 Kostya調用「.value()」方法來檢索代表整個組的單個對象。

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

該對象不適用於dc.js,因爲dc。js期望組對象具有all方法。克斯特亞修補的對象有像這樣一個「全」的方法:

// 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.js,因爲不是所有的團隊職能存在。例如,您將無法在圖表上使用「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

相關問題