d3.js 如何从 csv 或 table 生成树层次结构
d3.js how to generate tree hierarchy from csv or table
我有一个包含以下数据的 csv:
world,country,state
World,US,CA
World,US,NJ
World,INDIA,OR
World,INDIA,AP
我需要转换成如下所示的树层次结构:
{
"name": "World",
"children": [
{ "name": "US",
"children": [
{ "name": "CA" },
{ "name": "NJ" }
]
},
{ "name": "INDIA",
"children": [
{ "name": "OR" },
{ "name": "TN" }
]
}
]
};
使用 d3.nest 我只能得到一个 json 数组,而不是其中包含名称 'children' 的树。我还需要做什么吗?阅读 API 并没有真正帮助,而且我在搜索的任何地方都找不到执行转换的代码片段。
根据您的其他 question,我假设您想在 d3 分层布局中使用此分层数据
一旦被 d3.csv/tsv/dsv 等读取,您将得到一个带有 objects 的数组,如下所示:
[
{ "world": "World","country": "US","state": "CA" },
{ "world": "World","country": "US","state": "NJ" },
{ "world": "World","country": "INDIA","state": "OR" },
{ "world": "World","country": "INDIA","state": "AP"}
]
我们可以使用 d3 nest 来获得 d3 层次结构(树、树状图等)布局的可用树的大部分方法:
{
"key": "World", "values": [
{
"key": "US", "values": [
{ "world": "World", "country": "US", "state": "CA" },
{ "world": "World", "country": "US", "state": "NJ" }
]
},
{
"key": "INDIA", "values": [
{ "world": "World", "country": "INDIA", "state": "OR" },
{ "world": "World", "country": "INDIA", "state": "AP" }
]
}
]
}
这是用以下方法制作的:
var nestedData = d3.nest()
.key(function(d) { return d.world; })
.key(function(d) { return d.country; })
.entries(data);
这会生成一个数组,数组中的每一项都是一个根。要使用 d3.nest() 获取上面的 json,我们需要获取数组中的第一个元素,在本例中为 nestedData[0];
。另请注意,我们通常不需要嵌套最低级别,在本例中为 state
现在我们可以将此数据提供给 d3.hierarchy 以获得用于可视化的层次结构。如果您查看文档,我们有与示例相同的数据结构,除了我们的 children 包含在名为 "values" 而不是 "children" 的 属性 中。不用担心,d3.hierarchy 允许我们设置包含 children 的 属性 的名称:
d3.hierarchy(data[, children])
...
The specified children accessor function is invoked for each datum,
starting with the root data, and must return an array of data
representing the children, or null if the current datum has no
children. If children is not specified, it defaults to:
function children(d) { return d.children; }
因此,要获取从 d3.nest 创建的上述数据,让我们将其提供给 d3.hierarchy:
var root = d3.hierarchy(nestedData[0],function(d) { return d.values; })
现在我们有一个可以提供给任何 d3 分层布局的数据集:
var data = [
{ "world": "World","country": "US","state": "CA" },
{ "world": "World","country": "US","state": "NJ" },
{ "world": "World","country": "INDIA","state": "OR" },
{ "world": "World","country": "INDIA","state": "AP"}
];
var nestedData = d3.nest()
.key(function(d) { return d.world; })
.key(function(d) { return d.country; })
.entries(data);
var root = d3.hierarchy(nestedData[0], function(d) { return d.values; })
// Now draw the tree:
var width = 500;
var height = 400;
margin = {left: 10, top: 10, right: 10, bottom: 10}
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var g = svg.append("g").attr('transform','translate('+ margin.left +','+ margin.right +')');
var tree = d3.tree()
.size([height-margin.top-margin.bottom,width-margin.left-margin.right]);
var link = g.selectAll(".link")
.data(tree(root).links())
.enter().append("path")
.attr("class", "link")
.attr("d", d3.linkHorizontal()
.x(function(d) { return d.y; })
.y(function(d) { return d.x; }));
var node = g.selectAll(".node")
.data(root.descendants())
.enter().append("g")
.attr("class", function(d) { return "node" + (d.children ? " node--internal" : " node--leaf"); })
.attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; })
node.append("circle")
.attr("r", 2.5);
node.append("text")
.text(function(d) { return d.data.key; })
.attr('y',-10)
.attr('x',-10)
.attr('text-anchor','middle');
path {
fill:none;
stroke: steelblue;
stroke-width: 1px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>
Here's an example 具有实际的 csv 以及更多的行和级别。
如果 csv 数据结构不同,包含 parent、child 对,那么用 d3 解析后它看起来像这样。csv/tsv/dsv:
[
{parent: "", name: "World"},
{parent: "World", name:"US"},
{parent: "World", name:"India"},
{parent: "India", name:"OR" },
{parent: "India", name:"AP" },
{parent: "US", name:"CA" },
{parent: "US", name:"WA" }
]
这样我们就可以使用d3.stratify
代替d3.nest
和d3.hierarchy
的组合:
var data = [
{parent: "", name: "World"},
{parent: "World", name:"US"},
{parent: "World", name:"India"},
{parent: "India", name:"OR" },
{parent: "India", name:"AP" },
{parent: "US", name:"CA" },
{parent: "US", name:"WA" }
];
// manipulate data:
var root = d3.stratify()
.id(function(d) { return d.name; })
.parentId(function(d) { return d.parent; })
(data);
// Now draw the tree:
var width = 500;
var height = 400;
margin = {left: 10, top: 10, right: 10, bottom: 10}
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var g = svg.append("g").attr('transform','translate('+ margin.left +','+ margin.right +')');
var tree = d3.tree()
.size([height-margin.top-margin.bottom,width-margin.left-margin.right]);
var link = g.selectAll(".link")
.data(tree(root).links())
.enter().append("path")
.attr("class", "link")
.attr("d", d3.linkHorizontal()
.x(function(d) { return d.y; })
.y(function(d) { return d.x; }));
var node = g.selectAll(".node")
.data(root.descendants())
.enter().append("g")
.attr("class", function(d) { return "node" + (d.children ? " node--internal" : " node--leaf"); })
.attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; })
node.append("circle")
.attr("r", 2.5);
node.append("text")
.text(function(d) { return d.data.name; })
.attr('y',-10)
.attr('x',-10)
.attr('text-anchor','middle');
path {
fill: none;
stroke: steelblue;
stroke-width: 1px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>
我有一个包含以下数据的 csv:
world,country,state
World,US,CA
World,US,NJ
World,INDIA,OR
World,INDIA,AP
我需要转换成如下所示的树层次结构:
{
"name": "World",
"children": [
{ "name": "US",
"children": [
{ "name": "CA" },
{ "name": "NJ" }
]
},
{ "name": "INDIA",
"children": [
{ "name": "OR" },
{ "name": "TN" }
]
}
] };
使用 d3.nest 我只能得到一个 json 数组,而不是其中包含名称 'children' 的树。我还需要做什么吗?阅读 API 并没有真正帮助,而且我在搜索的任何地方都找不到执行转换的代码片段。
根据您的其他 question,我假设您想在 d3 分层布局中使用此分层数据
一旦被 d3.csv/tsv/dsv 等读取,您将得到一个带有 objects 的数组,如下所示:
[
{ "world": "World","country": "US","state": "CA" },
{ "world": "World","country": "US","state": "NJ" },
{ "world": "World","country": "INDIA","state": "OR" },
{ "world": "World","country": "INDIA","state": "AP"}
]
我们可以使用 d3 nest 来获得 d3 层次结构(树、树状图等)布局的可用树的大部分方法:
{
"key": "World", "values": [
{
"key": "US", "values": [
{ "world": "World", "country": "US", "state": "CA" },
{ "world": "World", "country": "US", "state": "NJ" }
]
},
{
"key": "INDIA", "values": [
{ "world": "World", "country": "INDIA", "state": "OR" },
{ "world": "World", "country": "INDIA", "state": "AP" }
]
}
]
}
这是用以下方法制作的:
var nestedData = d3.nest()
.key(function(d) { return d.world; })
.key(function(d) { return d.country; })
.entries(data);
这会生成一个数组,数组中的每一项都是一个根。要使用 d3.nest() 获取上面的 json,我们需要获取数组中的第一个元素,在本例中为 nestedData[0];
。另请注意,我们通常不需要嵌套最低级别,在本例中为 state
现在我们可以将此数据提供给 d3.hierarchy 以获得用于可视化的层次结构。如果您查看文档,我们有与示例相同的数据结构,除了我们的 children 包含在名为 "values" 而不是 "children" 的 属性 中。不用担心,d3.hierarchy 允许我们设置包含 children 的 属性 的名称:
d3.hierarchy(data[, children])
...
The specified children accessor function is invoked for each datum, starting with the root data, and must return an array of data representing the children, or null if the current datum has no children. If children is not specified, it defaults to:
function children(d) { return d.children; }
因此,要获取从 d3.nest 创建的上述数据,让我们将其提供给 d3.hierarchy:
var root = d3.hierarchy(nestedData[0],function(d) { return d.values; })
现在我们有一个可以提供给任何 d3 分层布局的数据集:
var data = [
{ "world": "World","country": "US","state": "CA" },
{ "world": "World","country": "US","state": "NJ" },
{ "world": "World","country": "INDIA","state": "OR" },
{ "world": "World","country": "INDIA","state": "AP"}
];
var nestedData = d3.nest()
.key(function(d) { return d.world; })
.key(function(d) { return d.country; })
.entries(data);
var root = d3.hierarchy(nestedData[0], function(d) { return d.values; })
// Now draw the tree:
var width = 500;
var height = 400;
margin = {left: 10, top: 10, right: 10, bottom: 10}
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var g = svg.append("g").attr('transform','translate('+ margin.left +','+ margin.right +')');
var tree = d3.tree()
.size([height-margin.top-margin.bottom,width-margin.left-margin.right]);
var link = g.selectAll(".link")
.data(tree(root).links())
.enter().append("path")
.attr("class", "link")
.attr("d", d3.linkHorizontal()
.x(function(d) { return d.y; })
.y(function(d) { return d.x; }));
var node = g.selectAll(".node")
.data(root.descendants())
.enter().append("g")
.attr("class", function(d) { return "node" + (d.children ? " node--internal" : " node--leaf"); })
.attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; })
node.append("circle")
.attr("r", 2.5);
node.append("text")
.text(function(d) { return d.data.key; })
.attr('y',-10)
.attr('x',-10)
.attr('text-anchor','middle');
path {
fill:none;
stroke: steelblue;
stroke-width: 1px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>
Here's an example 具有实际的 csv 以及更多的行和级别。
如果 csv 数据结构不同,包含 parent、child 对,那么用 d3 解析后它看起来像这样。csv/tsv/dsv:
[
{parent: "", name: "World"},
{parent: "World", name:"US"},
{parent: "World", name:"India"},
{parent: "India", name:"OR" },
{parent: "India", name:"AP" },
{parent: "US", name:"CA" },
{parent: "US", name:"WA" }
]
这样我们就可以使用d3.stratify
代替d3.nest
和d3.hierarchy
的组合:
var data = [
{parent: "", name: "World"},
{parent: "World", name:"US"},
{parent: "World", name:"India"},
{parent: "India", name:"OR" },
{parent: "India", name:"AP" },
{parent: "US", name:"CA" },
{parent: "US", name:"WA" }
];
// manipulate data:
var root = d3.stratify()
.id(function(d) { return d.name; })
.parentId(function(d) { return d.parent; })
(data);
// Now draw the tree:
var width = 500;
var height = 400;
margin = {left: 10, top: 10, right: 10, bottom: 10}
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var g = svg.append("g").attr('transform','translate('+ margin.left +','+ margin.right +')');
var tree = d3.tree()
.size([height-margin.top-margin.bottom,width-margin.left-margin.right]);
var link = g.selectAll(".link")
.data(tree(root).links())
.enter().append("path")
.attr("class", "link")
.attr("d", d3.linkHorizontal()
.x(function(d) { return d.y; })
.y(function(d) { return d.x; }));
var node = g.selectAll(".node")
.data(root.descendants())
.enter().append("g")
.attr("class", function(d) { return "node" + (d.children ? " node--internal" : " node--leaf"); })
.attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; })
node.append("circle")
.attr("r", 2.5);
node.append("text")
.text(function(d) { return d.data.name; })
.attr('y',-10)
.attr('x',-10)
.attr('text-anchor','middle');
path {
fill: none;
stroke: steelblue;
stroke-width: 1px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>