使用crossfilter减少多个间接指定的字段

时间:2014-12-07 21:50:43

标签: csv dc.js crossfilter

我有一个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行中的每个国家/地区组合都会在列表中创建一个新项目。

我想要的是有一个包含每个唯一国家/地区的列表,然后在行图中绘制该事物。

你能帮忙吗? 非常感谢你!

2 个答案:

答案 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 questiondc.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,如果vc条目,我们会从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];
             });
  });

在这里小提琴:http://jsfiddle.net/gordonwoodhull/gfe04je9/11/