import { SankeyDiagram } from "semiotic"
SankeyDiagram visualizes the flow and magnitude of movement between nodes in a directed acyclic graph. Nodes are arranged in columns and connected by ribbons whose width encodes the flow value. Sankey diagrams are ideal for budget allocation, conversion funnels, energy flows, and any data that moves through stages. They also support streaming data — push edges imperatively and watch the topology grow with animated particles.
Quick Start
The simplest Sankey diagram requires just edges withsource, target, and valueproperties. Nodes are inferred automatically from the edges.
import { SankeyDiagram } from "semiotic" const frameProps = { /* --- Data --- */ edges: [ { source: "Budget", target: "Engineering", value: 400 }, { source: "Budget", target: "Marketing", value: 250 }, { source: "Engineering", target: "Salaries", value: 300 }, // ...more edges with value ] } export default () => { return <SankeyDiagram {...frameProps} /> }
Circular Links
Semiotic handles cyclic flows — edges that loop back to earlier nodes. The top 4 cycles by value render as full ribbons routed around the outside of the chart. Lower-value cycles render as fade-in/fade-out stubs at the source and target, keeping the layout clean.
Feedback Loop
import { SankeyDiagram } from "semiotic" const frameProps = { /* --- Data --- */ edges: [ { source: "API", target: "Auth", value: 30 }, { source: "API", target: "Users", value: 25 }, { source: "API", target: "Orders", value: 40 }, { source: "Auth", target: "DB", value: 25 }, { source: "Users", target: "DB", value: 20 }, { source: "Orders", target: "DB", value: 35 }, { source: "DB", target: "API", value: 15 }, // cycle ], /* --- Size --- */ width: 700, height: 350 } export default () => { return <SankeyDiagram {...frameProps} /> }
Many Cycles
With many cycles, the layout shows the top 4 by value as full ribbons and renders the rest as subtle stubs. This prevents visual clutter while still indicating all cyclic connections.
Multiple Cycles
import { SankeyDiagram } from "semiotic" const frameProps = { /* --- Data --- */ edges: // 9 forward edges + 8 cycles (see source), /* --- Size --- */ width: 700, height: 450 } export default () => { return <SankeyDiagram {...frameProps} /> }
Examples
Colored by Category
Use explicit nodes with a category field andcolorBy to color both nodes and flow ribbons by stage type. The edgeColorBy prop controls whether ribbons inherit the source or target node color.
import { SankeyDiagram } from "semiotic" const frameProps = { /* --- Data --- */ nodes: [ { id: "Budget", category: "Source" }, { id: "Engineering", category: "Department" }, { id: "Salaries", category: "Expense" }, // ...nodes with category field ], edges: edgeData, /* --- Customize --- */ colorBy: "category", edgeColorBy: "source" } export default () => { return <SankeyDiagram {...frameProps} /> }
Conversion Funnel
Sankey diagrams are a natural fit for conversion funnels, where users flow from one stage to the next and drop off along the way.
import { SankeyDiagram } from "semiotic" const frameProps = { /* --- Data --- */ edges: [ { source: "Visitors", target: "Signups", value: 1000 }, { source: "Visitors", target: "Bounced", value: 4000 }, { source: "Signups", target: "Free Trial", value: 800 }, { source: "Free Trial", target: "Paid", value: 300 }, // ...funnel stages ], /* --- Layout --- */ nodeWidth: 20, nodePaddingRatio: 0.08, /* --- Customize --- */ edgeOpacity: 0.4 } export default () => { return <SankeyDiagram {...frameProps} /> }
Node Alignment Options
The nodeAlign prop controls how nodes are distributed across columns. Use "left" to pack nodes toward the start of the flow.
import { SankeyDiagram } from "semiotic" const frameProps = { /* --- Data --- */ edges: edgeData, /* --- Layout --- */ nodeAlign: "left", nodeWidth: 12, /* --- Customize --- */ edgeOpacity: 0.35 } export default () => { return <SankeyDiagram {...frameProps} /> }
Streaming
Use SankeyDiagram with a ref to build streaming Sankey diagrams. Push edges imperatively via push/pushMany/clear and watch nodes, links, and animated particles appear. The tension model batches relayouts for smooth performance during high-frequency updates.
Interactive Push API
Click Load Budget Data to seed the Sankey with a personal budget flow. Then click Add Edge to grow the topology or Increment Random Edge to increase flow on an existing link. Particles animate along links proportional to their value.
JSX
const chartRef = useRef() // Push edges at any frequency chartRef.current.push({ source: "Salary", target: "Budget", value: 5000 }) chartRef.current.push({ source: "Budget", target: "Rent", value: 2000 }) <SankeyDiagram ref={chartRef} width={800} height={400} showParticles edgeOpacity={0.4} />
Continuous Streaming
Click Start Streaming to continuously push random edges between infrastructure nodes. The tension model automatically triggers relayouts as the topology evolves. Includes a feedback cycle (Serve → Ingest) to demonstrate circular link handling.
JSX
useEffect(() => { const id = setInterval(() => { chartRef.current.push({ source: randomNode(), target: randomNode(), value: Math.round(Math.random() * 100) }) }, 300) return () => clearInterval(id) }, [])
Push API Reference
Access these methods via a React ref on SankeyDiagram:
push(edge) — push a single edge { source, target, value }pushMany(edges) — batch push multiple edgesclear() — reset the graphgetTopology() — get current { nodes, edges }relayout() — force a full relayoutgetTension() — current accumulated tension value
Tension Model
Each push adds tension proportional to topological disruption. When tension exceeds the threshold, a full d3-sankey relayout runs with smooth ease-out animation.
- New node: +1.0 tension
- New edge: +0.5 tension
- Weight change: +0.1 tension
- Default threshold: 3.0
Props
| Prop | Type | Required | Default | Description |
|---|
edges | array | Yes | — | Array of edge objects with source, target, and value properties. |
nodes | array | — | (inferred from edges) | Array of node objects. Will be inferred from edges if not provided. |
sourceAccessor | string | function | — | "source" | Field name or function to access source node identifier. |
targetAccessor | string | function | — | "target" | Field name or function to access target node identifier. |
valueAccessor | string | function | — | "value" | Field name or function to access edge value (flow width). |
nodeIdAccessor | string | function | — | "id" | Field name or function to access node identifier. |
colorBy | string | function | — | — | Field name or function to determine node color. |
colorScheme | string | array | — | "category10" | Color scheme name or custom colors array. |
edgeColorBy | "source" | "target" | "gradient" | function | — | "source" | Edge color strategy: "source", "target", "gradient", or a custom function. |
orientation | "horizontal" | "vertical" | — | "horizontal" | Layout orientation. Horizontal flows left to right; vertical flows top to bottom. |
nodeAlign | "justify" | "left" | "right" | "center" | — | "justify" | Node alignment strategy within the Sankey layout. |
nodePaddingRatio | number | — | 0.05 | Padding between nodes as a ratio of node height. |
nodeWidth | number | — | 15 | Fixed width of each node in pixels. |
nodeLabel | string | function | — | (uses nodeIdAccessor) | Label accessor for nodes. |
showLabels | boolean | — | true | Show node labels. |
enableHover | boolean | — | true | Enable hover annotations. |
edgeOpacity | number | — | 0.5 | Opacity of the flow ribbons. |
edgeSort | function | — | — | Sort function for edges within each node. |
tooltip | object | function | — | — | Tooltip configuration or render function. |
width | number | — | 800 | Chart width in pixels. |
height | number | — | 600 | Chart height in pixels. |
margin | object | — | { top: 50, bottom: 50, left: 50, right: 50 } | Margin around the chart area. |
title | string | — | — | Chart title displayed at the top. |
frameProps | object | — | — | Additional StreamNetworkFrame props for advanced customization. |
Graduating to the Frame
When you need more control — custom node rendering, drag interactions, or complex Sankey configuration — graduate toStreamNetworkFrame directly. Every SankeyDiagram is just a configuredStreamNetworkFrame under the hood.
Chart (simple)
JSX
import { SankeyDiagram } from "semiotic" <SankeyDiagram edges={flowData} nodes={nodeData} colorBy="category" edgeColorBy="source" nodeWidth={20} showLabels={true} />
Frame (full control)
JSX
import { StreamNetworkFrame } from "semiotic" <StreamNetworkFrame chartType="sankey" nodes={nodeData} edges={flowData} nodeIDAccessor="id" sourceAccessor="source" targetAccessor="target" valueAccessor="value" nodeAlign="justify" nodePaddingRatio={0.05} nodeWidth={20} showLabels enableHover showParticles size={[800, 600]} />
- ChordDiagram — circular layout for showing bidirectional flow between entities
- ForceDirectedGraph — force-directed layout for general network visualization
- TreeDiagram — hierarchical layouts for tree-structured data
- StreamNetworkFrame — the underlying Frame with full control over every rendering detail
- Tooltips — custom tooltip content and positioning