Skip to content

Sankey Chart

The Sankey Chart routes weighted flows between nodes as links whose width is proportional to the value carried, so where a quantity splits and merges is visible without reading a single number. Reach for it for energy and material flows, budget allocation, process pipelines and user journeys. Nodes are placed automatically by a layered layout: iterations sets how many relaxation passes it makes, and nodeWidth and nodePadding size the columns. Hover a link to highlight it, and legend and format handle the annotation. Renders to Canvas, SVG or a terminal context.

NOTE

For the full API, see the Charts API Reference.

Example

Usage

ts
import {
    createSankeyChart,
} from '@ripl/charts';

const chart = createSankeyChart('#container', {
    nodes: [
        {
            id: 'a',
            label: 'Source A',
        },
        {
            id: 'b',
            label: 'Target B',
        },
    ],
    links: [
        {
            source: 'a',
            target: 'b',
            value: 100,
        },
    ],
});

Data Format

A sankey chart takes nodes and the links between them. A link's source and target are node ids, and its value sets the ribbon's thickness:

ts
const nodes = [
    {
        id: 'search',
        label: 'Search',
    },
    {
        id: 'signup',
        label: 'Sign up',
    },
    {
        id: 'purchase',
        label: 'Purchase',
    },
];

const links = [
    {
        source: 'search',
        target: 'signup',
        value: 620,
    },
    {
        source: 'signup',
        target: 'purchase',
        value: 180,
    },
];

Node depth is computed from the link graph, so nodes do not need to be ordered.

Options

A full configuration for this chart. The options every chart shares — padding, title, animation, theme and the rest — behave the same everywhere and are documented on Shared Options.

ts
createSankeyChart('#container', {
    nodes,
    links,
    // Width of each node rectangle, in pixels.
    nodeWidth: 20,
    // Vertical gap between stacked nodes in a column, in pixels.
    nodePadding: 10,
    // Layout relaxation passes. Accepted and reserved for tuning node positioning — the current
    // layout does not read it, so changing it has no visible effect yet.
    iterations: 6,
    legend: { position: 'bottom' },
    format: 'number',
});

Events

Subscribe with chart.on(...). A handler receives an Event object, not the payload directly — the payload is on event.data, and carries the interacted datum plus its { x, y } anchor in chart pixels. event.target and event.stopPropagation() are also available.

ts
// Emitted when a node is clicked.
chart.on('nodeclick', event => console.log(event.data)); // event.data: SankeyChartNodeEvent<TData>
// Emitted when the pointer enters a node.
chart.on('nodeenter', event => console.log(event.data)); // event.data: SankeyChartNodeEvent<TData>
// Emitted when the pointer leaves a node.
chart.on('nodeleave', event => console.log(event.data)); // event.data: SankeyChartNodeEvent<TData>
// Emitted when a link is clicked.
chart.on('linkclick', event => console.log(event.data)); // event.data: SankeyChartLinkEvent
// Emitted when the pointer enters a link.
chart.on('linkenter', event => console.log(event.data)); // event.data: SankeyChartLinkEvent
// Emitted when the pointer leaves a link.
chart.on('linkleave', event => console.log(event.data)); // event.data: SankeyChartLinkEvent