Skip to content

2D layout algorithms for visualizing hierarchical data.

License

Notifications You must be signed in to change notification settings

d3/d3-hierarchy

Repository files navigation

d3-hierarchy

Installing

If you use NPM, npm install d3-hierarchy. Otherwise, download the latest release.

API Reference

Hierarchy

# d3.hierarchy(data)

Constructs a root node from the specified hierarchical data. The specified data must be an object representing the root node, and may have a data.children property specifying an array of data representing the children of the root node; each descendant child data may also have data.children.

For example, given the following input data:

{
  "name": "Eve",
  "children": [
    {
      "name": "Cain"
    },
    {
      "name": "Seth",
      "children": [
        {
          "name": "Enos"
        },
        {
          "name": "Noam"
        }
      ]
    },
    {
      "name": "Abel"
    },
    {
      "name": "Awan",
      "children": [
        {
          "name": "Enoch"
        }
      ]
    },
    {
      "name": "Azura"
    }
  ]
}

The following code returns a root node:

var root = d3.hierarchy(data);

The node.data of each node in the returned hierarchy is a reference to the corresponding object in the input data. See also Stratify for how to convert tabular data into a hierarchy.

# node.sum(value)

Evaluates the specified value function for node and each descendant of node in post-order traversal. The value of each node is set to the numeric value returned by the specified function plus the combined value of all descendants. The function is passed the node’s data, and must return a non-negative number.

# node.sort(compare)

Sorts the children of node, if any, and each of node’s descendants’ children, in pre-order traversal using the specified compare function. 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.

# node.value

The combined value of this node and all its descendants; computed by node.sum.

# node.data

A reference to the data associated with this node, as specified to the constructor.

# node.depth

The depth of the node: zero for the root node, and increasing by one for each subsequent generation.

# node.parent

A reference to the parent node; null for the root node.

# node.children

An array of child nodes, if any; undefined for leaf nodes.

# node.ancestors()

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

# node.descendants()

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

# node.leaves()

Returns the array of leaf nodes in traversal order; leaves are nodes with no children.

# node.copy()

Return a deep copy of the tree starting at this root node. (The returned deep copy shares the same data, however.)

# node.each(function)

Invokes the specified function for node and each descendent 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 preceeding nodes of the same depth. The specified function is passed the current node.

# node.eachAfter(function)

Invokes the specified function for node and each descendent 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 node.

# node.eachBefore(function)

Invokes the specified function for node and each descendent 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 node.

Treemap

Treemap

Introduced by Ben Shneiderman in 1991, a treemap recursively subdivides area into rectangles according to each node’s associated value. D3’s treemap implementation supports an extensible tiling method: the default squarified method seeks to generate rectangles with a golden aspect ratio; this offers better readability and size estimation than slice-and-dice, which simply alternates between horizontal and vertical subdivision by depth.

# d3.treemap()

# treemap(root)

# treemap.tile([tile])

# treemap.size([size])

# treemap.round([round])

# treemap.padding([padding])

# treemap.paddingInner([padding])

# treemap.paddingOuter([padding])

Treemap Tiling

# d3.treemapBinary(node, x0, y0, x1, y1)

# d3.treemapDice(node, x0, y0, x1, y1)

Divides the rectangular area specified by x0, y0, x1, y1 horizontally according the value of each of the specified node’s children. The children are positioned in order, starting with the left edge (x0) of the given rectangle. If the sum of the children’s values is less than the specified node’s value (i.e., if the specified node has a non-zero internal value), the remaining empty space will be positioned on the right edge (x1) of the given rectangle.

# d3.treemapSlice(node, x0, y0, x1, y1)

Divides the rectangular area specified by x0, y0, x1, y1 vertically according the value of each of the specified node’s children. The children are positioned in order, starting with the top edge (y0) of the given rectangle. If the sum of the children’s values is less than the specified node’s value (i.e., if the specified node has a non-zero internal value), the remaining empty space will be positioned on the bottom edge (y1) of the given rectangle.

# d3.treemapSliceDice(node, x0, y0, x1, y1)

If the specified node has odd depth, delegates to treemapSlice; otherwise delegates to treemapDice.

# d3.treemapSquarify(node, x0, y0, x1, y1)

# squarify.ratio(ratio)

Partition

# d3.partition()

# partition(root)

# partition.size([size])

# partition.round([round])

# partition.padding([padding])

Pack

# d3.pack()

# pack(root)

# pack.radius([radius])

# pack.size([size])

# pack.padding([padding])

Stratify

Before you can compute a hierarchical layout, you need a hierarchical data structure. If you have hierarchical data already, such as a JSON file, you can pass it directly to the hierarchical layout; otherwise, you can rearrange tabular input data, such as a comma-separated values (CSV) file, into a hierarchy using d3.stratify.

For example, consider the following table of relationships:

Name Parent
Eve
Cain Eve
Seth Eve
Enos Seth
Noam Seth
Abel Eve
Awan Eve
Enoch Awan
Azura Eve

These names are conveniently unique, so we can unambiguously represent the hierarchy as a CSV file:

id,parentId
Eve,
Cain,Eve
Seth,Eve
Enos,Seth
Noam,Seth
Abel,Eve
Awan,Eve
Enoch,Awan
Azura,Eve

To parse the CSV using d3.csvParse:

var table = d3.csvParse(text);

This returns:

[
  {"id": "Eve",   "parentId": ""},
  {"id": "Cain",  "parentId": "Eve"},
  {"id": "Seth",  "parentId": "Eve"},
  {"id": "Enos",  "parentId": "Seth"},
  {"id": "Noam",  "parentId": "Seth"},
  {"id": "Abel",  "parentId": "Eve"},
  {"id": "Awan",  "parentId": "Eve"},
  {"id": "Enoch", "parentId": "Awan"},
  {"id": "Azura", "parentId": "Eve"}
]

To convert to a hierarchy:

var root = d3.stratify()(table);

This returns:

{
  "id": "Eve",
  "depth": 0,
  "data": {
    "id": "Eve",
    "parentId": ""
  },
  "children": [
    {
      "id": "Cain",
      "depth": 1,
      "parent": [Circular],
      "data": {
        "id": "Cain",
        "parentId": "Eve"
      }
    },
    {
      "id": "Seth",
      "depth": 1,
      "parent": [Circular],
      "data": {
        "id": "Seth",
        "parentId": "Eve"
      },
      "children": [
        {
          "id": "Enos",
          "depth": 2,
          "parent": [Circular],
          "data": {
            "id": "Enos",
            "parentId": "Seth"
          }
        },
        {
          "id": "Noam",
          "depth": 2,
          "parent": [Circular],
          "data": {
             "id": "Noam",
             "parentId": "Seth"
          }
        }
      ]
    },
    {
      "id": "Abel",
      "depth": 1,
      "parent": [Circular],
      "data": {
        "id": "Abel",
        "parentId": "Eve"
      }
    },
    {
      "id": "Awan",
      "depth": 1,
      "parent": [Circular],
      "data": {
        "id": "Awan",
        "parentId": "Eve"
      },
      "children": [
        {
          "id": "Enoch",
          "depth": 2,
          "parent": [Circular],
          "data": {
             "id": "Enoch",
             "parentId": "Awan"
          }
        }
      ]
    },
    {
      "id": "Azura",
      "depth": 1,
      "parent": [Circular],
      "data": {
        "id": "Azura",
        "parentId": "Eve"
      }
    }
  ]
}

This hierarchy can now be passed to a hierarchical layout, such as d3.treemap, for visualization. See bl.ocks.org/6bbb0a7ff7686b124d80 for another example.

# d3.stratify()

Constructs a new stratify operator with the default settings.

# stratify(data)

Generates a new hierarchy from the specified tabular data. Each node in the returned object has a shallow copy of the properties from the corresponding data object, excluding the following reserved properties: id, parentId, children.

# stratify.id([id])

If id is specified, sets the id accessor to the given function and returns this stratify operator. Otherwise, returns the current id accessor, which defaults to:

function id(d) {
  return d.id;
}

The id accessor is invoked for each element in the input data passed to the stratify operator, being passed the current datum (d) and the current index (i). The returned string is then used to identify the node’s relationships in conjunction with the parent id. For leaf nodes, the id may be undefined; otherwise, the id must be unique. (Null and the empty string are equivalent to undefined.)

# stratify.parentId([parentId])

If parentId is specified, sets the parent id accessor to the given function and returns this stratify operator. Otherwise, returns the current parent id accessor, which defaults to:

function parentId(d) {
  return d.parentId;
}

The parent id accessor is invoked for each element in the input data passed to the stratify operator, being passed the current datum (d) and the current index (i). The returned string is then used to identify the node’s relationships in conjunction with the id. For the root node, the parent id should be undefined. (Null and the empty string are equivalent to undefined.) There must be exactly one root node in the input data, and no circular relationships.