Skip to content

Commit

Permalink
documentation for the tree mark and the treeLink, treeNode transforms (
Browse files Browse the repository at this point in the history
…observablehq#1351)

* documentation for the tree mark and the treeLink, treeNode transforms

* tweaks

* tweaks

---------

Co-authored-by: Mike Bostock <mbostock@gmail.com>
  • Loading branch information
2 people authored and chaichontat committed Jan 14, 2024
1 parent c164951 commit 9ec0b81
Show file tree
Hide file tree
Showing 4 changed files with 196 additions and 0 deletions.
37 changes: 37 additions & 0 deletions src/marks/tree.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,47 @@ import type {TextOptions} from "./text.js";

// TODO tree channels, e.g., "node:name" | "node:path" | "node:internal"?
export interface TreeOptions extends DotOptions, LinkOptions, TextOptions, TreeTransformOptions {
/**
* Whether to represent the node with a dot; defaults to true unless a
* **marker** is specified.
*/
dot?: boolean;
/**
* The **stroke** color for the text mark to improve the legibility of labels
* atop other marks by creating a halo effect; defaults to *white*.
*/
textStroke?: MarkOptions["stroke"];
}

/**
* Transforms a tabular dataset into a hierarchy according to the given **path**
* input channel, which typically contains slash-separated strings; then
* executes a tree layout algorithm, by default Reingold–Tilford’s “tidy”
* algorithm, to compute *x* and *y* output channels; these channels can then be
* fed to other marks to construct a node-link diagram.
*
* These options control how the tabular data is organized into a hierarchy:
*
* * **path** - a channel specifying each node’s hierarchy location; defaults to identity
* * **delimiter** - the path separator; defaults to forward slash (/)
*
* These options control how the node-link diagram is laid out:
*
* * **treeLayout** - a tree layout algorithm; defaults to [d3.tree](https://github.com/d3/d3-hierarchy/blob/main/README.md#tree)
* * **treeAnchor** - a tree layout orientation, either *left* or *right*; defaults to *left*
* * **treeSort** - a node comparator, or null to preserve input order
* * **treeSeparation** - a node separation function, or null for uniform separation
*/
export function tree(data?: Data, options?: TreeOptions): CompoundMark;

/**
* Shorthand for Plot.tree using
* [d3.cluster](https://github.com/d3/d3-hierarchy/blob/main/README.md#cluster)
* as the **treeLayout** option, placing leaf nodes of the tree at the same
* depth. Equivalent to:
*
* ```js
* Plot.tree(data, {...options, treeLayout: d3.cluster})
* ```
*/
export function cluster(data?: Data, options?: TreeOptions): CompoundMark;
93 changes: 93 additions & 0 deletions src/transforms/tree.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,107 @@ import type {ChannelValue} from "../channel.js";
import type {CompareFunction, Transformed} from "./basic.js";

export interface TreeTransformOptions {
/**
* The location of each node in the hierarchy; typically slash-separated
* strings, as with UNIX-based file systems or URLs. Defaults to identity,
* assuming the mark’s data are path strings.
*/
path?: ChannelValue;

/**
* The path separator, used for inferring the hierarchy from the **path**
* channel; defaults to forward slash (/).
*/
delimiter?: string;

/**
* How to orient the tree. If the **treeAnchor** is *left*, the root of the
* tree will be aligned with the left side of the frame; if **treeAnchor** is
* *right*, the root of the tree will be aligned with the right side of the
* frame; use the **insetLeft** and **insetRight** *x* scale options if
* horizontal padding is desired, say to make room for labels.
*/
treeAnchor?: "left" | "right";

/**
* How to layout the tree. The default **treeLayout** implements the
* Reingold–Tilford “tidy” algorithm. Use
* [d3.cluster](https://github.com/d3/d3-hierarchy/blob/main/README.md#cluster)
* instead to align leaf nodes; see also Plot.cluster.
*/
treeLayout?: () => any;

/**
* How much space to reserve between adjacent nodes in the layout. If the
* **treeSeparation** is not null, it is a function that is passed two nodes
* in the hierarchy and returns the desired (relative) amount of separation;
* see [d3-hierarchy’s
* _tree_.separation](https://github.com/d3/d3-hierarchy/blob/main/README.md#tree_separation)
* for more. By default, non-siblings are at least twice as far apart as
* siblings.
*/
treeSeparation?: CompareFunction | null;

/**
* How to order nodes prior to laying them out. If the **treeSort** option is
* not null, it is typically a function that is passed two nodes in the
* hierarchy and compares them, similar to
* [_array_.sort](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort);
* see [d3-hierarchy’s
* _node_.sort](https://github.com/d3/d3-hierarchy/blob/main/README.md#node_sort)
* for more. The **treeSort** option can also be specified as a string, in
* which case it refers either to a named column in data, or if it starts with
* “node:”, a node value such as node:name.
*/
treeSort?: CompareFunction | {node: (node: any) => any} | string | null;
}

/**
* Populates the *x* and *y* channels with the positions for each node, and
* applies a default **frameAnchor** based on the specified **treeAnchor**. This
* transform is intended to be used with dot, text, and other point-based marks.
* This transform is rarely used directly; see the tree mark.
*
* The treeNode transform will derive output columns for any *options* that have
* one of the following named node values:
*
* * *node:name* - the node’s name (the last part of its path)
* * *node:path* - the node’s full, normalized, slash-separated path
* * *node:internal* - true if the node is internal, or false for leaves
* * *node:depth* - the distance from the node to the root
* * *node:height* - the distance from the node to its deepest descendant
*
* In addition, if any option value is specified as an object with a **node**
* method, a derived output column will be generated by invoking the **node**
* method for each node in the tree.
*/
export function treeNode<T>(options?: T & TreeTransformOptions): Transformed<T>;

/**
* Populates the *x1*, *y1*, *x2*, and *y2* channels, and applies the following
* defaults: **curve** is *bump-x*, **stroke** is #555, **strokeWidth** is 1.5,
* and **strokeOpacity** is 0.5. This transform is intended to be used with
* link, arrow, and other two-point-based marks. This transform is rarely used
* directly; see the tree mark.
*
* The treeLink transform will derive output columns for any *options* that have
* one of the following named link values:
*
* * *node:name* - the child node’s name (the last part of its path)
* * *node:path* - the child node’s full, normalized, slash-separated path
* * *node:internal* - true if the child node is internal, or false for leaves
* * *node:depth* - the distance from the child node to the root
* * *node:height* - the distance from the child node to its deepest descendant
* * *parent:name* - the parent node’s name (the last part of its path)
* * *parent:path* - the parent node’s full, normalized, slash-separated path
* * *parent:depth* - the distance from the parent node to the root
* * *parent:height* - the distance from the parent node to its deepest descendant
*
* In addition, if any option value is specified as an object with a **node**
* method, a derived output column will be generated by invoking the **node**
* method for each child node in the tree; likewise if any option value is
* specified as an object with a **link** method, a derived output column will
* be generated by invoking the **link** method for each link in the tree, being
* passed two node arguments, the child and the parent.
*/
export function treeLink<T>(options?: T & TreeTransformOptions): Transformed<T>;
45 changes: 45 additions & 0 deletions test/output/greekGodsExplicit.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 21 additions & 0 deletions test/plots/greek-gods.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,24 @@ Chaos Tartarus`
marks: [Plot.tree(gods)]
});
}

export async function greekGodsExplicit() {
const gods = `Chaos Gaia Mountains
Chaos Gaia Pontus
Chaos Gaia Uranus
Chaos Eros
Chaos Erebus
Chaos Tartarus`.split("\n");
return Plot.plot({
axis: null,
insetLeft: 10,
insetTop: 20,
insetBottom: 20,
insetRight: 120,
marks: [
Plot.link(gods, Plot.treeLink({stroke: "node:internal", delimiter: " "})),
Plot.dot(gods, Plot.treeNode({fill: "node:internal", delimiter: " "})),
Plot.text(gods, Plot.treeNode({text: "node:name", stroke: "white", fill: "currentColor", dx: 6, delimiter: " "}))
]
});
}

0 comments on commit 9ec0b81

Please sign in to comment.