Sankey Diagram
Where an amount flows, stage by stage, with bands as wide as the amount.
Pattern · Shares patterns with Composition Chart, Funnel
≈ 1,098 tokens per use (tool 556 · guidance 300 · typical payload 242)How token costs are estimated
Example: Sankey Diagram
Where did my October income go? I mostly want to see food.
Where October's income went
All accounts, 1–31 Oct
- Income
- $6,000
- Stages
- 4
| From | To | Income | Share of from |
|---|---|---|---|
| Salary | Income | $5,200 | 100% |
| Freelance | Income | $800 | 100% |
| Income | Housing | $2,100 | 35% |
| Income | Savings | $1,500 | 25% |
| Income | Food | $950 | 16% |
| Income | Other spending | $550 | 9% |
| Income | Fun | $520 | 9% |
| Income | Transport | $380 | 6% |
| Food | Groceries | $610 | 64% |
| Food | Eating out | $340 | 36% |
| Fun | Travel | $300 | 58% |
| Fun | Concerts | $220 | 42% |
Housing and savings took 60% of income; food came next at $950, with $340 on eating out.
When to use
- The question is where an amount goes, or comes from, across two or more stages: income to spending categories to items, a budget to departments to teams, traffic sources to pages to sign-ups, energy from fuels to uses.
When not to use
- A whole splits once (spend by category). Use a Composition Chart.
- People drop out of one sequence of steps. Use a Funnel.
- Amounts loop back (A to B and back to A). Use a Data Table.
- You don't have the amounts from a tool. Never invent them.
How the agent should use it
- One row per flow with a source, a target and an amount in one unit. Flows into a node should add up to what flows out of it; a node is as tall as the larger of the two.
- Give every node a short, unique name (1–3 words). The same name in two stages is one node, so write "Other cloud" and "Other marketing", not "Other" twice.
- Keep it readable: at most 5 stages and about 20 nodes. Fold small flows into an "Other …" node first.
- Set
highlightto the node the user asked about: everything flowing into and out of it stays lit. - In
summary, name the biggest flow and anything surprising.
Design
- Stages come from the flows. A node's stage is the longest path to it from a starting node; nodes with nothing flowing out line up in the last stage. Flows that would loop back are left out, and a line under the diagram says how many.
- Fewer crossings. Within a stage, nodes are ordered by where their flows come from and go to (a few passes each way), and bands leave and enter each node in the order of the node at the other end.
- One colour. Nodes and bands use one strong colour (the chart ramp's deep end in light mode, its pale end in dark, or the site's tone); bands are translucent so overlaps stay readable. Text never takes the colour.
- Labels sit left of the first stage and right of every other node: the name, then the amount in compact form. Room is reserved for the outer labels, so they never cover a band.
- Hover a band for its amount and share of its source (other bands fade), or a node for what flows in and out (its whole path stays lit).
Accessibility
The SVG is hidden from screen readers. A visually hidden table lists every flow with its source, target, amount and share of the source. Amounts are formatted with Intl, so they follow the user's locale.
Installation
npx shadcn@latest add https://your-site.com/r/sankey-diagram.json
Usage
The Sankey Diagram is display-only, so the tool can return immediately:
import { tool } from "ai"
import { sankeyDiagramTool } from "@/components/genui/sankey-diagram.schema"
const tools = {
[sankeyDiagramTool.name]: tool({
description: sankeyDiagramTool.description,
inputSchema: sankeyDiagramTool.inputSchema,
execute: async () => ({ shown: true }),
}),
}Render it through the Renderer under show_sankey, or directly:
<SankeyDiagram {...part.input} status={part.state === "input-streaming" ? "streaming" : "ready"} />Flows render as they stream in; the layout settles once the last one arrives.
Schema
| Prop | Type | Notes |
|---|---|---|
title | string | What flows where, e.g. "Where October's income went" |
description | string? | Scope or source |
source | string | Field naming where each flow starts |
target | string | Field naming where each flow ends |
value | { key, label, format?, currency?, unit? } | The amounts. format: number, currency or percent |
highlight | string? | A node to trace, by name |
data | Record<string, string | number>[] | Data-bound. 2–60 rows, one per flow |
summary | string? | One-sentence takeaway, shown under the diagram |
Host props: status (streaming or ready) and className.