javascript - 使用 D3.js 加载和解析多个 csv 文件

标签 javascript d3.js

我正在使用 D3.js 实现 map 可视化。我有许多 x csv 文件(矩阵)。我想加载它们并对所有文件中的所有值求和。

我在名称数组上实现了 for 循环,并使用 d3.text 加载和解析数据,但由于异步行为,我找不到方法来执行此操作(我得到首先来自 console.logundefined,然后是 for 循环的结果)。

我尝试使用 async.js 但我不知道如何允许 for 循环的流程。这是我的代码:

var total=[];
var matrix=[];

for(var i=0; i<filenames.length; i++){

    d3.text(filenames[i], function(text){
      matrix = d3.csv.parseRows(text).map(function (row){
        return row.map(function(value){ 
          return +value;
        });
      });
    });

    //sum the matrix pseudocode
    for(...){
      total = total + matrix;
    }
}

//here I need the sum of all files and then do other stuffs with the total:
console.log(total);
...
...

我怎样才能实现这个目标?谢谢。

最佳答案

我建议您使用递归函数来完成此操作。

在下面的示例中,您可以像 d3.text() 一样使用 loadFilesAndCalculateSum(),但它不是一个字符串,而是一个字符串数组,并且回调获取计算出的总和而不是文件的文本。

/**
 * load all files and calculate the sum of the values
 * @param  {Array}    filenames Array with filenames as string
 * @param  {Function} cb        Callback function, gets the sum as param
 * @param  {number}   sum       The initial sum   
 * @param  {number}   i         Starting index for filenames
 * @return {void}
 */
function loadFilesAndCalculateSum(filenames, cb, sum, i) {
  sum = sum || 0;
  i = i || 0;
  d3.text(filenames[i], function(error, text) {
    //parse the rows and reduce them
    sum += d3.csv.parseRows(text).reduce(function(prev, curr) {
      //return previous sum + this rows sum
      return prev + d3.sum(curr, function(d){return +d;})
    },0); 

    if(i < filenames.length - 1){
      //load next file
      loadFilesAndCalculateSum(filenames, cb, sum, i+1);
    } else {
      //call the callback with the final sum
      cb(sum);
    }
  });
}

var filenames = ["file1.txt", "file2.txt", "file3.txt"];

loadFilesAndCalculateSum(filenames, function(sum){
  //do something with the total sum
  console.log(sum);
});

为了澄清这一点。您必须在回调函数内部对总和进行处理,我在其中添加了注释对总和进行处理。该函数仍在异步执行。这意味着,您在 loadFilesAndCalculateSum() 函数之后编写的所有内容都可能在回调内的代码之前执行。您可以找到async javascript here的更长一点的介绍。

//this is executed first
//....
loadFilesAndCalculateSum(filenames, function(sum){
  //do something with the total sum
  //this is executed third, when all files are loaded and the sum is calculated
  console.log(sum);
});

//code after this point is executed second, while the files are being loaded.

如果您已经有一个对总和执行某些操作的函数,则可以将此函数作为第二个参数传递给 loadFilesAndCalculateSum。这是可能的,因为函数被称为 first class citizens :

var addthis = 5;

function doSomethingWithTheSum(sum) {
  //everything you want to do with the sum goes inside this function.

  //from here you could call other functions and pass the sum.
  soSomethingDifferentWithTheSum(sum);

  //or you use the sum inside this function
  console.log(sum);
  var newsum = sum + addthis;
  console.log(sum);

  d3.select("whatever")
      .data([sum])
      .enter()
    .append("text")
      .text(function(d){ return d;});
}

loadFilesAndCalculateSum(filenames, doSomethingWithTheSum);

您可以像传递任何其他变量一样传递函数。在第一个示例中,我调用了 loadFiles... 函数的第二个参数 cb,它是 callback 的常用缩写。如文档注释中所述,此参数应为 Function 类型。

loadFiles... 函数的末尾,回调函数被调用

....
//call the callback with the final sum
cb(sum);
....

这里将总和作为第一个参数提供给回调函数。因此,如果您传递一个函数,它应该采用单个参数,例如第一个示例中的匿名函数或上面示例中的 doSomethingWithTheSum 函数。

关于javascript - 使用 D3.js 加载和解析多个 csv 文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30766696/

相关文章:

javascript - 为什么以下函数在执行 `greet({ name = ' Rauno' } = {} )` instead of ` greet(name = 'Rauno')`?

javascript - 选择三个具有属性值的div

javascript - 在柱形图中旋转标签 d3.JS

javascript - 如何在 d3 上标记力导向图?

svg - D3.js - 如何在此可折叠树中的文本中添加新行?

php ajax mysql 投票按钮,第一次点击没有注册

javascript - 如何将唯一 id 分配给与其行号对应的复选框(更新 : or item ID) under Bootstrap 4?

javascript - 当我在同一页面上有两个图形 D3.js 时宽度异常

javascript - dc.js - 使用 jquery 数据表插件的数据表

javascript - 新 D3 API 中 '.orient()' 的替代项是什么?