【问题标题】:d3.nest with variable children depthd3.nest 具有可变子深度
【发布时间】:2014-02-25 16:39:03
【问题描述】:

我有一个带有简单“类型”“计数”内容的 tsv 文件,如下所示:

type    count
level1/level2/level3/Foo    24
level1/level2/level3/Bar    2
level1/level2/Baz   28
level1/level2/Quz   3
...

level 字符串可以是任何字符串,我在这里只是这样命名它们,以传达含义。该类型的最后一个元素FooBar等可以认为是数据的叶子。

使用 d3,我想把它变成一个旭日形图。为此,我使用d3.nest 函数在斜线处分解类型。

d3.tsv("data.tsv", function(error, data) {
  data.forEach(function(d) {
    d.count = +d.count;
  });

  // define key functions for a depth up to 4 
  var nestedData = d3.nest()
     .key(function(d) { return level(d.type, 2); })
     .key(function(d) { return level(d.type, 3); })
     .key(function(d) { return level(d.type, 4); })
     .entries(data);

  // create the key for a specified level 
  function level(type, l) {
     var parts = type.split("/");
     var result = "";
     for (i = 0; i < l && i < parts.length; i++) {
        result += parts[i];
        if (i < l-1 && i < parts.length-1) {
            result += "/";
        }
     }
     return result;
  }
  ...

这里的问题是生成的nestedData 的条目/叶子总是深度为 4。在示例数据中,您可以看到叶子可以处于任何深度。

如何构造嵌套数据,以便条目可以出现在任何深度,而不仅仅是在预定义的深度?

【问题讨论】:

    标签: javascript d3.js sunburst-diagram


    【解决方案1】:

    由于d3.nest 让您在调用nest.entries 之前提前注册嵌套键,因此无法通过预先指定所有内容来执行具有可变层数的嵌套。

    可能有用的一件事是递归地使用nest.rollup 函数来控制每个级别的值的样子。在 rollup 中,您可以决定每个条目元素是否应该是包含下一级详细信息的新 d3.nest,或者是否应该是叶节点。

    这是一个粗略的破解(假设level1 将始终存在):

    function rollupFn(group) {
        var leaves = [],
            groups = [];
    
        // Split the items into leaves and groups
        group.forEach(function(item) {
            // First eliminate level already accounted for by d3.nest key
            item.type = item.type.substr(item.type.indexOf('/')+1);
    
            if (item.type.indexOf('/') > -1) {
                groups.push(item);
            } else {
                leaves.push(item);
            }
        });
    
        // Convert the "group" items into a d3.nest object
        groups = d3.nest().key(function(d) {
                return d.type.split('/')[0];
            })
            .rollup(rollupFn)
            .entries(groups);
    
        var results = [];
        if (groups.length > 0) { results.push(groups); }
        if (leaves.length > 0) { results.push(leaves); }
        return results;
    };
    
    var nestedData = d3.nest()
        .key(function(d) { return "level1" })  // optional: first group contains everything
        .rollup(rollupFn)
        .entries(data);
    

    每个级别的值将由一个元素组成,该元素包含一个代表所有较低级别的 d3.nest 对象,然后是所有叶节点。如果没有其他级别,则 values 数组将是所有叶节点。

    这里有一些你可以单步执行的工作代码:http://jsfiddle.net/S8aMU/10

    【讨论】:

    • 我无法让它工作。 rollup 的文档很少。使用这个,叶子节点都被添加到nestedData的第二层。我认为问题可能是 item.type 被重新分配,从而删除了两者之间的级别。
    • 我应该知道我第一次做对的机会基本上为零。 :P 我创建了一个 jsfiddle,所以我可以稍微玩一下,所以它现在应该可以更好地工作了。
    • 这很好用,谢谢!为了在旭日形图中使用,我只对其进行了更改,以便 groupsleaves 元素都直接在 results 数组中。
    • 这很有帮助,谢谢!我还改变了它的返回方式,而不是创建一个results 数组并推送组和离开,我只是做了return groups.concat(leaves)
    猜你喜欢
    • 2013-11-14
    • 1970-01-01
    • 2011-07-19
    • 1970-01-01
    • 2015-07-14
    • 2020-04-09
    • 1970-01-01
    • 1970-01-01
    • 2018-10-24
    相关资源
    最近更新 更多