【问题标题】:Reduce multiple indirectly-specified fields using crossfilter使用交叉过滤器减少多个间接指定的字段
【发布时间】:2015-02-05 12:49:04
【问题描述】:

我有一个 CSV 数据集,我正在使用 dc.js(交叉过滤器)。

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 });

但是,如您所见,它不会将 uniques 推送到 list 数组中。这会导致愚蠢的结果,因为 CSV 行中的每个国家/地区组合都会在列表中创建一个新项目。

我想要的是有一个包含每个独特国家的列表,然后在行图中绘制。

你能帮忙吗? 非常感谢!

【问题讨论】:

    标签: csv dc.js crossfilter


    【解决方案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 传递给交叉过滤器,而不是您的原始数据。

    这样做的好处是,现在当您点击图表中的行时,您可以按各个国家/地区过滤其余图表。由于交叉过滤器仅按行过滤,因此没有其他方法(没有严重的技巧)可以按单个国家/地区进行过滤,而不会无意中过滤共享这些行的其他国家/地区。

    【讨论】:

    • 这里唯一的问题是,除了您的国家/地区维度之外,您的计数和总和在任何维度上都会被夸大。如果您需要处理这种情况,可以通过定义自定义分组来处理该问题。
    • 啊,说得好。您是否正在考虑简化为每个国家/地区具有字段的对象?
    • 老实说,我很迷茫。从昨天开始一直在修修补补,没有任何成功:(
    • 很抱歉,如果这没有帮助。 @Ethan,您是否在考虑像stackoverflow.com/questions/17524627/… 中的“一组标签”方法?
    • @Gordon 是的,我想就是这样。执行您的建议(将组合分解为单独的行),然后使用花哨的分组功能确保不要重复计算。 Reductio 支持这种求和和计数 - 请参阅自述文件底部的异常聚合示例 - github.com/esjewett/reductio 您可以看到将值列表保存在 github.com/esjewett/reductio/blob/master/src/value-list.js 的一般方法以及基于它们的计数在 github.com/esjewett/reductio/blob/master/src/exception-count.js
    【解决方案2】:

    根据后来的对话 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”......在原始数据集中,间接指定您要在缩减中创建的字段。

    我们正在从值v 减少到映射p。我们遍历国家字段,并且对于每个c,如果v 有一个c 的条目,我们从p[v[c]] 中添加或减去v.totalNumberOfStrikes。如果该值不存在,我们必须小心:表达式 || 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/

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多