Chart guide Tableau and SQL

How do I build a waterfall chart?

Put the steps in order on Columns, the running total RUNNING_SUM(SUM([Amount])) on Rows, set the mark to Gantt Bar and put -SUM([Amount]) on Size, so each bar hangs from where the last one ended. Here it bridges a year of ARR from $1.2M to $1.3M.

Updated

The data

Northwind Analytics ARR movements, 2025

Synthetic dataarr_movements.csv

A B2B software company starting 2025 at 1.2M annual recurring revenue, with monthly new, expansion, contraction and churn movements.

monthstep_ordermovementarr_change
2025-01-011Starting ARR1200000
2025-01-012New customers23589.38
2025-01-013Expansion7955.44
2025-01-014Contraction-2721.48

Step 1

One bar per movement

Each movement's total for the year. Plain bars all start at zero, so you can't see how they add up.

Tableau

SUM([arr_change])

The xmetric engine ran this formula and got the SQL’s ARR change column, row for row.

SQL

SELECT step_order, movement, SUM(arr_change) AS delta
FROM input
GROUP BY step_order, movement
ORDER BY step_order

Rows

Step orderMovementARR change
1Starting ARR$1,200,000
2New customers$221,746
3Expansion$109,311
4Contraction−$38,007
5Churn−$143,912

Step 2

Lift each bar onto the running total

The running total marks where each step ends. That's the top of a gain and the bottom of a loss.

Tableau

RUNNING_SUM(SUM([arr_change]))

SQL

WITH s AS (
  SELECT step_order, movement, SUM(arr_change) AS delta
  FROM input
  GROUP BY step_order, movement
)
SELECT
  step_order,
  movement,
  delta,
  SUM(delta) OVER (ORDER BY step_order ROWS UNBOUNDED PRECEDING) AS end_y
FROM s
ORDER BY step_order

Rows

Step orderMovementARR changeEnd y
1Starting ARR1,200,000$1,200,000
2New customers221,746$1,421,746
3Expansion109,311$1,531,057
4Contraction−38,007$1,493,050
5Churn−143,912$1,349,139

Step 3

Hang a Gantt bar back to the start

A negative size draws the bar backwards from the running total to where the step began. Gains step up, losses step down, and the end bar lands on the year's closing ARR.

Tableau

-SUM([arr_change])
// on Size, mark type Gantt Bar

SQL

WITH s AS (
  SELECT step_order, movement, SUM(arr_change) AS delta
  FROM input
  GROUP BY step_order, movement
)
SELECT
  step_order,
  movement,
  delta,
  COALESCE(SUM(delta) OVER (ORDER BY step_order ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING), 0) AS start_y,
  SUM(delta) OVER (ORDER BY step_order ROWS UNBOUNDED PRECEDING) AS end_y
FROM s
ORDER BY step_order

Rows

Step orderMovementARR changeStart yEnd y
1Starting ARR$1,200,000$0$1,200,000
2New customers$221,746$1,200,000$1,421,746
3Expansion$109,311$1,421,746$1,531,057
4Contraction−$38,007$1,531,057$1,493,050
5Churn−$143,912$1,493,050$1,349,139

What the bridge shows that a line chart hides

ARR grew 12.4% in 2025, which looks healthy. The bridge tells the real story: new customers added the growth, while existing customers shrank. Expansion didn't cover contraction and churn, so net revenue retention was 93.9%. Without new sales, this company would be getting smaller.

In Tableau

The shelves for the finished chart

Marks Gantt Bar

  • Size-SUM([arr_change])
  • ColorSUM([arr_change]) > 0
  • LabelSUM([arr_change])
Columnsmovement (sorted by step_order)
RowsRUNNING_SUM(SUM([arr_change]))

Green pills are continuous, blue are discrete, as in Tableau.

Variants

Other ways to draw it

Horizontal

Point at a bar to read it.
$0$500K$1M$1.5M$1.2MStarting ARR+$221.7KNew customers+$109.3KExpansion−$38KContraction−$143.9KChurn$1.3MEnd
GainLossTotal

By month

Put month on Columns instead of movement to bridge month by month. The axis starts near the smallest month so the monthly steps stay visible; the January bar, which carries the starting ARR, is cut at the axis.

Point at a bar to read it.
$1.15M$1.2M$1.25M$1.3MJanFebMarAprMayJunJulAugSepOctNovDec$1.3MEnd
GainLossTotal

Common mistake

Labels show the running total instead of the step

Readers expect each floating bar to say what that step added or took away. Put SUM([arr_change]) on Label, not the running total; only the end bar shows the total.

Wrong

Tableau

Label: RUNNING_SUM(SUM([arr_change]))
Right

Tableau

Label: SUM([arr_change])

Common mistake

Sorting the steps by size

Sort by value and the bridge stops being a sequence: the bars no longer connect start to end in the order the money moved. Keep the logical order with a step_order field.

WrongStarts with Starting ARR, New customers, Expansion…
Point at a bar to read it.
0500K1000K1500KStarting ARRNew customersExpansionContractionChurn

SQL

WITH s AS (
  SELECT step_order, movement, SUM(arr_change) AS delta
  FROM input
  GROUP BY step_order, movement
)
SELECT
  movement,
  delta,
  SUM(delta) OVER (ORDER BY delta DESC ROWS UNBOUNDED PRECEDING) AS running_arr
FROM s
ORDER BY delta DESC
RightStarts with Starting ARR, New customers, Expansion…
Point at a bar to read it.
0500K1000K1500KStarting ARRNew customersExpansionContractionChurn

SQL

WITH s AS (
  SELECT step_order, movement, SUM(arr_change) AS delta
  FROM input
  GROUP BY step_order, movement
)
SELECT
  movement,
  delta,
  SUM(delta) OVER (ORDER BY step_order ROWS UNBOUNDED PRECEDING) AS running_arr
FROM s
ORDER BY step_order

Run it on your own data

Any table with a step (a P&L line, a movement type or a month) and an amount works. Drop your CSV, pick the step, its order and the amount, and the bridge builds itself in your browser. Nothing is uploaded.

Drop a CSV anywhere on this page

Up to 10,000 rows. The sample, arr_movements.csv, shows the shape.

Questions

Why does the Size field have a minus sign?

The running total puts each mark at the end of its step. A Gantt bar of size -SUM([Amount]) then draws back to where the step started: down for a gain, up for a loss. That's what makes each bar hang off the previous one.

How do I add the final total bar?

In Tableau, turn on Analysis > Totals > Show Row Grand Totals; the grand total column shows the ending running total. In SQL, add a row for the end value with a start of zero.

Can I sort the steps by size?

Not for a bridge: the order is the story (start, gains, losses, end). Sort by size only when the chart compares contributions, not a sequence.

Sources