我有一个CSV数据集,我正在使用dc.js(crossfilter)。
Date, Country 1,Country 2,Country 3,Country 4,Country 5,Country 6,Target country (...)
2014/12/11, USA, France, UAE, (...), Iraq
我要做的是绘制一个行图,每个国家一行。 这是我今天的解决方案:
var countries = ndx.dimension(function(d) {
var list = [];
list.push(d["Country 1"]);
if (d["Country 2"]) {list.push(d["Country 2"]);};
if (d["Country 3"]) {list.push(d["Country 3"]);};
if (d["Country 4"]) {list.push(d["Country 4"]);};
if (d["Country 5"]) {list.push(d["Country 5"]);};
if (d["Country 6"]) {list.push(d["Country 6"]);};
return list;
});
var countriesGroup = countries.group().reduceSum(function(d) {
return d.totalNumberOfStrikes;
});;
countryChart
.width(400).height(500)
.group(countriesGroup)
.dimension(countries)
.ordering(function(d){ return -d.value });
但是,正如您所看到的,它不会在 list 数组中推送唯一身份。这会导致愚蠢的结果,因为CSV行中的每个国家/地区组合都会在列表中创建一个新项目。
我想要的是有一个包含每个唯一国家/地区的列表,然后在行图中绘制该事物。
你能帮忙吗? 非常感谢你!答案 0 :(得分:1)
执行此操作最简单的方法可能是展平您的阵列,因此您的源代码中只有Date, Country, Target
。像(未经测试)的东西:
var dest = [];
var countries = ["Country 1", "Country 2", ...]
source.forEach(function(d) {
countries.forEach(function(c) {
dest.push({Date: d.Date, Country: c, Target: d.Target});
});
});
然后将dest
传递给crossfilter而不是原始数据。
这样做的好处是,现在当您点击图表中的行时,您可以按个别国家/地区过滤其余图表。由于crossfilter只按行过滤,因此没有其他方法(没有严重的欺骗)可以按个别国家进行过滤而不会无意中过滤其他共享这些行的国家。
答案 1 :(得分:1)
根据以后的对话in another question和dc.js users group,这里有一个更好的缩减,可以保持数据不变:
var strikingCountriesGroup = xScaleDimension.group().reduce(
function(p, v) { // add
countryFields.forEach(function(c) {
if(v[c]) p[v[c]] = (p[v[c]] || 0) + v.totalNumberOfStrikes;
});
return p;
},
function(p, v) { // remove
countryFields.forEach(function(c) {
if(v[c]) p[v[c]] = p[v[c]] - v.totalNumberOfStrikes;
});
return p;
},
function() { // initial
return {};
}
);
虽然这可能看起来像是一大块括号,但我们的想法是字段v[c]
,其中c
是"国家1","国家2&# 34; ...在原始数据集中,间接指定要在缩减中创建的字段。
我们正在从值p
缩减到地图v
。我们遍历国家/地区字段,对于每个c
,如果v
有c
条目,我们会从v.totalNumberOfStrikes
添加或减去p[v[c]]
。如果值不存在,我们必须要小心:如果未定义,表达式|| 0
默认值为零。
然后,我们可以像这样动态创建堆栈(按值排序):
var reducedCountries = strikingCountriesGroup.all()[0].value;
var countries = d3.keys(reducedCountries).sort(function(a, b) {
return reducedCountries[b] - reducedCountries[a];
});
// we have to special-case the first group, see https://github.com/dc-js/dc.js/issues/797
var first = countries.shift();
strikingCountries
.group(strikingCountriesGroup, first,
function(d) {
return d.value[first];
});
// rest
countries.forEach(function(c) {
strikingCountries
.stack(strikingCountriesGroup, c,
function(d) {
return d.value[c];
});
});