NEW:我在解决方案工作中发布的小提琴(https://jsfiddle.net/jnf84n7c/)。然而,当我试图在我的项目中实施策略时,我遇到了一些问题。当我点击一个不是第一张图的图表时,我会收到一条错误消息。
Uncaught : a.group.all不是函数(错误位于dc.min.js中)
你知道为什么它在小提琴中工作,但在我的红宝石路轨应用程序中却不起作用吗?
新代码
var data = [
{"key":"KEY-1","state":"MA","status":["A","R","C"],"items":["orange","meat","bread"],"date":"Y16"},
{"key":"KEY-2","state":"MA","status":["A","O"],"items":["apple","bread"],"date":"Y15"},
{"key":"KEY-3","state":"TX","status":["O"],"items":["bread"],"date":"Y16"},
{"key":"KEY-4","state":"TN","status":["A","R"],"items":["apple","bread"],"date":"Y16"},
{"key":"KEY-5","state":"TN","status":["A","O"],"items":["apple","orange"],"date":"Y15"},
{"key":"KEY-6","state":"TN","status":[],"items":[],"date":"Y14"}
];
var cf = crossfilter(data);
var dates = cf.dimension(function(d){ return d.date; });
var datesGroup = dates.group();
var states = cf.dimension(function(d){ return d.state; });
var statesGroup = states.group();
var itemsDim = cf.dimension(function(d){ return d.items; });
var itemsGroup = itemsDim.groupAll().reduce(reduceAdd, reduceRemove, reduceInitial).value();
itemsGroup.all = myAllFunction;
var states_items_group_apple = states.group().reduce(reduceAdd_apple, reduceRemove_apple, reduceInitial_items);
var states_items_group_bread = states.group().reduce(reduceAdd_bread, reduceRemove_bread, reduceInitial_items);
var states_items_group_orange = states.group().reduce(reduceAdd_orange, reduceRemove_orange, reduceInitial_items);
var states_items_group_meat = states.group().reduce(reduceAdd_meat, reduceRemove_meat, reduceInitial_items);
var itemsGroup1 = itemsDim.groupAll().reduce(reduceAdd1, reduceRemove1, reduceInitial).value();
var itemsGroup2 = itemsDim.groupAll().reduce(reduceAdd2, reduceRemove2, reduceInitial).value();
var itemsGroup3 = itemsDim.groupAll().reduce(reduceAdd3, reduceRemove3, reduceInitial).value();
itemsGroup1.all = myAllFunction;
itemsGroup2.all = myAllFunction;
itemsGroup3.all = myAllFunction;
var status = cf.dimension(function(d){ return d.status; });
var statusGroup1 = status.groupAll().reduce(reduceAdd_group1, reduceRemove_group1, reduceInitial_group).value();
var statusGroup2 = status.groupAll().reduce(reduceAdd_group2, reduceRemove_group2, reduceInitial_group).value();
var statusGroup3 = status.groupAll().reduce(reduceAdd_group3, reduceRemove_group3, reduceInitial_group).value();
var statusGroup4 = status.groupAll().reduce(reduceAdd_group4, reduceRemove_group4, reduceInitial_group).value();
statusGroup1.all = myAllFunction;
statusGroup2.all = myAllFunction;
statusGroup3.all = myAllFunction;
statusGroup4.all = myAllFunction;
var statusGroup = status.groupAll().reduce(reduceAdd_group, reduceRemove_group, reduceInitial_group).value();
statusGroup.all = myAllFunction;
var row = dc.rowChart("#rowchart");
row.height(170)
.dimension(itemsDim)
.group(itemsGroup)
.ordering(function(d){return -d.value;})
.renderLabel(true)
.ordinalColors(["#008600","#80FF80","#FF80FF","#860086"])
.xAxis().ticks(3);
row.filterHandler(myFilterFunction);
var pie1 = dc.pieChart("#piechart1");
pie1.height(75).width(75)
.dimension(dates)
.group(datesGroup);
var pie2 = dc.pieChart("#piechart2");
pie2.height(75).width(75)
.dimension(states)
.group(statesGroup);
var pie3 = dc.pieChart("#piechart3");
pie3.height(75).width(75)
.dimension(status)
.group(statusGroup);
pie3.filterHandler(myFilterFunction);
var bar = dc.barChart("#barchart");
bar.width(500).height(200)
.dimension(states)
.group(states_items_group_bread, 'bread')
.stack(states_items_group_orange, 'orange')
.stack(states_items_group_apple, 'apple')
.stack(states_items_group_meat, 'meat')
.valueAccessor(function(p){ return p.value.count; })
.renderHorizontalGridLines(true)
.renderLabel(true)
.legend(dc.legend().x(100).y(0).horizontal(1).itemHeight(13).gap(6).legendWidth(400).itemWidth(100))
.gap(10)
.elasticX(true).elasticY(true)
.yAxisLabel("count")
.x(d3.scale.ordinal())
.xUnits(dc.units.ordinal)
.margins({top:30,left:50,right:10,bottom:50});
var bar2 = dc.barChart("#barchart2");
bar2.width(500).height(200)
.dimension(itemsDim)
.group(itemsGroup1,'MA')
.stack(itemsGroup2,'TN')
.stack(itemsGroup3,'TX')
.renderHorizontalGridLines(true)
.renderLabel(true)
.legend(dc.legend().x(60).y(0).horizontal(1).itemHeight(13).gap(6).legendWidth(400).itemWidth(60))
.gap(10)
.yAxisLabel("count")
.x(d3.scale.ordinal())
.xUnits(dc.units.ordinal)
.ordinalColors(["#008600","#80FF80","#FF80FF","#860086"])
.margins({top:30,left:50,right:10,bottom:50});
bar2.filterHandler(myFilterFunction);
var bar3 = dc.barChart("#barchart3");
bar3.width(500).height(200)
.dimension(status)
.group(statusGroup1,"bread")
.stack(statusGroup2,"apple")
.stack(statusGroup3,"orange")
.stack(statusGroup4,"meat")
.renderHorizontalGridLines(true)
.renderLabel(true)
.legend(dc.legend().x(60).y(0).horizontal(1).itemHeight(13).gap(6).legendWidth(400).itemWidth(60))
.gap(10)
.yAxisLabel("count")
.x(d3.scale.ordinal())
.xUnits(dc.units.ordinal)
.margins({top:30,left:50,right:10,bottom:50});
bar3.filterHandler(myFilterFunction);
dc.renderAll();
function reduceAdd(p,v){
if (v.items[0] === "") return p;
v.items.forEach(function(val,idx){
p[val] = (p[val] || 0) + 1;
});
return p;
}
function reduceRemove(p,v){
if (v.items[0] === "") return p;
v.items.forEach(function(val,idx){
p[val] = (p[val] || 0) - 1;
});
return p;
}
function reduceInitial(){
return {
bread: 0,
apple: 0,
orange: 0,
meat: 0
};
}
function reduceAdd1(p,v){
if (v.items[0] === "") return p;
if (v.state === "MA"){
v.items.forEach(function(val,idx){
p.bread += (val === 'bread' ? 1 : 0);
p.apple += (val === 'apple' ? 1 : 0);
p.orange += (val === 'orange' ? 1 : 0);
p.meat += (val === 'meat' ? 1 : 0);
});
}
return p;
}
function reduceRemove1(p,v){
if (v.items[0] === "") return p;
if (v.state === "MA"){
v.items.forEach(function(val,idx){
p.bread -= (val === 'bread' ? 1 : 0);
p.apple -= (val === 'apple' ? 1 : 0);
p.orange -= (val === 'orange' ? 1 : 0);
p.meat -= (val === 'meat' ? 1 : 0);
});
}
return p;
}
function reduceAdd2(p,v){
if (v.items[0] === "") return p;
if (v.state === "TN"){
v.items.forEach(function(val,idx){
p.bread += (val === 'bread' ? 1 : 0);
p.apple += (val === 'apple' ? 1 : 0);
p.orange += (val === 'orange' ? 1 : 0);
p.meat += (val === 'meat' ? 1 : 0);
});
}
return p;
}
function reduceRemove2(p,v){
if (v.items[0] === "") return p;
if (v.state === "TN"){
v.items.forEach(function(val,idx){
p.bread -= (val === 'bread' ? 1 : 0);
p.apple -= (val === 'apple' ? 1 : 0);
p.orange -= (val === 'orange' ? 1 : 0);
p.meat -= (val === 'meat' ? 1 : 0);
});
}
return p;
}
function reduceAdd3(p,v){
if (v.items[0] === "") return p;
if (v.state === "TX"){
v.items.forEach(function(val,idx){
p.bread += (val === 'bread' ? 1 : 0);
p.apple += (val === 'apple' ? 1 : 0);
p.orange += (val === 'orange' ? 1 : 0);
p.meat += (val === 'meat' ? 1 : 0);
});
}
return p;
}
function reduceRemove3(p,v){
if (v.items[0] === "") return p;
if (v.state === "TX"){
v.items.forEach(function(val,idx){
p.bread -= (val === 'bread' ? 1 : 0);
p.apple -= (val === 'apple' ? 1 : 0);
p.orange -= (val === 'orange' ? 1 : 0);
p.meat -= (val === 'meat' ? 1 : 0);
});
}
return p;
}
function reduceAdd_apple(p,v){
if (v.items[0] === "") return p;
p.state = v.state;
v.items.forEach(function(val,idx){
p.count += (val === 'apple' ? 1 : 0);
});
return p;
}
function reduceRemove_apple(p,v){
if (v.items[0] === "") return p;
p.state = v.state;
v.items.forEach(function(val,idx){
p.count -= (val === 'apple' ? 1 : 0);
});
return p;
}
function reduceAdd_bread(p,v){
if (v.items[0] === "") return p;
p.state = v.state;
v.items.forEach(function(val,idx){
p.count += (val === 'bread' ? 1 : 0);
});
return p;
}
function reduceRemove_bread(p,v){
if (v.items[0] === "") return p;
p.state = v.state;
v.items.forEach(function(val,idx){
p.count -= (val === 'bread' ? 1 : 0);
});
return p;
}
function reduceAdd_orange(p,v){
if (v.items[0] === "") return p;
p.state = v.state;
v.items.forEach(function(val,idx){
p.count += (val === 'orange' ? 1 : 0);
});
return p;
}
function reduceRemove_orange(p,v){
if (v.items[0] === "") return p;
p.state = v.state;
v.items.forEach(function(val,idx){
p.count -= (val === 'orange' ? 1 : 0);
});
return p;
}
function reduceAdd_meat(p,v){
if (v.items[0] === "") return p;
p.state = v.state;
v.items.forEach(function(val,idx){
p.count += (val === 'meat' ? 1 : 0);
});
return p;
}
function reduceRemove_meat(p,v){
if (v.items[0] === "") return p;
p.state = v.state;
v.items.forEach(function(val,idx){
p.count -= (val === 'meat' ? 1 : 0);
});
return p;
}
function reduceAdd_group1(p,v){
if (v.items[0] === "") return p;
if (v.status[0] === "") return p;
v.items.forEach(function(val1,idx1){
if (val1 === "bread"){
v.status.forEach(function(val2,idx2){
if(idx1 === idx2){
p.A += (val2 === 'A' ? 1 : 0);
p.O += (val2 === 'O' ? 1 : 0);
p.C += (val2 === 'C' ? 1 : 0);
p.R += (val2 === 'R' ? 1 : 0);
}
});
}
});
return p;
}
function reduceRemove_group1(p,v){
if (v.items[0] === "") return p;
if (v.status[0] === "") return p;
v.items.forEach(function(val1,idx1){
if(val1 === "bread"){
v.status.forEach(function(val2,idx2){
if(idx1 === idx2){
p.A -= (val2 === 'A' ? 1 : 0);
p.O -= (val2 === 'O' ? 1 : 0);
p.C -= (val2 === 'C' ? 1 : 0);
p.R -= (val2 === 'R' ? 1 : 0);
}
});
}
});
return p;
}
function reduceAdd_group2(p,v){
if (v.items[0] === "") return p;
if (v.status[0] === "") return p;
v.items.forEach(function(val1,idx1){
if(val1 === "apple"){
v.status.forEach(function(val2,idx2){
if(idx1 === idx2){
p.A += (val2 === 'A' ? 1 : 0);
p.O += (val2 === 'O' ? 1 : 0);
p.C += (val2 === 'C' ? 1 : 0);
p.R += (val2 === 'R' ? 1 : 0);
}
});
}
});
return p;
}
function reduceRemove_group2(p,v){
if (v.items[0] === "") return p;
if (v.status[0] === "") return p;
v.items.forEach(function(val1,idx1){
if(val1 === "apple"){
v.status.forEach(function(val2,idx2){
if(idx1 === idx2){
p.A -= (val2 === 'A' ? 1 : 0);
p.O -= (val2 === 'O' ? 1 : 0);
p.C -= (val2 === 'C' ? 1 : 0);
p.R -= (val2 === 'R' ? 1 : 0);
}
});
}
});
return p;
}
function reduceAdd_group3(p,v){
if (v.items[0] === "") return p;
if (v.status[0] === "") return p;
v.items.forEach(function(val1,idx1){
if(val1 === "orange"){
v.status.forEach(function(val2,idx2){
if(idx1 === idx2){
p.A += (val2 === 'A' ? 1 : 0);
p.O += (val2 === 'O' ? 1 : 0);
p.C += (val2 === 'C' ? 1 : 0);
p.R += (val2 === 'R' ? 1 : 0);
}
});
}
});
return p;
}
function reduceRemove_group3(p,v){
if (v.items[0] === "") return p;
if (v.status[0] === "") return p;
v.items.forEach(function(val1,idx1){
if(val1 === "orange"){
v.status.forEach(function(val2,idx2){
if(idx1 === idx2){
p.A -= (val2 === 'A' ? 1 : 0);
p.O -= (val2 === 'O' ? 1 : 0);
p.C -= (val2 === 'C' ? 1 : 0);
p.R -= (val2 === 'R' ? 1 : 0);
}
});
}
});
return p;
}
function reduceAdd_group4(p,v){
if (v.items[0] === "") return p;
if (v.status[0] === "") return p;
v.items.forEach(function(val1,idx1){
if(val1 === "meat"){
v.status.forEach(function(val2,idx2){
if(idx1 === idx2){
p.A += (val2 === 'A' ? 1 : 0);
p.O += (val2 === 'O' ? 1 : 0);
p.C += (val2 === 'C' ? 1 : 0);
p.R += (val2 === 'R' ? 1 : 0);
}
});
}
});
return p;
}
function reduceRemove_group4(p,v){
if (v.items[0] === "") return p;
if (v.status[0] === "") return p;
v.items.forEach(function(val1,idx1){
if(val1 === "meat"){
v.status.forEach(function(val2,idx2){
if(idx1 === idx2){
p.A -= (val2 === 'A' ? 1 : 0);
p.O -= (val2 === 'O' ? 1 : 0);
p.C -= (val2 === 'C' ? 1 : 0);
p.R -= (val2 === 'R' ? 1 : 0);
}
});
}
});
return p;
}
function reduceAdd_group(p,v){
if (v.status[0] === "") return p;
v.status.forEach(function(val,idx){
p[val] = (p[val] || 0) + 1;
});
return p;
}
function reduceRemove_group(p,v){
if (v.status[0] === "") return p;
v.status.forEach(function(val,idx){
p[val] = (p[val] || 0) - 1;
});
return p;
}
function reduceInitial_group(){
return {
A: 0,
O: 0,
C: 0,
R: 0
};
}
function reduceInitial_items(){
return {
count: 0,
state: ''
};
}
//filter function:
function myFilterFunction(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;
}
function myAllFunction(){
var newObject = [];
for(var key in this){
if(this.hasOwnProperty(key) && key != "all"){
newObject.push({
key: key,
value: this[key]
});
}
}
return newObject;
};老问题:,很抱歉,我又提出了一个问题。不幸的是,我无法评论其他帖子来问我的问题。与我类似的两个问题是:dc.js -如何按唯一id进行分组和是否有一种方法可以告诉交叉过滤器将数组元素作为单独的记录来处理,而不是将整个数组作为单键处理?
我使用的代码,在后面的解释。然而,我想要能够堆叠。正如您可以在jsfiddle中看到的那样,下面的条形图没有列出x轴中的项目,而是堆叠了不同的状态计数。任何帮助都将不胜感激。谢谢!
这是最初的小提琴:https://jsfiddle.net/7qwqcakr/1/
我几乎有这个小提琴:https://jsfiddle.net/wq0ed5hr/,但堆叠的条形图都是一种颜色,即使传说中有不同的颜色。如何解决颜色问题?
修正了颜色问题:https://jsfiddle.net/rmc2zpr4/
现在唯一的问题是“计数问题”,正如我在下面的解决方案和评论中所解释的那样。
下面是更新的代码:
var data = [
{"key":"KEY-1","state":"MA","items":["orange","meat","bread"],"date":"Y16"},
{"key":"KEY-2","state":"MA","items":["apple","bread"],"date":"Y15"},
{"key":"KEY-3","state":"TX","items":["bread"],"date":"Y16"},
{"key":"KEY-4","state":"TN","items":["apple","bread"],"date":"Y16"},
{"key":"KEY-5","state":"TN","items":["apple","orange"],"date":"Y15"},
{"key":"KEY-6","state":"TN","items":[],"date":"Y14"}
];
var cf = crossfilter(data);
var dates = cf.dimension(function(d){ return d.date; });
var datesGroup = dates.group().reduceCount(function(d){ return d.key; });
var states = cf.dimension(function(d){ return d.state; });
var statesGroup = states.group().reduceCount(function(d){ return d.key; });
var itemsDim = cf.dimension(function(d){ return d.items; });
var itemsGroup = itemsDim.groupAll().reduce(reduceAdd, reduceRemove, reduceInitial).value();
itemsGroup.all = myAllFunction;
var statesDim = cf.dimension(function(d){ return d.state; });
var states_items_group_apple = statesDim.group().reduce(reduceAdd_apple, reduceRemove_apple, reduceInitial_items);
var states_items_group_bread = statesDim.group().reduce(reduceAdd_bread, reduceRemove_bread, reduceInitial_items);
var states_items_group_orange = statesDim.group().reduce(reduceAdd_orange, reduceRemove_orange, reduceInitial_items);
var states_items_group_meat = statesDim.group().reduce(reduceAdd_meat, reduceRemove_meat, reduceInitial_items);
var items = cf.dimension(function(d){ return d.items; })
var itemsGroup1 = items.groupAll().reduce(reduceAdd1, reduceRemove1, reduceInitial).value();
var itemsGroup2 = items.groupAll().reduce(reduceAdd2, reduceRemove2, reduceInitial).value();
var itemsGroup3 = items.groupAll().reduce(reduceAdd3, reduceRemove3, reduceInitial).value();
itemsGroup1.all = myAllFunction;
itemsGroup2.all = myAllFunction;
itemsGroup3.all = myAllFunction;
var row = dc.rowChart("#rowchart");
row.height(170)
.dimension(itemsDim)
.group(itemsGroup)
.ordering(function(d){return -d.value;})
.renderLabel(true)
.ordinalColors(["#008600","#80FF80","#FF80FF","#860086"])
.xAxis().ticks(3);
row.filterHandler(myFilterFunction);
var pie1 = dc.pieChart("#piechart1");
pie1.height(75).width(75)
.dimension(dates)
.group(datesGroup);
var pie2 = dc.pieChart("#piechart2");
pie2.height(75).width(75)
.dimension(states)
.group(statesGroup);
var bar = dc.barChart("#barchart");
bar.width(500).height(200)
.dimension(statesDim)
.group(states_items_group_bread, 'bread')
.stack(states_items_group_orange, 'orange')
.stack(states_items_group_apple, 'apple')
.stack(states_items_group_meat, 'meat')
.valueAccessor(function(p){ return p.value.count; })
.renderHorizontalGridLines(true)
.renderLabel(true)
.legend(dc.legend().x(100).y(0).horizontal(1).itemHeight(13).gap(6).legendWidth(400).itemWidth(100))
.gap(10)
.elasticX(true).elasticY(true)
.yAxisLabel("count")
.x(d3.scale.ordinal())
.xUnits(dc.units.ordinal)
.margins({top:30,left:50,right:10,bottom:50});
var bar2 = dc.barChart("#barchart2");
bar2.width(500).height(200)
.dimension(items)
.group(itemsGroup1,'MA')
.stack(itemsGroup2,'TN')
.stack(itemsGroup3,'TX')
.renderHorizontalGridLines(true)
.renderLabel(true)
.legend(dc.legend().x(60).y(0).horizontal(1).itemHeight(13).gap(6).legendWidth(400).itemWidth(60))
.gap(10)
.yAxisLabel("count")
.x(d3.scale.ordinal())
.xUnits(dc.units.ordinal)
.ordinalColors(["#008600","#80FF80","#FF80FF","#860086"])
.margins({top:30,left:50,right:10,bottom:50});
bar2.filterHandler(myFilterFunction);
dc.renderAll();
//reduce functions:
function reduceAdd(p,v){
if (v.items[0] === "") return p;
v.items.forEach(function(val,idx){
p[val] = (p[val] || 0) + 1;
});
return p;
}
function reduceRemove(p,v){
if (v.items[0] === "") return p;
v.items.forEach(function(val,idx){
p[val] = (p[val] || 0) - 1;
});
return p;
}
function reduceInitial(){
return {
bread: 0,
apple: 0,
orange: 0,
meat: 0
};
}
function reduceAdd1(p,v){
if (v.items[0] === "") return p;
if (v.state === "MA"){
v.items.forEach(function(val,idx){
p.bread += (val === 'bread' ? 1 : 0);
p.apple += (val === 'apple' ? 1 : 0);
p.orange += (val === 'orange' ? 1 : 0);
p.meat += (val === 'meat' ? 1 : 0);
});
}
return p;
}
function reduceRemove1(p,v){
if (v.items[0] === "") return p;
if (v.state === "MA"){
v.items.forEach(function(val, idx){
p.bread -= (val === 'bread' ? 1 : 0);
p.apple -= (val === 'apple' ? 1 : 0);
p.orange -= (val === 'orange' ? 1 : 0);
p.meat -= (val === 'meat' ? 1 : 0);
});
}
return p;
}
function reduceAdd2(p,v){
if (v.items[0] === "") return p;
if (v.state === "TN"){
v.items.forEach(function(val,idx){
p.bread += (val === 'bread' ? 1 : 0);
p.apple += (val === 'apple' ? 1 : 0);
p.orange += (val === 'orange' ? 1 : 0);
p.meat += (val === 'meat' ? 1 : 0);
});
}
return p;
}
function reduceRemove2(p,v){
if (v.items[0] === "") return p;
if (v.state === "TN"){
v.items.forEach(function(val,idx){
p.bread -= (val === 'bread' ? 1 : 0);
p.apple -= (val === 'apple' ? 1 : 0);
p.orange -= (val === 'orange' ? 1 : 0);
p.meat -= (val === 'meat' ? 1 : 0);
});
}
return p;
}
function reduceAdd3(p,v){
if (v.items[0] === "") return p;
if (v.state === "TX"){
v.items.forEach(function(val,idx){
p.bread += (val === 'bread' ? 1 : 0);
p.apple += (val === 'apple' ? 1 : 0);
p.orange += (val === 'orange' ? 1 : 0);
p.meat += (val === 'meat' ? 1 : 0);
});
}
return p;
}
function reduceRemove3(p,v){
if (v.items[0] === "") return p;
if (v.state === "TX"){
v.items.forEach(function(val,idx){
p.bread -= (val === 'bread' ? 1 : 0);
p.apple -= (val === 'apple' ? 1 : 0);
p.orange -= (val === 'orange' ? 1 : 0);
p.meat -= (val === 'meat' ? 1 : 0);
});
}
return p;
}
function reduceAdd_apple(p,v){
if (v.items[0] === "") return p;
p.state = v.state;
v.items.forEach(function(val,idx){
p.count += (val === 'apple' ? 1 : 0);
});
return p;
}
function reduceRemove_apple(p,v){
if (v.items[0] === "") return p;
p.state = v.state;
v.items.forEach(function(val,idx){
p.count -= (val === 'apple' ? 1 : 0);
});
return p;
}
function reduceAdd_bread(p,v){
if (v.items[0] === "") return p;
p.state = v.state;
v.items.forEach(function(val,idx){
p.count += (val === 'bread' ? 1 : 0);
});
return p;
}
function reduceRemove_bread(p,v){
if (v.items[0] === "") return p;
p.state = v.state;
v.items.forEach(function(val,idx){
p.count -= (val === 'bread' ? 1 : 0);
});
return p;
}
function reduceAdd_orange(p,v){
if (v.items[0] === "") return p;
p.state = v.state;
v.items.forEach(function(val,idx){
p.count += (val === 'orange' ? 1 : 0);
});
return p;
}
function reduceRemove_orange(p,v){
if (v.items[0] === "") return p;
p.state = v.state;
v.items.forEach(function(val,idx){
p.count -= (val === 'orange' ? 1 : 0);
});
return p;
}
function reduceAdd_meat(p,v){
if (v.items[0] === "") return p;
p.state = v.state;
v.items.forEach(function(val,idx){
p.count += (val === 'meat' ? 1 : 0);
});
return p;
}
function reduceRemove_meat(p,v){
if (v.items[0] === "") return p;
p.state = v.state;
v.items.forEach(function(val,idx){
p.count -= (val === 'meat' ? 1 : 0);
});
return p;
}
function reduceInitial_items(){
return {
count: 0,
state: ''
};
}
function myFilterFunction(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;
}
function myAllFunction(){
var newObject = [];
for(var key in this){
if(this.hasOwnProperty(key) && key != "all"){
newObject.push({
key: key,
value: this[key]
});
}
}
return newObject;
};发布于 2016-10-28 18:33:26
您需要做的第一件事是升级到:
接下来,有了这些新的优点,我们可以简化很多事情。下面是使用这些库的新特性更新的小提琴:https://jsfiddle.net/ff8ox8vq/
我将在下面的完整代码示例中详细介绍它们。
var data = [
{"key":"KEY-1","state":"MA", "items":["orange", "meat", "bread"], "date":"Y16"},
{"key":"KEY-2","state":"MA", "items":["apple", "bread"], "date":"Y15"},
{"key":"KEY-3","state":"TX", "items":["bread"], "date":"Y16"},
{"key":"KEY-4","state":"TN", "items":["apple", "bread"], "date":"Y16"},
{"key":"KEY-5","state":"TN", "items":["apple", "orange"], "date":"Y15"},
{"key":"KEY-6","state":"TN", "items": [], "date":"Y14"}
];
var cf = crossfilter(data);上面没有变化。
//dimensions and groups:
var dates = cf.dimension(function(d){ return d.date; });
var datesGroup = dates.group();
var states = cf.dimension(function(d){ return d.state; });
var statesGroup = states.group().reduceCount是组的默认设置。在一个新的小组上打电话什么都不做。reduceCount也不接受任何参数(不像reduceSum)。所以我们就把它处理掉。
var itemsDim = cf.dimension(function(d){ return d.items; }, true);
var itemsGroup = itemsDim.group();这就是它开始变得有趣的地方。CrossFilter1.4.0支持维度调用中的"Array维度“标志。如果我们将其设置为true,则交叉筛选器知道items是一个数组,并且在处理它的方式上非常聪明。您不再需要重写.all方法或类似的东西。是内部处理的。
var addValueGroup = function(reducer, key) {
reducer
.value(key)
.filter(function(d) { return d.items.indexOf(key) !== -1; })
.count(true)
}实用程序函数,用于向状态组添加特定项的计数。
// Reductio nest to break down states by item
var reducer = reductio().count(true)
addValueGroup(reducer, "orange")
addValueGroup(reducer, "meat")
addValueGroup(reducer, "bread")
addValueGroup(reducer, "apple")
reducer(statesGroup);配置statesGroup的分组。Reductio只是构建自定义的还原函数。这里发生的事情是,我们维护状态中所有记录的顶级计数,然后为每种类型的项创建过滤计数。运行后执行console.log(statesGroup.all())以查看结果组的结构。
//graphs:
var row = dc.rowChart("#rowchart");
row
.renderLabel(true)
.height(200)
.dimension(itemsDim)
.group(itemsGroup)
.ordering(function(d){return -d.value;})
.xAxis().ticks(3);
var pie1 = dc.pieChart("#piechart1");
pie1
.height(75)
.width(75)
.dimension(dates)
.group(datesGroup);没有变化。
var pie2 = dc.pieChart("#piechart2");
pie2
.height(75)
.width(75)
.dimension(states)
.group(statesGroup)
.valueAccessor(function(d) { return d.value.count; });我们的还原剂在一定程度上改变了这个组的结构,所以我们需要一个valueAccessor。
var bar = dc.barChart("#barchart");
bar.width(500).height(200)
.dimension(states)
.group(statesGroup, 'orange', sel_stack('orange'))
.stack(statesGroup, 'meat', sel_stack('meat'))
.stack(statesGroup, 'bread', sel_stack('bread'))
.stack(statesGroup, 'apple', sel_stack('apple'))
.renderHorizontalGridLines(true)
.renderLabel(true)
.legend(dc.legend())
.gap(10)
.yAxisLabel("count")
.x(d3.scale.ordinal())
.xUnits(dc.units.ordinal);只是没有什么花哨的自定义过滤功能。dc.js和交叉过滤器知道该做什么。不幸的是,在dc.js中似乎确实有一个带有序号堆叠条形图的错误,所以您现在必须正确地对条形进行后渲染:-(也许Gordon会在这里加入一个提示。
dc.renderAll();
function sel_stack(i) {
return function(d) {
return d.value[i] ? d.value[i].count : 0;
};
}由于更新后的组结构略有变化,如果您错误地键入其中一个项键,则有一点安全性。
发布于 2016-10-28 19:23:49
我修正了彩色堆栈问题和计数问题,以确定如何进行计数。我使用的是D3.jsverison2.5.5、crossfilter.js版本1.3.11以及2.1.0dev版本的dc.js和dc.css。https://jsfiddle.net/jnf84n7c/
var data = [
{"key":"KEY-1","state":"MA", "status":["A","R","C"], "items":["orange", "meat", "bread"], "date":"Y16"},
{"key":"KEY-2","state":"MA", "status":["A","O"], "items":["apple", "bread"], "date":"Y15"},
{"key":"KEY-3","state":"TX", "status":["O"], "items":["bread"], "date":"Y16"},
{"key":"KEY-4","state":"TN", "status":["A","R"], "items":["apple", "bread"], "date":"Y16"},
{"key":"KEY-5","state":"TN", "status":["A","O"], "items":["apple", "orange"], "date":"Y15"},
{"key":"KEY-6","state":"TN", "status":[], "items": [], "date":"Y14"}
];
var cf = crossfilter(data);
//dimensions and groups:
var dates = cf.dimension(function(d){ return d.date; });
var datesGroup = dates.group();//.reduceCount(function(d){ return d.key; });
var states = cf.dimension(function(d){ return d.state; });
var statesGroup = states.group();//.reduceCount(function(d){ return d.key; });
var itemsDim = cf.dimension(function(d){ return d.items; });
var itemsGroup = itemsDim.groupAll().reduce(reduceAdd, reduceRemove, reduceInitial).value();
itemsGroup.all = myAllFunction;
var states_items_group_apple = states.group().reduce(reduceAdd_apple, reduceRemove_apple, reduceInitial_items);
var states_items_group_bread = states.group().reduce(reduceAdd_bread, reduceRemove_bread, reduceInitial_items);
var states_items_group_orange = states.group().reduce(reduceAdd_orange, reduceRemove_orange, reduceInitial_items);
var states_items_group_meat = states.group().reduce(reduceAdd_meat, reduceRemove_meat, reduceInitial_items);
var itemsGroup1 = itemsDim.groupAll().reduce(reduceAdd1, reduceRemove1, reduceInitial).value();
var itemsGroup2 = itemsDim.groupAll().reduce(reduceAdd2, reduceRemove2, reduceInitial).value();
var itemsGroup3 = itemsDim.groupAll().reduce(reduceAdd3, reduceRemove3, reduceInitial).value();
itemsGroup1.all = myAllFunction;
itemsGroup2.all = myAllFunction;
itemsGroup3.all = myAllFunction;
var status = cf.dimension(function(d){ return d.status; });
var statusGroup1 = status.groupAll().reduce(reduceAdd_group1, reduceRemove_group1, reduceInitial_group).value();
var statusGroup2 = status.groupAll().reduce(reduceAdd_group2, reduceRemove_group2, reduceInitial_group).value();
var statusGroup3 = status.groupAll().reduce(reduceAdd_group3, reduceRemove_group3, reduceInitial_group).value();
var statusGroup4 = status.groupAll().reduce(reduceAdd_group4, reduceRemove_group4, reduceInitial_group).value();
statusGroup1.all = myAllFunction;
statusGroup2.all = myAllFunction;
statusGroup3.all = myAllFunction;
statusGroup4.all = myAllFunction;
var statusGroup = status.groupAll().reduce(reduceAdd_group, reduceRemove_group, reduceInitial_group).value();
statusGroup.all = myAllFunction;
//graphs:
var row = dc.rowChart("#rowchart");
row.height(170)
.dimension(itemsDim)
.group(itemsGroup)
.ordering(function(d){return -d.value;})
.renderLabel(true)
.ordinalColors(["#008600", "#80FF80", "#FF80FF", "#860086"])
.xAxis().ticks(3);
row.filterHandler(myFilterFunction);
var pie1 = dc.pieChart("#piechart1");
pie1.height(75).width(75)
.dimension(dates)
.group(datesGroup);
var pie2 = dc.pieChart("#piechart2");
pie2.height(75).width(75)
.dimension(states)
.group(statesGroup);
var pie3 = dc.pieChart("#piechart3");
pie3.height(75).width(75)
.dimension(status)
.group(statusGroup);
pie3.filterHandler(myFilterFunction);
var bar = dc.barChart("#barchart");
bar.width(500).height(200)
.dimension(states)
.group(states_items_group_bread, 'bread')
.stack(states_items_group_orange, 'orange')
.stack(states_items_group_apple, 'apple')
.stack(states_items_group_meat, 'meat')
.valueAccessor(function(p){ return p.value.count; })
.renderHorizontalGridLines(true)
.renderLabel(true)
.legend(dc.legend().x(100).y(0).horizontal(1).itemHeight(13).gap(6).legendWidth(400).itemWidth(100))
.gap(10)
.elasticX(true).elasticY(true)
.yAxisLabel("count")
.x(d3.scale.ordinal())
.xUnits(dc.units.ordinal)
.margins({top:30, left:50, right:10, bottom:50});
//bar.filterHandler(myFilterFunction);
//bar.on("renderlet", function(_chart){
// _chart.selectAll("rect.bar").on("click", _chart.onClick);
//});
var bar2 = dc.barChart("#barchart2");
bar2.width(500).height(200)
.dimension(itemsDim)
.group(itemsGroup1, 'MA')
.stack(itemsGroup2, 'TN')
.stack(itemsGroup3, 'TX')
.renderHorizontalGridLines(true)
.renderLabel(true)
.legend(dc.legend().x(60).y(0).horizontal(1).itemHeight(13).gap(6).legendWidth(400).itemWidth(60))
.gap(10)
.yAxisLabel("count")
.x(d3.scale.ordinal())
.xUnits(dc.units.ordinal)
.ordinalColors(["#008600", "#80FF80", "#FF80FF", "#860086"])
.margins({top:30, left:50, right:10, bottom:50});
bar2.filterHandler(myFilterFunction);
var bar3 = dc.barChart("#barchart3");
bar3.width(500).height(200)
.dimension(status)
.group(statusGroup1, "bread")
.stack(statusGroup2, "apple")
.stack(statusGroup3, "orange")
.stack(statusGroup4, "meat")
.renderHorizontalGridLines(true)
.renderLabel(true)
.legend(dc.legend().x(60).y(0).horizontal(1).itemHeight(13).gap(6).legendWidth(400).itemWidth(60))
.gap(10)
.yAxisLabel("count")
.x(d3.scale.ordinal())
.xUnits(dc.units.ordinal)
// .ordinalColors(["#008600", "#80FF80", "#FF80FF", "#860086"])
.margins({top:30, left:50, right:10, bottom:50});
bar3.filterHandler(myFilterFunction);
dc.renderAll(); // render graphs
//reduce functions:
function reduceAdd(p, v) {
if (v.items[0] === "") return p; // skip empty values
v.items.forEach (function(val, idx) {
p[val] = (p[val] || 0) + 1; //increment counts
});
return p;
}
function reduceRemove(p, v) {
if (v.items[0] === "") return p; // skip empty values
v.items.forEach (function(val, idx) {
p[val] = (p[val] || 0) - 1; //decrement counts
});
return p;
}
function reduceInitial() {
return {
bread: 0,
apple: 0,
orange: 0,
meat: 0
};
}
function reduceAdd1(p, v) {
if (v.items[0] === "") return p; // skip empty values
if (v.state === "MA"){
v.items.forEach (function(val, idx) {
p.bread += (val === 'bread' ? 1 : 0);
p.apple += (val === 'apple' ? 1 : 0);
p.orange += (val === 'orange' ? 1 : 0);
p.meat += (val === 'meat' ? 1 : 0);
});
}
return p;
}
function reduceRemove1(p, v) {
if (v.items[0] === "") return p; // skip empty values
if (v.state === "MA"){
v.items.forEach (function(val, idx) {
p.bread -= (val === 'bread' ? 1 : 0);
p.apple -= (val === 'apple' ? 1 : 0);
p.orange -= (val === 'orange' ? 1 : 0);
p.meat -= (val === 'meat' ? 1 : 0);
});
}
return p;
}
function reduceAdd2(p, v) {
if (v.items[0] === "") return p; // skip empty values
if (v.state === "TN"){
v.items.forEach (function(val, idx) {
p.bread += (val === 'bread' ? 1 : 0);
p.apple += (val === 'apple' ? 1 : 0);
p.orange += (val === 'orange' ? 1 : 0);
p.meat += (val === 'meat' ? 1 : 0);
});
}
return p;
}
function reduceRemove2(p, v) {
if (v.items[0] === "") return p; // skip empty values
if (v.state === "TN"){
v.items.forEach (function(val, idx) {
p.bread -= (val === 'bread' ? 1 : 0);
p.apple -= (val === 'apple' ? 1 : 0);
p.orange -= (val === 'orange' ? 1 : 0);
p.meat -= (val === 'meat' ? 1 : 0);
});
}
return p;
}
function reduceAdd3(p, v) {
if (v.items[0] === "") return p; // skip empty values
if (v.state === "TX"){
v.items.forEach (function(val, idx) {
p.bread += (val === 'bread' ? 1 : 0);
p.apple += (val === 'apple' ? 1 : 0);
p.orange += (val === 'orange' ? 1 : 0);
p.meat += (val === 'meat' ? 1 : 0);
});
}
return p;
}
function reduceRemove3(p, v) {
if (v.items[0] === "") return p; // skip empty values
if (v.state === "TX"){
v.items.forEach (function(val, idx) {
p.bread -= (val === 'bread' ? 1 : 0);
p.apple -= (val === 'apple' ? 1 : 0);
p.orange -= (val === 'orange' ? 1 : 0);
p.meat -= (val === 'meat' ? 1 : 0);
});
}
return p;
}
function reduceAdd_apple(p, v){
if (v.items[0] === "") return p; // skip empty values
p.state = v.state;
v.items.forEach(function(val, idx){
p.count += (val === 'apple' ? 1 : 0);
});
return p;
}
function reduceRemove_apple(p, v){
if (v.items[0] === "") return p; // skip empty values
p.state = v.state;
v.items.forEach(function(val, idx){
p.count -= (val === 'apple' ? 1 : 0);
});
return p;
}
function reduceAdd_bread(p, v){
if (v.items[0] === "") return p; // skip empty values
p.state = v.state;
v.items.forEach(function(val, idx){
p.count += (val === 'bread' ? 1 : 0);
});
return p;
}
function reduceRemove_bread(p, v){
if (v.items[0] === "") return p; // skip empty values
p.state = v.state;
v.items.forEach(function(val, idx){
p.count -= (val === 'bread' ? 1 : 0);
});
return p;
}
function reduceAdd_orange(p, v){
if (v.items[0] === "") return p; // skip empty values
p.state = v.state;
v.items.forEach(function(val, idx){
p.count += (val === 'orange' ? 1 : 0);
});
return p;
}
function reduceRemove_orange(p, v){
if (v.items[0] === "") return p; // skip empty values
p.state = v.state;
v.items.forEach(function(val, idx){
p.count -= (val === 'orange' ? 1 : 0);
});
return p;
}
function reduceAdd_meat(p, v){
if (v.items[0] === "") return p; // skip empty values
p.state = v.state;
v.items.forEach(function(val, idx){
p.count += (val === 'meat' ? 1 : 0);
});
return p;
}
function reduceRemove_meat(p, v){
if (v.items[0] === "") return p; // skip empty values
p.state = v.state;
v.items.forEach(function(val, idx){
p.count -= (val === 'meat' ? 1 : 0);
});
return p;
}
function reduceAdd_group1(p, v) {
if (v.items[0] === "") return p; // skip empty values
if (v.status[0] === "") return p; // skip empty values
v.items.forEach(function(val1, idx1){
if (val1 === "bread"){
v.status.forEach (function(val2, idx2) {
if (idx1 === idx2) {
p.A += (val2 === 'A' ? 1 : 0);
p.O += (val2 === 'O' ? 1 : 0);
p.C += (val2 === 'C' ? 1 : 0);
p.R += (val2 === 'R' ? 1 : 0);
}
});
}
});
return p;
}
function reduceRemove_group1(p, v) {
if (v.items[0] === "") return p; // skip empty values
if (v.status[0] === "") return p; // skip empty values
v.items.forEach(function(val1, idx1){
if (val1 === "bread"){
v.status.forEach (function(val2, idx2) {
if (idx1 === idx2) {
p.A -= (val2 === 'A' ? 1 : 0);
p.O -= (val2 === 'O' ? 1 : 0);
p.C -= (val2 === 'C' ? 1 : 0);
p.R -= (val2 === 'R' ? 1 : 0);
}
});
}
});
return p;
}
function reduceAdd_group2(p, v) {
if (v.items[0] === "") return p; // skip empty values
if (v.status[0] === "") return p; // skip empty values
v.items.forEach(function(val1, idx1){
if (val1 === "apple"){
v.status.forEach (function(val2, idx2) {
if (idx1 === idx2) {
p.A += (val2 === 'A' ? 1 : 0);
p.O += (val2 === 'O' ? 1 : 0);
p.C += (val2 === 'C' ? 1 : 0);
p.R += (val2 === 'R' ? 1 : 0);
}
});
}
});
return p;
}
function reduceRemove_group2(p, v) {
if (v.items[0] === "") return p; // skip empty values
if (v.status[0] === "") return p; // skip empty values
v.items.forEach(function(val1, idx1){
if (val1 === "apple"){
v.status.forEach (function(val2, idx2) {
if (idx1 === idx2) {
p.A -= (val2 === 'A' ? 1 : 0);
p.O -= (val2 === 'O' ? 1 : 0);
p.C -= (val2 === 'C' ? 1 : 0);
p.R -= (val2 === 'R' ? 1 : 0);
}
});
}
});
return p;
}
function reduceAdd_group3(p, v) {
if (v.items[0] === "") return p; // skip empty values
if (v.status[0] === "") return p; // skip empty values
v.items.forEach(function(val1, idx1){
if (val1 === "orange"){
v.status.forEach (function(val2, idx2) {
if (idx1 === idx2) {
p.A += (val2 === 'A' ? 1 : 0);
p.O += (val2 === 'O' ? 1 : 0);
p.C += (val2 === 'C' ? 1 : 0);
p.R += (val2 === 'R' ? 1 : 0);
}
});
}
});
return p;
}
function reduceRemove_group3(p, v) {
if (v.items[0] === "") return p; // skip empty values
if (v.status[0] === "") return p; // skip empty values
v.items.forEach(function(val1, idx1){
if (val1 === "orange"){
v.status.forEach (function(val2, idx2) {
if (idx1 === idx2){
p.A -= (val2 === 'A' ? 1 : 0);
p.O -= (val2 === 'O' ? 1 : 0);
p.C -= (val2 === 'C' ? 1 : 0);
p.R -= (val2 === 'R' ? 1 : 0);
}
});
}
});
return p;
}
function reduceAdd_group4(p, v) {
if (v.items[0] === "") return p; // skip empty values
if (v.status[0] === "") return p; // skip empty values
v.items.forEach(function(val1, idx1){
if (val1 === "meat"){
v.status.forEach (function(val2, idx2) {
if (idx1 === idx2) {
p.A += (val2 === 'A' ? 1 : 0);
p.O += (val2 === 'O' ? 1 : 0);
p.C += (val2 === 'C' ? 1 : 0);
p.R += (val2 === 'R' ? 1 : 0);
}
});
}
});
return p;
}
function reduceRemove_group4(p, v) {
if (v.items[0] === "") return p; // skip empty values
if (v.status[0] === "") return p; // skip empty values
v.items.forEach(function(val1, idx1){
if (val1 === "meat"){
v.status.forEach (function(val2, idx2) {
if (idx1 === idx2) {
p.A -= (val2 === 'A' ? 1 : 0);
p.O -= (val2 === 'O' ? 1 : 0);
p.C -= (val2 === 'C' ? 1 : 0);
p.R -= (val2 === 'R' ? 1 : 0);
}
});
}
});
return p;
}
function reduceAdd_group(p, v) {
if (v.status[0] === "") return p; // skip empty values
v.status.forEach (function(val, idx) {
p[val] = (p[val] || 0) + 1;
});
return p;
}
function reduceRemove_group(p, v) {
if (v.status[0] === "") return p; // skip empty values
v.status.forEach (function(val, idx) {
p[val] = (p[val] || 0) - 1;
});
return p;
}
function reduceInitial_group() {
return {
A: 0,
O: 0,
C: 0,
R: 0
};
}
function reduceInitial_items(){
return {
count: 0,
state: ''
};
}
//filter function:
function myFilterFunction (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;
}
//all function:
function myAllFunction() {
var newObject = [];
for (var key in this) {
if (this.hasOwnProperty(key) && key != "all") {
newObject.push({
key: key,
value: this[key]
});
}
}
return newObject;
};https://stackoverflow.com/questions/40307099
复制相似问题