首页 > 解决方案 > 如何在 D3 中汇总 .csv 的过滤数据?

问题描述

在这个 .csv 文件中:

country,year,sex,num
Argentina,1985,male,150
Argentina,1985,female,240
Argentina,1986,male,100
Argentina,1986,female,200
Brazil,1985,male,10
Brazil,1985,female,140
Brazil,1986,male,45
Brazil,1986,female,48

如何将 num 列的值(150 和 240)相加,过滤国家:阿根廷和年份:1985 和 d3.js?

标签: csvd3.js

解决方案


假设您希望在国家和年份相同时求和一个值 - 而不仅仅是一个国家和一年:

您可以使用d3.nest()它,它可以让您对行共享某些属性的列求和,在这种情况下,您可以随时对num列求和country并且year相同:

var nest = d3.nest()
    .key(function(row) { return row.country; })
    .key(function(row) { return row.year; })
    .rollup(function(values) { return d3.sum(values, function(d) {return +d.num; })  })
    .entries(data);

var csv = d3.select("pre").text();

var data = d3.csvParse(csv);

var nest = d3.nest()
    .key(function(row) { return row.country; })
    .key(function(row) { return row.year; })
    .rollup(function(values) { return d3.sum(values, function(d) {return +d.num; })  })
    .entries(data);
    
console.log(nest);
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<pre>country,year,sex,num
Argentina,1985,male,150
Argentina,1985,female,240
Argentina,1986,male,100
Argentina,1986,female,200
Brazil,1985,male,10
Brazil,1985,female,140
Brazil,1986,male,45
Brazil,1986,female,48</pre>

我将 CSV 解析为文本,因为我无法在片段中加载实际的 CSV。

下面解释了代码,并演示了另一种结构,其中输出是 d3.map() 而不是数组。

按键分组数据

首先,我们可以按国家/地区对数据进行分组,为此我们使用nest().key()

var nest = d3.nest()
    .key(function(row) { return row.country; })

当提供一些数据时,嵌套的工作方式如下:

var csv = d3.select("pre").text();

var data = d3.csvParse(csv);

var nest = d3.nest()
    .key(function(row) { return row.country; })
    .entries(data);
    
console.log(nest);
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<pre>country,year,sex,num
Argentina,1985,male,150
Argentina,1985,female,240
Argentina,1986,male,100
Argentina,1986,female,200
Brazil,1985,male,10
Brazil,1985,female,140
Brazil,1986,male,45
Brazil,1986,female,48</pre>

结果数组的每个唯一键值都有一个条目,在这种情况下,每个国家/地区有一个条目:

[
  {
    "key": "Argentina",
    "values": [
      {
        "country": "Argentina",
        "year": "1985",
        "sex": "male",
        "num": "150"
      },
      {
        "country": "Argentina",
        "year": "1985",
        "sex": "female",
        "num": "240"
      }, ...

我们还可以通过创建第二个键按年份分组:

var nest = d3.nest()
    .key(function(row) { return row.country; })
    .key(function(row) { return row.year; })

其中,如果我们复制上面的代码片段,我们会得到一个类似的数组,现在多了一层:

[
  {
    "key": "Argentina",
    "values": [
      {
        "key": "1985",
        "values": [
          {
            "country": "Argentina",
            "year": "1985",
            "sex": "male",
            "num": "150"
          },
          {
            "country": "Argentina",
            "year": "1985",
            "sex": "female",
            "num": "240"
          }
        ]
      },
      {
        "key": "1986",
        "values": [
          {
            "country": "Argentina",
            "year": "1986",
            "sex": "male",
            "num": "100"
          }, ...

对分组值求和

我们还可以使用以下方法对这个嵌套数组的最低级别的值求和nest.rollup()

var csv = d3.select("pre").text();

var data = d3.csvParse(csv);

var nest = d3.nest()
    .key(function(row) { return row.country; })
    .key(function(row) { return row.year; })
    .rollup(function(values) { return d3.sum(values, function(d) {return +d.num; })  })
    .entries(data);

console.log(nest);
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<pre>country,year,sex,num
Argentina,1985,male,150
Argentina,1985,female,240
Argentina,1986,male,100
Argentina,1986,female,200
Brazil,1985,male,10
Brazil,1985,female,140
Brazil,1986,male,45
Brazil,1986,female,48</pre>

这给了我们一个与上面略有不同的结果,尽管结构相同:

[
  {
    "key": "Argentina",
    "values": [
      {
        "key": "1985",
        "value": 390
      },
      {
        "key": "1986",
        "value": 300
      }
    ]
  } ...

或者映射结果

如果您尝试查找单个值,上述结构并不总是理想的。我们可以使用nest.map()而不是nest.entries()创建d3 映射,以便我们可以轻松访问任何一个值:

var nest = d3.nest()
    .key(function(row) { return row.country; })
    .key(function(row) { return row.year; })
    .rollup(function(values) { return d3.sum(values, function(d) {return +d.num; })  })
    .map(data);

console.log(nest.get("Argentina").get("1985"));

它在行动中:

var csv = d3.select("pre").text();

var data = d3.csvParse(csv);

var nest = d3.nest()
    .key(function(row) { return row.country; })
    .key(function(row) { return row.year; })
    .rollup(function(values) { return d3.sum(values, function(d) {return +d.num; })  })
    .map(data);
    
console.log("Argentina, 1985: ",nest.get("Argentina").get("1985"));
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<pre>country,year,sex,num
Argentina,1985,male,150
Argentina,1985,female,240
Argentina,1986,male,100
Argentina,1986,female,200
Brazil,1985,male,10
Brazil,1985,female,140
Brazil,1986,male,45
Brazil,1986,female,48</pre>


推荐阅读