1

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

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

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

使用 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 的条目/叶子。在示例数据中,您可以看到,叶子可以处于任何深度。

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

4

1 回答 1

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 对象,然后是所有叶节点。如果没有其他级别,则值数组将是所有叶节点。

这是一些您可以逐步完成的工作代码:http: //jsfiddle.net/S8aMU/10

于 2014-02-25T20:57:43.060 回答