Skip to content

层级结构

¥Hierarchies

在计算 分层布局 之前,你需要一个根节点。如果你的数据已经是分层格式,例如 JSON,你可以将其直接传递给 hierarchy;否则,你可以使用 stratify 将表格数据(例如逗号分隔值 (CSV))重新排列成层次结构。

¥Before you can compute a hierarchical layout, you need a root node. If your data is already in a hierarchical format, such as JSON, you can pass it directly to hierarchy; otherwise, you can rearrange tabular data, such as comma-separated values (CSV), into a hierarchy using stratify.

hierarchy(data, children)

示例 · 源代码 · 根据指定的层级数据构造一个根节点。指定的数据必须是一个表示根节点的对象。例如:

¥Examples · Source · Constructs a root node from the specified hierarchical data. The specified data must be an object representing the root node. For example:

js
const data = {
  name: "Eve",
  children: [
    {name: "Cain"},
    {name: "Seth", children: [{name: "Enos"}, {name: "Noam"}]},
    {name: "Abel"},
    {name: "Awan", children: [{name: "Enoch"}]},
    {name: "Azura"}
  ]
};

构造层次结构:

¥To construct a hierarchy:

js
const root = d3.hierarchy(data);

为每个数据调用指定的 children 访问器函数,从根数据开始,并且必须返回表示子级(如果有)的数据的可迭代对象。如果未指定 children 访问器,则默认为:

¥The specified children accessor function is invoked for each datum, starting with the root data, and must return an iterable of data representing the children, if any. If the children accessor is not specified, it defaults to:

js
function children(d) {
  return d.children;
}

如果 data 是一个 Map,则会隐式转换为 [undefined, data] 类型的条目,而 children 访问器则默认为:

¥If data is a Map, it is implicitly converted to the entry [undefined, data], and the children accessor instead defaults to:

js
function children(d) {
  return Array.isArray(d) ? d[1] : null;
}

这允许你将 grouprollup 的结果传递给层次结构。

¥This allows you to pass the result of group or rollup to hierarchy.

返回的根节点及其每个后代节点具有以下属性:

¥The returned root node and each descendant has the following properties:

  • node.data - 传递给 hierarchy 的相关数据

    ¥node.data - the associated data as passed to hierarchy

  • node.depth - 根为零,每增加一代后代加一。

    ¥node.depth - zero for the root, increasing by one for each descendant generation

  • node.height - 与任何后代叶子节点的最大距离,如果是叶子节点则为零

    ¥node.height - the greatest distance from any descendant leaf, or zero for leaves

  • node.parent - 父节点,如果为根节点则为 null

    ¥node.parent - the parent node, or null for the root node

  • node.children - 子节点数组(如果有),或未定义叶子节点数组。

    ¥node.children - an array of child nodes, if any, or undefined for leaves

  • node.value - 节点及其 descendants 的可选总和值

    ¥node.value - the optional summed value of the node and its descendants

此方法还可用于测试节点是否为 instanceof d3.hierarchy 并扩展节点原型。

¥This method can also be used to test if a node is an instanceof d3.hierarchy and to extend the node prototype.

node.ancestors() {#node_ancestors}

源代码 · 返回祖级节点数组,从此节点开始,然后是每个父节点,直至根节点。

¥Source · Returns the array of ancestors nodes, starting with this node, then followed by each parent up to the root.

node.descendants() {#node_descendants}

源代码 · 返回后代节点数组,从此节点开始,然后按拓扑顺序依次是每个子节点。

¥Source · Returns the array of descendant nodes, starting with this node, then followed by each child in topological order.

node.leaves() {#node_leaves}

源代码 · 按遍历顺序返回叶节点数组。叶子节点是指没有子节点的节点。

¥Source · Returns the array of leaf nodes in traversal order. A leaf is a node with no children.

node.find(filter) {#node_find}

源代码 · 返回此节点的层次结构中第一个节点,指定过滤器为其返回真值。如果未找到这样的节点,则返回 undefined。

¥Source · Returns the first node in the hierarchy from this node for which the specified filter returns a truthy value. Returns undefined if no such node is found.

node.path(target) {#node_path}

源代码 · 返回从此节点到指定目标节点的层次结构中的最短路径。路径从此节点开始,向上移动到此节点和目标节点的最小公共祖级,然后向下移动到目标节点。这对 分层边缘打包 很有用。

¥Source · Returns the shortest path through the hierarchy from this node to the specified target node. The path starts at this node, ascends to the least common ancestor of this node and the target node, and then descends to the target node. This is useful for hierarchical edge bundling.

源代码 · 返回此节点及其后代的链接数组,其中每个链接都是一个定义源和目标属性的对象。每个链接的源是父节点,目标是子节点。

¥Source · Returns an array of links for this node and its descendants, where each link is an object that defines source and target properties. The source of each link is the parent node, and the target is a child node.

node.sum(value) {#node_sum}

示例 · 源代码 · 针对此节点及其 后序遍历 中的每个后代节点,计算指定的值函数,并返回此节点。每个节点的 node.value 属性设置为指定函数返回的数值加上所有子节点的值之和。该函数传递节点的数据,并且必须返回非负数。值访问器针对节点及其每个后代(包括内部节点)进行求值;如果只希望叶节点具有内部值,则对任何具有子节点的节点返回零。例如,作为 node.count 的替代方案:

¥Examples · Source · Evaluates the specified value function for this node and each descendant in post-order traversal, and returns this node. The node.value property of each node is set to the numeric value returned by the specified function plus the combined value of all children. The function is passed the node’s data, and must return a non-negative number. The value accessor is evaluated for node and every descendant, including internal nodes; if you only want leaf nodes to have internal value, then return zero for any node with children. For example, as an alternative to node.count:

js
root.sum((d) => d.value ? 1 : 0);

在调用需要 node.value 的分层布局(例如 treemap)之前,必须调用 node.sum 或 node.count。例如:

¥You must call node.sum or node.count before invoking a hierarchical layout that requires node.value, such as treemap. For example:

js
// Construct the treemap layout.
const treemap = d3.treemap();
treemap.size([width, height]);
treemap.padding(2);

// Sum and sort the data.
root.sum((d) => d.value);
root.sort((a, b) => b.height - a.height || b.value - a.value);

// Compute the treemap layout.
treemap(root);

// Retrieve all descendant nodes.
const nodes = root.descendants();

由于 API 支持 方法链,你还可以这样写:

¥Since the API supports method chaining, you can also say:

js
d3.treemap()
    .size([width, height])
    .padding(2)
  (root
      .sum((d) => d.value)
      .sort((a, b) => b.height - a.height || b.value - a.value))
  .descendants()

此示例假设节点数据具有值字段。

¥This example assumes that the node data has a value field.

node.count() {#node_count}

示例 · 源代码 · 计算此节点下的叶子节点数并将其赋值给 node.value,对节点的每个后代节点也执行类似操作。如果此节点是叶节点,则其计数为 1。返回此节点。另请参阅 node.sum

¥Examples · Source · Computes the number of leaves under this node and assigns it to node.value, and similarly for every descendant of node. If this node is a leaf, its count is one. Returns this node. See also node.sum.

node.sort(compare) {#node_sort}

示例 · 源代码 · 使用指定的比较函数,在 先序遍历 中对此节点(如果有)及其每个后代的子节点进行排序,并返回此节点。

¥Examples · Source · Sorts the children of this node, if any, and each of this node’s descendants’ children, in pre-order traversal using the specified compare function, and returns this node.

指定的函数传递两个节点 a 和 b 进行比较。如果 a 应该在 b 之前,则函数必须返回小于零的值;如果 b 应该在 a 之前,则该函数必须返回一个大于零的值;否则,未指定 a 和 b 的相对顺序。更多信息请参阅 array.sort

¥The specified function is passed two nodes a and b to compare. If a should be before b, the function must return a value less than zero; if b should be before a, the function must return a value greater than zero; otherwise, the relative order of a and b are not specified. See array.sort for more.

Unlike node.sum, the compare function is passed two nodes rather than two nodes’ data.例如,如果数据具有 value 属性,则按照节点及其所有后代节点的降序聚合值对节点进行排序,正如 circle-packing 的建议:

¥Unlike node.sum, the compare function is passed two nodes rather than two nodes’ data. For example, if the data has a value property, this sorts nodes by the descending aggregate value of the node and all its descendants, as is recommended for circle-packing:

js
root
    .sum((d) => d.value)
    .sort((a, b) => b.value - a.value);

同样,要按降序高度(与任何后代叶子节点的距离最大)对节点进行排序,然后按降序值对节点进行排序,就像对 treemapsicicles 的建议一样:

¥Similarly, to sort nodes by descending height (greatest distance from any descendant leaf) and then descending value, as is recommended for treemaps and icicles:

js
root
    .sum((d) => d.value)
    .sort((a, b) => b.height - a.height || b.value - a.value);

要按高度降序排列节点,然后按 ID 升序排列节点(建议对 treesdendrograms 进行排序):

¥To sort nodes by descending height and then ascending id, as is recommended for trees and dendrograms:

js
root
    .sum((d) => d.value)
    .sort((a, b) => b.height - a.height || d3.ascending(a.id, b.id));

如果你希望新的排序顺序影响布局,则必须在调用层次结构布局之前调用 node.sort;有关示例,请参阅 node.sum

¥You must call node.sort before invoking a hierarchical layout if you want the new sort order to affect the layout; see node.sum for an example.

nodeSymbol.iterator {#node_iterator}

源代码 · 返回一个按广度优先顺序遍历节点后代的迭代器。例如:

¥Source · Returns an iterator over the node’s descendants in breadth-first order. For example:

js
for (const descendant of node) {
  console.log(descendant);
}

node.each(function, that) {#node_each}

示例 · 源代码 · 为节点及其 广度优先顺序 中的每个后代调用指定的函数,使得只有在访问完所有较小深度的节点以及所有相同深度的先前节点后,才会访问给定节点。指定的函数传递当前后代、从零开始的遍历索引和此节点。如果指定了 this,则为回调的 this 上下文。

¥Examples · Source · Invokes the specified function for node and each descendant in breadth-first order, such that a given node is only visited if all nodes of lesser depth have already been visited, as well as all preceding nodes of the same depth. The specified function is passed the current descendant, the zero-based traversal index, and this node. If that is specified, it is the this context of the callback.

node.eachAfter(function, that) {#node_eachAfter}

示例 · 源代码 · 为节点及其 后序遍历 中的每个后代调用指定的函数,使得只有在访问完所有后代节点后,才会访问给定节点。指定的函数传递当前后代、从零开始的遍历索引和此节点。如果指定了 this,则为回调的 this 上下文。

¥Examples · Source · Invokes the specified function for node and each descendant in post-order traversal, such that a given node is only visited after all of its descendants have already been visited. The specified function is passed the current descendant, the zero-based traversal index, and this node. If that is specified, it is the this context of the callback.

node.eachBefore(function, that) {#node_eachBefore}

示例 · 源代码 · 为节点及其 先序遍历 中的每个后代调用指定的函数,使得只有在访问完所有祖级节点后,才会访问给定节点。指定的函数传递当前后代、从零开始的遍历索引和此节点。如果指定了 this,则为回调的 this 上下文。

¥Examples · Source · Invokes the specified function for node and each descendant in pre-order traversal, such that a given node is only visited after all of its ancestors have already been visited. The specified function is passed the current descendant, the zero-based traversal index, and this node. If that is specified, it is the this context of the callback.

node.copy() {#node_copy}

源代码 · 返回从此节点开始的子树的深层副本。(但是,返回的深层副本共享相同的数据。)返回的节点是新树的根节点;返回节点的父节点始终为 null,其深度始终为 0。

¥Source · Return a deep copy of the subtree starting at this node. (The returned deep copy shares the same data, however.) The returned node is the root of a new tree; the returned node’s parent is always null and its depth is always zero.