For AI agents: the complete XY documentation index is at llms.txt. Markdown versions are available by appending .md or sending Accept: text/markdown.
Chart Gallery

/

Sankey Diagram in Python

Sankey Diagrams in Python

A Sankey diagram shows how a quantity flows through a sequence of stages. Node height represents total flow, and each connecting ribbon is proportional to its value. Use one for budgets, energy transfer, conversion funnels, supply chains, or any directed flow where the size of each path matters.

With xy, pass (source, target, value) triples to sankey_chart. XY assigns layers, minimizes crossings, sizes the nodes, stacks the ribbon endpoints, and uses each link's source and target colors to paint its gradient.

Jump to the basic chart, a dense energy network, sink alignment, or custom ribbon styling.

Create a Sankey Diagram

This example follows an investment inflow through allocations and outcomes:

Node names default to their first-appearance order in links. When you need stable ordering independent of the input rows, pass every name through nodes=:

The colors sequence follows that same node order and must contain exactly one CSS color per node.

Trace a Dense Energy Network

Sankey diagrams are most useful when several branches split and rejoin. This energy balance uses four stages, a compact node_padding, and extra crossing-minimization iterations. Every ribbon blends from its source node color to its target node color:

Use an explicit nodes list when color meaning must remain stable even if the input rows are reordered. More iterations can improve a busy layout, though the crossing-minimization algorithm is heuristic rather than guaranteed to find the mathematical optimum.

Compare Sink Alignment

A sink is a node with no outgoing link. With align="left", an early sink stays in the first layer where the graph places it. The default align="justify" moves every sink to the final layer, producing a flush right edge. Compare the position of Direct purchase:

For a single-column mobile layout, place the two chart components in an rx.vstack or make the grid's columns prop responsive in your Reflex app.

Style the Ribbon Layer

Use the xy.sankey mark directly when you want mark-level styling. The style mapping below adds a subtle purple outline, while high-opacity links preserve the intended lavender-to-violet gradient without competing with the solid node bars. Composing the mark yourself also means supplying the hidden unit-box axes that sankey_chart normally adds for you:

The mark's style mapping applies to links, while colors controls nodes and the two ends of each link gradient. Here, pale lavender sources transition through a saturated purple process hub to deep-violet outcomes, reinforcing the left-to-right flow. Wider, fully opaque node bars sit above slightly dimmed ribbons, so every stage remains distinct instead of blending into its attached flows. Sankey names use the chart's annotation_label style slot; a light color and dark shadow keep labels readable across changing ribbon colors. Set labels=False for a compact, label-free diagram, or increase label_size when the chart has room for larger text.

Layout and Flow Rules

Sankey links form a directed acyclic graph: every path moves from an earlier stage to a later stage. XY rejects cycles and names the nodes involved instead of drawing a misleading backward flow.

Each (source, target) pair must appear once. Aggregate repeated pairs before passing them to the chart, and use finite, non-negative values. Node height is the larger of total inflow and total outflow, so a node remains large enough for every ribbon attached to it.

align="justify" places terminal nodes on the final layer. The other supported alignments are "left", "right", and "center": left keeps each node in the earliest layer its links allow, right hangs each node by its distance to a sink, and center moves nodes without incoming links next to their first target. Alternating barycenter sweeps reduce crossings; increase iterations for a denser graph when the extra layout work improves the result.

Sankey Options

OptionPurpose
links(source, target, value) triples describing each flow.
nodesExplicit node order; defaults to first appearance in links.
colorsOne CSS color per node, following node order.
node_widthNode width as a fraction of the diagram, between 0 and 1.
node_paddingVertical gap between nodes in a layer, between 0 and 1.
alignNode alignment: "justify", "left", "right", or "center".
iterationsNumber of crossing-minimization sweeps.
link_opacityRibbon opacity in the interval (0, 1].
labelsWhether node names are drawn beside their nodes.
label_sizeNode-label font size in pixels.

Chart options such as width, height, title, and theme settings are passed to sankey_chart alongside the Sankey options.

Interaction and Export

The browser resolves ribbon hover by testing the pointer against the same curved band geometry used for rendering. Link tooltips show source → target with the flow value; node tooltips show the node name and its total flow. Sankey diagrams also export through the standard chart methods:

GPU picking, ribbon hover highlighting, automatic legend swatches for two-color ribbons, cycle breaking, and Sankey-specific level of detail are not implemented yet.

  • Bar and column charts compare independent category totals without encoding a flow between them.
  • Segments draw independent point-to-point connections when band width does not carry a value.
  • Annotations add explanatory labels, callouts, and thresholds around a flow diagram.

API Reference

xy.sankey_chart

A Sankey diagram chart: flow layout, gradient ribbons, hidden axes.

Props

PropTypeDescription
linksAny

Defaults to None.

*childrenComponent

Marks, axes, annotations, and chart chrome.

titleOptional[str]

Title shown above the plot.

widthint | str

Chart width in pixels or a CSS size such as ``"100%"``.

heightint | str

Chart height in pixels or a CSS size such as ``"100%"``.

paddingUnion[float, Sequence[float], None]

Plot margins, as one value or a sequence of side values. Use zero for an edge-to-edge sparkline.

dataTableLike

Chart-level data used by marks that omit their own ``data``.

class_nameOptional[str]

CSS class applied to the chart container.

class_namesOptional[dict[str, str]]

CSS classes keyed by stable chart DOM slot.

styleOptional[dict[str, StyleValue]]

Inline style overrides for the chart container.

stylesOptional[dict[str, dict[str, StyleValue]]]

Inline style mappings keyed by stable chart DOM slot.

on_hoverOptional[Callable[[dict], None]]

Callback receiving hover event payloads.

on_clickOptional[Callable[[dict], None]]

Callback receiving picked-mark click payloads.

on_brushOptional[Callable[[dict], None]]

Callback receiving brush event payloads.

on_selectOptional[Callable[[Selection], None]]

Callback receiving data-space selections.

on_view_changeOptional[Callable[[dict], None]]

Callback receiving viewport change payloads.

hoverOptional[bool]

Whether pointer movement emits hover events.

clickOptional[bool]

Whether picked marks emit click events.

selectOptional[bool]

Whether shift-drag box selection is enabled.

brushOptional[bool]

Whether brush selection is enabled.

crosshairOptional[bool]

Whether plot-aligned hover guides are shown.

navigationOptional[bool]

Whether browser pan and zoom navigation is enabled.

panOptional[bool]

Whether plain-drag panning is enabled.

pan_axesOptional[tuple[str, ...]]

Declared axis IDs translated by pan gestures.

zoomOptional[bool]

Whether viewport zoom is enabled.

default_drag_actionOptional[DefaultDragAction]

Initial action performed by a plain plot drag.

zoom_axesOptional[tuple[str, ...]]

Declared axis IDs changed by zoom gestures and controls.

zoom_limitsOptional[ZoomLimits]

Minimum and maximum magnification globally or by axis.

wheel_zoomOptional[bool]

Whether wheel and trackpad zoom is available.

box_zoomOptional[bool]

Whether box zoom is available as a drag action.

zoom_buttonsOptional[bool]

Whether modebar Zoom In/Out commands are available.

double_click_resetOptional[bool]

Whether double-click restores ``reset_axes``.

reset_axesOptional[tuple[str, ...]]

Declared axis IDs restored by reset.

link_groupOptional[str]

Identifier used to synchronize charts in the browser.

link_axesOptional[tuple[str, ...]]

Axes synchronized within the link group.

coordsstr

Coordinate system, ``"cartesian"`` (default) or ``"polar"``. Under ``"polar"`` each mark's first channel is the angle and its second is the radius. Prefer ``xy.polar_chart(...)``, which sets this for you.

FAQ

How do I create a Sankey diagram in Python?

Pass (source, target, value) triples to xy.sankey_chart(...). XY computes the node layers, sizes, ordering, and ribbon endpoints automatically.

Can a Sankey diagram contain cycles?

No. A Sankey flows from earlier stages to later stages. XY raises an error that names the nodes in a cycle so you can break or aggregate that loop explicitly.

How do I control Sankey colors?

Pass one CSS color per node through colors=. The source and target colors are interpolated across each ribbon to make its direction readable.

How do I move terminal nodes to the right edge?

Use the default align="justify". Choose "left", "right", or "center" when a different layer alignment better matches the story in your data.

Built with Reflex