我有一个带有简单“类型”“计数”内容的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的条目/叶子。在示例数据中,您可以看到叶子可以处于任何深度。
如何构建嵌套数据,以便条目可以在任何深度发生,而不仅仅是在预定义的深度?
答案 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