d3使用循环嵌套在几个键上

bob*_*bby 4 javascript csv svg nested d3.js

我正在使用d3.nest()来从CSV文件创建分层对象.

你能帮我理解为什么以下代码不起作用.我没有设法在循环中使用嵌套函数,如下所述.

我有以下CSV文件,取自d3网站上的示例:

"type1","type2","type3","type4","type5","size"
"flare","analytics","cluster","AgglomerativeCluster","","3938"
"flare","analytics","cluster","CommunityStructure","","3812"
"flare","analytics","cluster","MergeEdge","","743"
"flare","analytics","graph","BetweennessCentrality","","3534"
"flare","analytics","graph","LinkDistance","","5731"
Run Code Online (Sandbox Code Playgroud)

这个基本的嵌套工作原理:

data = data.entries(csv)
        .key(function(d) {return d.type1; })
        .key(function(d) {return d.type2; })
        .key(function(d) {return d.type3; })
        .entries(csv);
Run Code Online (Sandbox Code Playgroud)

我想使用一个值数组来指定我的键,以便动态地修改它们.

这有效:

    var data = d3.nest();
    var nesting = ["type1","type2","type3"];
    data = data.key(function(d) {return d[nesting[0]]; });
    data = data.key(function(d) {return d[nesting[1]]; });
    data = data.key(function(d) {return d[nesting[2]]; });
    data = data.entries(csv);
Run Code Online (Sandbox Code Playgroud)

但它不适用于循环......

    var data = d3.nest();
    for(var i=0;i<nesting.length;i++)
    {
        data = data.key(function(d) {return d[nesting[i]]; });
    }
    data = data.entries(csv);
Run Code Online (Sandbox Code Playgroud)

我无法理解为什么循环版本不起作用...也许我想念d3.nest()功能...

此外,我想知道是否有一种方法可以"跳过"嵌套级别,如果此级别没有任何内容填充(即:上面提取的所有行中的"type5"级别).我怎么能这样做?

非常感谢阅读!

nra*_*itz 16

这对.nest()运算符来说不是问题,这是JavaScript闭包的问题.任何时候你有这种模式:

for (var x=0; x < y; x++) {
    something.attachCallback(function() {
        // now do something with x
    });
}
Run Code Online (Sandbox Code Playgroud)

你将会遇到关闭问题.您定义的内部匿名函数不包含值的副本x,它包含对外部变量的引用,该外部变量x将在外部变量更新时更新.因此,在循环结束时x,每个回调函数的值都将是x循环中的最终值(在上面的代码中,y在代码中nesting.length).

D3 .nest()运算符使用其.key()参数作为回调 - 它们在您调用.map()或之前不会执行.entries().所以上面的问题适用.

有多种方法可以解决这个问题; 我倾向于使用.forEach()而不是for循环.这在旧版浏览器中不起作用,但D3的大部分都不适用,所以你可能很安全:

var data = d3.nest();
nesting.forEach(function(key) {
    data.key(function(d) {return d[key]; })
});
Run Code Online (Sandbox Code Playgroud)

另一种选择是使用单独的函数进行回调定义.将迭代器变量传递给另一个函数将"修复"其值,因为回调现在具有对创建者函数的参数的引用,而不是对原始x变量的引用:

var data = d3.nest();

function addKey(index) {
    data.key(function(d) { return d[nesting[index]]; })
}

for(var i=0;i<nesting.length;i++) {
    addKey(i);
}
Run Code Online (Sandbox Code Playgroud)

还有一些其他的方法,但在我看来forEach是最优雅的.