D3.js:使用d3.nest()动态添加键 [英] D3.js: use d3.nest() adding keys dynamically

查看:1061
本文介绍了D3.js:使用d3.nest()动态添加键的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用 d3.nest()将平面JSON文件转换为分层树。这个工作很好,如果你事先知道在你的数据中发现的级别: d3.nest()创建一个嵌套级别的每个键函数传递它。 p>

但是,我想知道是否有一个优雅的方式来动态传递关键函数。这可能是一个基本的问题,但我的Javascript技能也是基本的。



这是一个使用存储在数组中的键名称的静态示例:

  var levels = ['first','second','third'] 

var root = {
key:root,
values:
d3.nest()
.key(function(d){return d [levels [0]]})
.key(function(d){return d [levels [1]]})
.key(function(d){return d [levels [2]
}



我现在的解决方案是一个if-else循环,伪动态创建不同的嵌套:

  //伪动态建立嵌套树
if(levels.length === 1){
var nest = d3.nest()
.key(function(d){return d [levels [0]]})

} else if(levels.length === 2){
var nest = d3.nest()
.key(function(d){return d [levels [0]]} )
.key(function(d){return d [levels [1]]})
.entries(data);
} else if(levels.length === 3){
var nest = d3.nest()
.key(function(d){return d [levels [0]]} )
.key(function(d){return d [levels [1]]})
.key(function(d){return d [levels [2]]})
。条目(数据);
}
[...]

传递密钥到 d3.nest()?我想要的是原则上像下面的例子(它不工作):

  var root = {
key:root,
values:
d3.nest()
for(var i = 0; i .key(function(d){return d [levels [i]]})
}
.entries(data)
}

感谢您的时间!

解决方案

容易作为你假设优雅的代码,但你可以肯定地简化它与你的if-else方法。



第一本能是做这样的事情:

  var levels = ['first','second','third'] 

var nest = d3.nest();
for(var i = 0; i< levels.length; i ++){
nest = nest.key(function(d){return d [levels [i]]});
//创建一个新的嵌套函数,并添加一个更多的键函数
//并将其保存在变量
}

var root = {
key:root,
values:nest.entries(data)//计算嵌套
}

,这不起作用,因为在您创建所有嵌套函数之后,才会使用嵌套功能,因此在嵌套实际运行时,您的 i 变量等于3和 levels [i] 返回undefined,因此 d [levels [i]] 返回undefined。 这里的示例



您需要创建一个单独的功能框,以便级别的正确值锁定:

  function createNestingFunction(propertyName){
return function(d){
return d [propertyName];
};
}

var levels = ['first','second','third']

var nest = d3.nest();
for(var i = 0; i< levels.length; i ++){
nest = nest.key(createNestingFunction(levels [i]))
//创建一个新的嵌套函数,添加一个更多的键函数
//并将其保存在变量

//函数`createNestingFunction`被调用*立即*
//带有基于`i'当前值的参数
//返回的函数将总是使用该参数
//无论多少次createNestingFunction被调用
}

var root = {
key:root,
values:nest.entries(data)//计算嵌套
}

示例的工作版本: http://fiddle.jshell.net/brVLH/1/


I am using d3.nest() to convert flat JSON files into hierarchical trees. This works just fine if you know in advance the levels that found in your data: d3.nest() creates a nesting-level for each key function you pass it.

However, I would like to know if there is an elegant way to dynamically pass key functions. This might be an elementary question, but my Javascript skills are also elementary.

This is a static example working with key names stored in an array:

var levels = ['first', 'second', 'third']

var root = {
    "key":"root", 
    "values": 
        d3.nest()
            .key(function(d){ return d[levels[0]] })
            .key(function(d){ return d[levels[1]] })
            .key(function(d){ return d[levels[2]] })
            .entries(data)
}

My solution now is an if-else loop that pseudo-dynamically creates different nestings:

// build the nested tree pseudo-dynamically
if (levels.length === 1) {
    var nest = d3.nest()
           .key(function(d){return d[levels[0]]})
           .entries(data);
} else if (levels.length === 2) {
    var nest = d3.nest()
           .key(function(d){return d[levels[0]]})
           .key(function(d){return d[levels[1]]})
           .entries(data);
} else if (levels.length === 3) {
    var nest = d3.nest()
           .key(function(d){return d[levels[0]]})
           .key(function(d){return d[levels[1]]})
           .key(function(d){return d[levels[2]]})
           .entries(data);
}
[...]

Is there an elegant way to dynamically pass keys to d3.nest()? What I would like is something in principle like the following example (which DOES NOT WORK):

var root = {
    "key":"root", 
    "values": 
        d3.nest()
            for (var i = 0; i < levels.length; i++) {
                .key(function(d){return d[levels[i]]})
            }
            .entries(data)
}

Thanks for your time!

解决方案

It's not as easy as you hypothetical elegant code, but you can certainly simplify it compared to your if-else method.

A first instinct is to do something like this:

var levels = ['first', 'second', 'third']

var nest = d3.nest();
for (var i = 0; i < levels.length; i++) {
    nest = nest.key(function(d){return d[levels[i]]});
    //create a new nesting function that has one more key function added
    //and save it in the variable
}

var root = {
      "key":"root", 
      "values": nest.entries(data) //compute the nest
    }

However, this doesn't work because your nesting function won't be used until after you create all your nesting functions, so by the time the nest is actually run your i variable equals 3 and levels[i] returns undefined, and therefore d[levels[i]] returns undefined. Example here.

You need to create a separate function enclosure so that the correct value from levels is locked in:

function createNestingFunction(propertyName){
  return function(d){ 
            return d[propertyName];
         };
}

var levels = ['first', 'second', 'third']

var nest = d3.nest();
for (var i = 0; i < levels.length; i++) {
    nest = nest.key( createNestingFunction(levels[i]) );
    //create a new nesting function that has one more key function added
    //and save it in the variable

    //the function `createNestingFunction` is called *immediately*
    //with a parameter based on the current value of `i`
    //the returned function will always use that parameter,
    //regardless of how many times createNestingFunction is called
}

var root = {
      "key":"root", 
      "values": nest.entries(data) //compute the nest
    }

The working version of the example: http://fiddle.jshell.net/brVLH/1/

这篇关于D3.js:使用d3.nest()动态添加键的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆