我有一个交叉过滤器,输入了以下数据结构。
project | subproject | cost
data = [
["PrA", "SubPr1", 100],
["PrA", "SubPr2", 150],
["PrA", "SubPr3", 100],
["PrB", "SubPr4", 300],
["PrB", "SubPr5", 500],
["PrC", "SubPr6", 450]]
我可以创建一个条形图,其中包含每个项目的总成本:
var ndx = crossfilter(data)
var projDim = ndx.dimension(function(d){return d.project;});
var projGroup = costDim.group().reduceSum(function(d){return d.budget;});
我想要做的是按项目成本创建一个dc.js直方图......所以{450:2,300:1}等等。据我所知,crossfilter只能拥有每一行的属性输入维度。有没有解决的办法?
答案 0 :(得分:3)
接受挑战!
确实,crossfilter不支持这种双重缩减,但如果你愿意接受轻微的效率损失,你可以创建"假维度"和" fake groups"具有所需的行为。幸运的是,dc.js并没有使用很多的crossfilter API,所以你不必实现太多的方法。
技巧的第一部分是复制维度和组,以便新维度和旧维度都会在另一维上观察过滤。
第二部分是创建假组和维度,它们遍历复制组的区域,并根据值而不是键重新组合和重新过滤。
下面是一般解决方案的开始。对于某些图表,还需要实现group.top()
,通常可以将其转发到group.all()
。
function values_dimension(dim, group) {
return {
filter: function(v) {
if(v !== null)
throw new Error("don't know how to do this!");
return dim.filter(null);
},
filterFunction: function(f) {
var f2 = [];
group.all().forEach(function(kv) {
if(f(kv.value))
f2.push(kv.key);
});
dim.filterFunction(function(k) {
return f2.indexOf(k) >= 0;
});
return this;
}
};
}
function values_group(group) {
return {
all: function() {
var byv = [];
group.all().forEach(function(kv) {
if(kv.value === 0)
return;
byv[kv.value] = (byv[kv.value] || 0) + 1;
});
var all2 = [];
byv.forEach(function(d, i) {
all2.push({key: i, value: d});
});
return all2;
}
};
}
// duplicate the dimension & group so each will observe filtering on the other
var projDim2 = ndx.dimension(function(d){return d.project;});
var projGroup2 = projDim2.group().reduceSum(function(d){return d.budget;});
var countBudgetDim = values_dimension(projDim2, projGroup2),
countBudgetGroup = values_group(projGroup2);
jsfiddle here:http://jsfiddle.net/gordonwoodhull/55zf7L1L/
答案 1 :(得分:0)
Denormalize + Map-reduce。请注意,数据已经包含每个项目的成本作为第4列(这可以很容易地预先计算)。这是一个黑客,但希望是一个简单的方法,以使DC.js和crossfilter工作没有太大的变化。
var data = [
["PrA", "SubPr1", 100, 450],
["PrA", "SubPr2", 150, 450],
["PrA", "SubPr3", 200, 450],
["PrB", "SubPr4", 300, 800],
["PrB", "SubPr5", 500, 800],
["PrC", "SubPr6", 450, 450]
];
var newdata = data.map(function (d) {
return {
project: d[0],
subproject: d[1],
budget: d[2],
cost: d[3]
};
})
var ndx = crossfilter(newdata),
costDim = ndx.dimension(function (d) {
return d.cost;
}),
visitedProj = {},
costGroup = costDim.group().reduce(function (p, v) {
if (visitedProj[v.project]) return p;
console.info(v.project);
visitedProj[v.project] = true;
return p + 1;
}, null, function () {
return 0;
});
dc.rowChart("#costChart")
.renderLabel(true)
.dimension(costDim)
.group(costGroup)
.xAxis().ticks(2);
dc.renderAll();
Map-Reduce功能非常强大,可以从here访问API。 JSFillde Link