SankeyDiagram andProcessSankey both display flow. They both use very similar methods to do so. But where they differ is in how we understand time as part of a system. Systems and flows are usually represented outside of time, only showing the topology, or they show elements of the system over time without encoding the topology of the system. But now there's a diagram that can do that: The Process Sankey.
Why two flow layouts?
The classic Sankey layout, born in the 19th century to visualize steam-engine energy budgets, treats flows between nodes as instantaneous and the layout as a sequence of vertical columns. That's why it is a surprisingly popular and familiar chart for bothflows but also forpart-to-whole questions where it is used almost like a hierarchical diagram.
In contrast, the new Process Sankey uses the same ribbon geometry but pins the x-axis to actual time. When you do this, four problems disappear at once:
- Cycles work. Fresno to Los Angeles in January and Los Angeles to Fresno in March are two forward-moving flows on the timeline, not a DAG-breaking loop. Circular sankeys are common since Tom Shanley built d3-sankey-circular in 2017 but most people still use the classic d3-sankey approach that errors out when it detects cycles.
- Edges carry duration. A snowpack melt that flows over several months, the shipment that takes three weeks to cross the pacific or any other flow from one part of the system to another is not instantaneous. That's not always important. But until now, it didn't matter if it was.
- Parallel discrete events. The same source-target pair can fire ten times across a year; the classic Sankey aggregates them into one ribbon, the Process Sankey shows ten distinct ribbons at their actual moments.
- Nodes have lifetimes. Even if the flows are simultaneous (or practically so, in the case of a transfer from the ER to the ICU), the nodes themselves encode time spent in the stores and sinks that make up a flow diagram. Lakes dry up, patients get discharged, and even if a node is always there, it is not always the same magnitude. Process Sankey encodes the presence or absence of a node as a function of time but also its changing size and shape.
Where classic sankeys work
Ten water reservoirs (Ocean, Atmosphere, Clouds, Land Rain, Snowpack, Glaciers, Soil Moisture, Vegetation, Surface Water, Groundwater) and 16 flows. Volumes are in thousand km³/yr and it's a complex system but it is clear and legible and, like any sankey: compelling to the reader.
SankeyDiagram — system-readable, time-blind
The classic Sankey layout treats reservoirs as ranked columns. Return-to-Ocean edges become curved back to represent the cycle in its column ordering. The diagram answers 'what fraction of total flow moves between these nodes annually?'
What it shows well: relative magnitudes such as ocean to atmosphere exchange dominates because that's where most of the global flux is.
You can see in the diagram that the Ocean to Atmosphere ribbon dominates because itis the dominant flux. The eye walks from left to right and gets the system's mass-balance at a glance: ~85% of all evaporation comes from the ocean; clouds split their precipitation roughly 80/20 between ocean and land; only a fraction of land precipitation makes it back to the ocean as river flow. Volume and dependency get encoded in a legible manner.
Timing, though, is invisible. The Surface Water to Ocean and Groundwater to Ocean return edges show up as curved back links rather than as a closed loop. Whether the snowmelt pulse happens in spring or in October is information the chart literally cannot carry. That's not important for understanding the system's mass balance, but it is a real loss of information about the system's behavior over time.
Patient journeys
We can contrast that to a different dataset: twelve patients move through five wards (ER, Surgery, ICU, General, Discharge) over seven days. Each row in the dataset encodes time into the transition between wards.
SankeyDiagram — aggregated ward flow
Classical sankey diagrams collapse every patient's transitions into the underlying source to target counts. You see the funnel clearly: most patients hit ICU before General, and ribbon thickness is the total patient count along each route. The same 12 patients could have arrived uniformly across the week or in a single 4-hour burst; this chart looks identical either way.
ProcessSankey — per-patient timeline
Same data on a time axis with a process sankey. The vertical wall around Day 2 is the surge as six trauma patients hit ER, Surgery, then ICU inside a 4-hour window. The pre- and post-surge admit rates are visibly thinner. Independent cycles (P2 ICU readmission on Day 2.2; P8 surgical re-op on Day 2.4; P11 cardiac re-event on Day 5.0) unroll as forward-moving events in time.
What the classic Sankey shows here
The diagram aggregates all patient-transition events into ribbons keyed by source-target pair. You get a clean utilization readout: most patients hit ICU before General, the General ward is the most common discharge launchpad. It's useful for monthly utilization review to allocate resources and answer operational concerns from that perspective.
But the surge is invisible. Every operationally meaningful question about that is hidden in this aggregation:
- Was there a mass-casualty event?
- When did the ICU run hot?
- How saturated were the operating rooms, and for how long?
- How many surge-cohort patients are still admitted on Monday morning?
That's all gone. The Sankey answers "where does the mass go." For this dataset, the mass is identical-patients. We won't be able to ask any questions that require us to knowwhen they showed up, which the aggregation throws away.
What the Process Sankey shows here
The temporal layout makes the surge unmissable: a vertical wall of ER to Surgery and ER to ICU ribbons around a couple hours on Day 2, with the cascade visible as Surgery to ICU edges trailing Day 2 and ICU to General edges trailing into Day 3. Pre-surge and post-surge admits are visibly sparser on the timeline. An operations dashboard reader sees the wave shape immediately and without having to compute anything.
Independent of the surge, the cycles stand out in time too: One patient ICU readmission at Day 2.2 (caught mid-surge, which would have been a real-world bed crisis), Another patient's post-op re-op at Day 2.4, and a third patient's cardiac re-event in the General ward at Day 5.0 are all cycles back into earlier parts of the system but discrete events in time.
Capacity-planning context that only the temporal view surfaces: three patients from the surge cohort never reach the Discharge node by the week's end. Their flow stops at whichever ward they were last transferred to (two still in General, one still in ICU). Anyone making Monday admit decisions needs to know which beds are carrying held-over patients.
Anscombe's Sankey
That's one temporal pattern (the mass-casualty surge) that the aggregate Sankey couldn't surface. But the failure mode is worse than that: the aggregate can't distinguish between any number of completely different temporal realities, because timestamps aren't in the summary at all.
Below are four scenarios. Each one runs the same twelve patients through thesame five wards via the same ward sequences (same cycles, same routes). But they have different times they were admitted and stayed at each step.
This is the flow analogue ofAnscombe's quartet. Anscombe used four datasets with the same summary statistics and visibly different underlying shapes to argue you always look at your data; this says the same thing but for flows.
Notice the Emergency Room (ER) node in each of the four ProcessSankeys which, instead of simply being a single flat "always there" band is an outline showing the time when actions affect the node with gradient stubs indicating when people enter the system. The cumulative effect is a staircase whose riser shape is the admit schedule. The pattern is diagnostic on its own showing a vertical wall in the surge week, even risers under normal ops, or a flat start with a Wednesday cliff in the outbreak. In this example each patient's first edge carries a systemInDay field equal to admit time (the column name is consumer-chosen); the chart wires it in viasystemInTimeAccessor="systemInDay". The underlying layout / mass balance is unchanged because the gradients are pure rendering to indicate how we encode flows that come in and out of a system.
One aggregate Sankey — true for all four scenarios below
Same 12 patients, same routes, same ribbon thicknesses. The aggregate cannot tell these four weeks apart.
Four ProcessSankeys — the four weeks the aggregate just hid
Identical aggregate above, but the temporal layout reveals four operationally distinct realities.
Mass-casualty surge
Saturday-evening bus accident; six trauma cases inside a 4-hour window.
The vertical wall around Day 2 is the surge. ICU and Surgery saturate; three surge patients still admitted at week's end.
Normal operations
Routine week — admits drift in roughly every 14 hours.
Even spread, low concurrent census, system never breaks a sweat. Nothing's wrong; nothing's interesting either.
Delayed outbreak
Quiet first half, then ten admits cluster Days 3.7–5 as the bug peaks.
Empty timeline through Wednesday, then the right half of the chart fills as the cohort piles in. End-of-week census stays elevated.
Shift-change rhythm
Admits cluster at the morning and evening shift changes every day.
Twelve admits, six daily peaks. The periodicity is unmistakable — and only the temporal view shows it.
Each of these days tells a different story but the traditional Sankey cannot tell them apart. A dashboard built only on the summary statistic would treat them as identical situations.
When to use which
| Reach for | When the question is | When the data is |
|---|
| SankeyDiagram | Where does the bulk go? What fraction stays vs. leaks? | Already aggregated totals (km³/yr, $/quarter, users/month). No time dimension or one you're happy to flatten. |
| ProcessSankey | When did each transition happen? How long did each step take? Does this loop back? Are there parallel events? | Discrete event-stamped rows (one patient × one move, one PR × one merge, one shipment × one leg). Or a graph with cycles you want to read as forward-moving time. |
Other domains where this contrast pays off
Anywhere a system has both mass-balance and time-of-flight meaning. A few that translate cleanly:
- Pull-request lifecycle from opened → in review → revisions → merged → released, with cycle edges when a PR returns from review with comments. Edges carry "sat in queue for X days." Classic Sankey shows the merge funnel; ProcessSankey shows where the bottlenecks sit.
- Supply-chain logistics from supplier → warehouse → in-transit → store → returns. Returns cycle back to warehouse. Edges carry shipping duration. Classic shows leakage; ProcessSankey shows the slow legs.
- Financial settlement from payment → clearing → settlement, with reversal cycles. Classic shows volume by route; ProcessSankey shows where days-to-settle accumulate.
- Manufacturing rework from raw → assembly → QA → ship, with the rework loop from QA back to assembly. Classic shows yield; ProcessSankey shows how long the rework legs take in calendar time.