Sankey Diagram
render_sankey_chartVisualize flows between nodes with width proportional to value. Ideal for budget flows, user journeys, and conversion funnels, showing where resources go.
Instructions
Render a sankey flow diagram - 'Where does it go?' Shows flows between nodes with width proportional to value. Great for budget flows, user journeys, energy transfers, conversion funnels with multiple paths.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| title | Yes | Chart title | |
| data | Yes | Array of flows between nodes | |
| options | No | ||
| theme | No | Theme preset: boardroom, corporate, sales-floor, golden-treasury, clinical, startup, ops-control, tokyo-midnight, zen-garden, consultant, black-tron, black-elegance, black-matrix, forest-amber, forest-earth, sky-light, sky-ocean, sky-twilight, gray-hf, gray-copilot | |
| palette | No | Override palette only (mix-and-match) | |
| typography | No | Override typography: professional, luxury, cyberpunk, editorial, mono, bold, system, techno | |
| effects | No | Override effects: none, subtle, shimmer, neon, energetic |
Implementation Reference
- src/charts/sankey.ts:32-118 (handler)The main handler function that renders a Sankey chart. It takes a container HTMLElement and a SankeyData payload, creates a Chart.js sankey chart with color mapping, tooltips, click handling, export/refresh buttons, and theme support.
export function renderSankeyChart(container: HTMLElement, payload: SankeyData): void { const { title, data, options } = payload; const colorMode = options.colorMode ?? "gradient"; const theme = resolveTheme(payload.theme, { palette: payload.palette, typography: payload.typography, effects: payload.effects, }); if (theme) applyTheme(container, theme); // Build color map for all unique nodes const nodes = [...new Set(data.flatMap(d => [d.from, d.to]))]; const palette = resolveColors(options.colors, nodes.length); const colorMap = new Map<string, string>(); nodes.forEach((n, i) => colorMap.set(n, palette[i % palette.length])); container.innerHTML = ` <div class="chart-view"> <div class="card chart-card"> <div class="chart-card__header"> <div> <div class="chart-card__title${theme?.effects.shimmerTitle ? " shimmer-text" : ""}">${escapeHtml(title)}</div> <div class="chart-card__subtitle">${data.length} flows - ${nodes.length} nodes</div> </div> </div> <div class="chart-card__body"> <canvas id="chart-canvas"></canvas> </div> </div> </div> `; const canvas = container.querySelector<HTMLCanvasElement>("#chart-canvas")!; const chartInstance = new Chart(canvas, { type: "sankey" as any, data: { datasets: [{ data, colorFrom: (ctx: any) => { const flow = ctx.dataset.data[ctx.dataIndex]; return flow ? (colorMap.get(flow.from) ?? palette[0]) : palette[0]; }, colorTo: (ctx: any) => { const flow = ctx.dataset.data[ctx.dataIndex]; return flow ? (colorMap.get(flow.to) ?? palette[1]) : palette[1]; }, colorMode, borderWidth: 0, nodeWidth: 12, color: getCSSVar("--text-primary"), font: { size: 11 }, }] as any, }, options: { responsive: true, maintainAspectRatio: false, onClick: (_event, elements) => { if (elements.length === 0) return; const el = elements[0] as any; const idx = el.index; const flow = data[idx]; if (flow) { sendClickMessage(`${flow.from} → ${flow.to}: ${flow.flow.toLocaleString()} in "${title}"`); } }, plugins: { legend: { display: false }, tooltip: { ...tooltipStyle(), callbacks: { label: (ctx: any) => { const flow = ctx.dataset.data[ctx.dataIndex]; if (!flow) return ""; return `${flow.from} → ${flow.to}: ${flow.flow.toLocaleString()}`; }, }, }, }, }, }); deferResize(chartInstance); addExportButton(container, chartInstance, title); addRefreshButton(container, () => (window as any).__mcpRefresh?.()); } - src/charts/sankey.ts:12-30 (schema)Type definitions for SankeyData and SankeyFlow interfaces, specifying the input schema: title, data (array of from/to/flow), options (colorMode, colors), and theme/palette/typography/effects properties.
interface SankeyFlow { from: string; to: string; flow: number; } interface SankeyData { type: "sankey"; title: string; data: SankeyFlow[]; options: { colorMode?: "gradient" | "from" | "to"; colors?: string[]; }; theme?: string; palette?: string; typography?: string; effects?: string; } - src/charts/sankey.ts:120-120 (registration)Registration call that maps the chart type 'sankey' to the tool name 'render_sankey_chart' and the renderSankeyChart handler function.
registerChart("sankey", "render_sankey_chart", renderSankeyChart); - src/charts/shared.ts:188-194 (helper)The registerChart utility function that stores chart entries in a CHART_REGISTRY record, mapping a chart type to its tool name and render function.
export function registerChart( type: string, toolName: string, render: (root: HTMLElement, data: any) => void, ): void { CHART_REGISTRY[type] = { toolName, render }; }