具有可变儿童深度的d3.nest

时间:2014-02-25 16:39:03

标签: javascript d3.js sunburst-diagram

我有一个带有简单“类型”“计数”内容的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的条目/叶子。在示例数据中,您可以看到叶子可以处于任何深度。

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

1 个答案:

答案 0 :(得分: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