Sankey
Flow
"Where does it all go?" A Sankey diagram traces flow through a system: nodes are laid out in columns, and the thickness of each band is the flow value. It is the right picture for trade between exporters and markets, budget from sources to uses, traffic from referrers to pages - anywhere a quantity splits and recombines on its way across.
Layout is computed with d3-sankey: nodes are assigned to columns from the graph topology, packed vertically, and links drawn as smooth horizontal bands. Hover a node or a flow for its figures.
Usage
import { SankeyChart } from "@michi-vz/react";
export default () => <SankeyChart {...props} />; // props = the chart options<script setup>
import { SankeyChart } from "@michi-vz/vue";
</script>
<template>
<SankeyChart :options="props" />
</template><script>
import { sankeyChart } from "@michi-vz/svelte";
</script>
<div use:sankeyChart={props}></div>// main.ts - register the elements once
import "@michi-vz/angular";
import { applySankeyChartProps } from "@michi-vz/angular";
// component (uses CUSTOM_ELEMENTS_SCHEMA)
// template: <michi-vz-sankey-chart #c></michi-vz-sankey-chart>
applySankeyChartProps(this.c.nativeElement, props);<script type="module" src="https://cdn.jsdelivr.net/npm/@michi-vz/wc"></script>
<michi-vz-sankey-chart id="c"></michi-vz-sankey-chart>
<script>
Object.assign(document.getElementById("c"), props); // nodes, links, …
</script>import { mountSankeyChart } from "@michi-vz/core";
const chart = mountSankeyChart(el, props);
chart.update(next);
chart.getContext(); // renderer-agnostic, LLM-ready
chart.destroy();Data shape
Unlike the other charts, a Sankey takes two arrays: nodes (each with a unique id, an optional label and color) and links (source → target by id, with a value).
const props = {
linkColorMode: "source", // colour links by their source (or "target")
nodes: [
{ id: "France" }, { id: "Germany" },
{ id: "EU" }, { id: "Asia" },
],
links: [
{ source: "France", target: "EU", value: 40 },
{ source: "France", target: "Asia", value: 22 },
{ source: "Germany", target: "EU", value: 55 },
{ source: "Germany", target: "Asia", value: 35 },
],
};A link to an unknown node id (or a node in disabledItems) is dropped with a datawarning; disabling a node drops its links too.
Layout knobs
nodeWidth sets the node rect width, nodePadding the vertical gap between nodes in a column, and linkOpacity how translucent the bands are. linkColorMode colours each band by its source (default) or target node. The a11y mirror and getContext() expose the links as a readable "Source → Target: value" table.
Rounded nodes. nodeRadius (px, default 2) rounds the node rect corners - bump it up for the pill look, or set 0 for square corners. It's clamped to half the node's shorter side, so it never deforms a thin node.
Rounded flows. The flows are drawn as filled ribbons; linkRadius (px, default 2) rounds their corners where they meet the nodes, for a softer connection (clamped to half the band's thickness; 0 = sharp). linkColorMode colours each flow by its source or target node, at linkOpacity:
const props = { nodeRadius: 4, linkRadius: 4, /* …nodes, links */ };API
Props are typed as SankeyChartProps in @michi-vz/core. Shared across all charts: width, height, margin, colors / colorsMapping, renderer ("svg" | "canvas"), highlightItems, disabledItems, and the on* callbacks. onChartDataProcessed / getContext() return the renderer-agnostic ChartContext. Full reference: Sankey API.