Bridge charts
The most valuable chart in finance and the most consistently under-used. A bridge answers how we got from A to B — the one question a table of two numbers cannot.
Build it with chartkit.waterfallLayout (see svg-charting), which computes the geometry and, more
importantly, checks that the bridge foots.
The rule that comes before any styling
The bars must sum exactly to the closing anchor.
If they do not, the decomposition is wrong. Fix the analysis. Never add a plug, never quietly widen "other", never adjust the closing anchor to match. A bridge that foots because of a plug is a chart that asserts a false explanation.
const {bars, domain, footing} = chartkit.waterfallLayout(items);
if (footing && !footing.ok) {
throw new Error(`Bridge does not foot by ${footing.variance} — fix the analysis`);
}
Fail loudly. A silent plug is the single worst failure mode in financial charting because it is invisible in the output.
Anatomy
| Bar type | Sits | Encodes |
|---|---|---|
| Anchor | On the baseline | An absolute state — opening, closing |
| Delta | Floating, from the running total | A change |
| Subtotal | On the baseline | The running total at a stage |
┌───┐ ┌───┐
│ │ ┌──┐ │ │
┌───┐ │ │ │ │ ┌──┐ │ │
│ │──┘ └──┘ └──┘ └──┐ ┌──┐ │ │
│ │ └───┘ └───────────│ │
│ │ │ │
└───┘ └───┘
Opening New Expan Contr Churn Closing
Anchors in a neutral colour. Deltas coloured by direction. The connector lines are not optional — without them the eye cannot follow the cumulative path, and the chart degrades into floating bars.
The four bridges worth knowing
ARR bridge
Opening ARR → New → Expansion → Contraction → Churn → Closing ARR
The definitive SaaS growth visual. Rules: a customer appears in exactly one bucket per period; downgrade-to-zero is churn, not contraction; group New and Expansion visually to make gross-add versus gross-loss readable at a glance.
EBITDA / margin bridge
Prior EBITDA → Volume → Price → Mix → COGS → Personnel → Other opex → Current EBITDA
Order matters here: put the operational drivers first and the one-offs last, so the reader sees the underlying movement before the noise. Add a note reconciling to a clean run rate — that is what gets used for forecasting.
Cash bridge
Opening cash → Collections → Payroll → Vendors → Capex → Financing → Closing cash
Outflows always negative. A cash chart with positive outflows will be misread by someone in a board meeting. Consider a subtotal after operating items to separate operating from financing.
Budget-to-actual bridge
Budget → Volume variance → Price variance → Mix → Timing → Actual
Reconciles the gap in driver terms rather than line-item terms. Far more useful than a variance table when someone asks "why did we miss".
Multi-level and stacked bridges
Stacked deltas — when a single bar decomposes further (Expansion = upsell + cross-sell + price): stack within the bar, keep the stack order consistent across bars, and only do this when the sub-components are genuinely comparable. Beyond two or three sub-parts it becomes unreadable.
Subtotal bridges — for long walks, insert subtotals to create readable stages:
Opening → [operating deltas] → Subtotal: operating → [financing deltas] → Closing
Nested bridges — a summary bridge with a second bridge decomposing one bar. Excellent for
drill-down (app-interaction-patterns); the child bridge must foot to the parent bar exactly, and it
should say so.
Encoding
Sign. Two colours plus position. Increases and decreases must differ in lightness as well as hue, or the chart dies in greyscale. Never red/green alone.
Direction is not goodness. A rise in churn is an increase and bad. Decide whether the chart encodes direction or goodness, then say which in the legend. Encoding both in one colour scale guarantees a misread.
Anchors are neutral — grey or a muted tone. They are states, not changes, and colouring them like deltas implies movement.
Order is chronological or logical, never sorted by size. A bridge sorted by magnitude is no longer a walk.
Labels
Every bar carries its value. A bridge the reader has to estimate from axis position has failed.
- Value inside the bar when it fits, above/below when it does not
- Signed deltas (
+180K,−38K) — the sign is information - Anchors labelled with the absolute, deltas with the change; never mix the two conventions
- Use
chartkit.avoidOverlapfor dense bridges — it preserves order while separating labels - Add the percentage of the opening for context where it helps:
+180K (+3.9%)
Category labels below the axis, rotated only as a last resort — rotated labels are a sign the chart is too narrow or has too many bars.
How many bars
Five to nine is the sweet spot. Beyond about twelve it stops being readable.
Too many? Group the small ones into "Other" — but "Other" must be smaller than the smallest named bar. If it is not, you have hidden the story in a residual, which is a named anti-pattern. Break out the next largest until that holds.
Scale
- Zero baseline, unless every bar sits far from zero and the deltas would be invisible — in which case truncate deliberately, mark the axis break, and say so.
- Domain must include zero when any bar crosses it.
- For a bridge where deltas are tiny relative to the anchors, consider charting only the deltas with the anchors as text. The alternative is five bars of identical apparent height.
Checklist
-
footing.okis true — checked in code, not by eye - Connector lines present
- Every bar labelled with a signed value
- Anchors visually distinct from deltas
- Sign survives greyscale
- "Other" smaller than the smallest named bar
- Order is chronological or logical
- Title states the finding, not "ARR Bridge" (
chart-annotation) - As-of and period status present
Related skills
svg-charting—waterfallLayoutand the footing checkchart-selection— when a bridge is the right formchart-annotation— the takeaway titlevariance-charts— the budget-to-actual siblingfinancial-tables— the table that accompanies a bridge