Chart guide Tableau and SQL
How do I build a small multiples chart?
Give each category its own small panel with the same axes: sort the categories, number them with INDEX(), and use (INDEX()-1) % 4 for the panel column and INT((INDEX()-1) / 4) for the row. In this library system, loans fell 3.6%, yet 10 of 12 branches grew; only the panels show it.
The data
Maple Falls Public Library loans, Nov 2023 to Oct 2025
A city library with 12 branches. Monthly loans per branch over two years. The Central branch moved to a small temporary site for a renovation in January 2025.
month | branch | loans |
|---|---|---|
| 2023-11-01 | Brookside | 2405 |
| 2023-11-01 | Cedar Hill | 3333 |
| 2023-11-01 | Central | 19653 |
| 2023-11-01 | Eastgate | 1545 |
Step 1
One line per branch: the spaghetti chart
Twelve colors, one obvious story: Central drops in January 2025. Everything else is a tangle near the bottom.
Tableau
Columns: MONTH([month]) Rows: SUM([loans]) Color: [branch]SQL
SELECT month, branch, SUM(loans) AS loans
FROM input
GROUP BY month, branch
ORDER BY month, branchRows
| Month | Branch | Loans |
|---|---|---|
| Nov 1, 2023 | Brookside | 2,405 |
| Nov 1, 2023 | Cedar Hill | 3,333 |
| Nov 1, 2023 | Central | 19,653 |
| Nov 1, 2023 | Eastgate | 1,545 |
| Nov 1, 2023 | Fairview | 3,067 |
| Nov 1, 2023 | Hillside | 5,775 |
| Nov 1, 2023 | Lakeview | 7,200 |
| Nov 1, 2023 | Mill Creek | 4,311 |
| Nov 1, 2023 | Northgate | 8,948 |
| Nov 1, 2023 | Oak Park | 5,264 |
| Nov 1, 2023 | Southport | 3,961 |
| Nov 1, 2023 | Westbrook | 8,170 |
| Dec 1, 2023 | Brookside | 2,255 |
| Dec 1, 2023 | Cedar Hill | 3,102 |
| Dec 1, 2023 | Central | 17,412 |
| Dec 1, 2023 | Eastgate | 1,556 |
| Dec 1, 2023 | Fairview | 2,777 |
| Dec 1, 2023 | Hillside | 5,305 |
| Dec 1, 2023 | Lakeview | 6,109 |
| Dec 1, 2023 | Mill Creek | 4,192 |
| Dec 1, 2023 | Northgate | 8,364 |
| Dec 1, 2023 | Oak Park | 4,900 |
| Dec 1, 2023 | Southport | 3,826 |
| Dec 1, 2023 | Westbrook | 7,361 |
| Jan 1, 2024 | Brookside | 2,777 |
| Jan 1, 2024 | Cedar Hill | 3,892 |
| Jan 1, 2024 | Central | 21,891 |
| Jan 1, 2024 | Eastgate | 1,961 |
| Jan 1, 2024 | Fairview | 3,600 |
| Jan 1, 2024 | Hillside | 6,401 |
| Jan 1, 2024 | Lakeview | 8,109 |
| Jan 1, 2024 | Mill Creek | 5,306 |
| Jan 1, 2024 | Northgate | 10,023 |
| Jan 1, 2024 | Oak Park | 6,061 |
| Jan 1, 2024 | Southport | 4,502 |
| Jan 1, 2024 | Westbrook | 9,480 |
| Feb 1, 2024 | Brookside | 2,703 |
| Feb 1, 2024 | Cedar Hill | 3,918 |
| Feb 1, 2024 | Central | 21,622 |
| Feb 1, 2024 | Eastgate | 1,976 |
| Feb 1, 2024 | Fairview | 3,323 |
| Feb 1, 2024 | Hillside | 6,585 |
| Feb 1, 2024 | Lakeview | 7,211 |
| Feb 1, 2024 | Mill Creek | 4,829 |
| Feb 1, 2024 | Northgate | 9,885 |
| Feb 1, 2024 | Oak Park | 5,686 |
| Feb 1, 2024 | Southport | 3,933 |
| Feb 1, 2024 | Westbrook | 8,473 |
| Mar 1, 2024 | Brookside | 2,579 |
| Mar 1, 2024 | Cedar Hill | 3,989 |
First 50 of 288 rows.
Step 2
Wrap the branches into a grid
Each branch gets a panel, biggest first, all on the same axis. INDEX() numbers the branches in sort order; the remainder after dividing by the column count picks the column, the whole part picks the row. Compute Using must be branch, or the numbering runs along the months instead.
Tableau
// [Panel col]: (INDEX() - 1) % {knob.cols}
// [Panel row]: INT((INDEX() - 1) / {knob.cols})
// Both discrete. Compute Using: branch, sorted by SUM([loans]) descending
// Columns: [Panel col], MONTH([month]) Rows: [Panel row], SUM([loans]) Detail: [branch]SQL
WITH t AS (
SELECT branch, SUM(loans) AS total
FROM input
GROUP BY branch
), k AS (
SELECT
branch,
ROW_NUMBER() OVER (ORDER BY total DESC, branch) - 1 AS idx
FROM t
)
SELECT
i.month,
i.branch,
i.loans,
k.idx % 4 AS panel_col,
k.idx // {knob.cols} AS panel_row FROM input i JOIN k USING (branch) ORDER BY panel_row, panel_col, i.monthRows
| Month | Branch | Loans | Panel col | Panel row |
|---|---|---|---|---|
| Nov 1, 2023 | Central | 19,653 | 0 | 0 |
| Dec 1, 2023 | Central | 17,412 | 0 | 0 |
| Jan 1, 2024 | Central | 21,891 | 0 | 0 |
| Feb 1, 2024 | Central | 21,622 | 0 | 0 |
| Mar 1, 2024 | Central | 21,386 | 0 | 0 |
| Apr 1, 2024 | Central | 19,637 | 0 | 0 |
| May 1, 2024 | Central | 19,433 | 0 | 0 |
| Jun 1, 2024 | Central | 22,525 | 0 | 0 |
| Jul 1, 2024 | Central | 24,819 | 0 | 0 |
| Aug 1, 2024 | Central | 24,166 | 0 | 0 |
| Sep 1, 2024 | Central | 19,878 | 0 | 0 |
| Oct 1, 2024 | Central | 20,354 | 0 | 0 |
| Nov 1, 2024 | Central | 18,900 | 0 | 0 |
| Dec 1, 2024 | Central | 18,668 | 0 | 0 |
| Jan 1, 2025 | Central | 12,641 | 0 | 0 |
| Feb 1, 2025 | Central | 12,625 | 0 | 0 |
| Mar 1, 2025 | Central | 13,705 | 0 | 0 |
| Apr 1, 2025 | Central | 13,011 | 0 | 0 |
| May 1, 2025 | Central | 12,691 | 0 | 0 |
| Jun 1, 2025 | Central | 14,171 | 0 | 0 |
| Jul 1, 2025 | Central | 15,637 | 0 | 0 |
| Aug 1, 2025 | Central | 14,751 | 0 | 0 |
| Sep 1, 2025 | Central | 12,150 | 0 | 0 |
| Oct 1, 2025 | Central | 12,553 | 0 | 0 |
| Nov 1, 2023 | Northgate | 8,948 | 1 | 0 |
| Dec 1, 2023 | Northgate | 8,364 | 1 | 0 |
| Jan 1, 2024 | Northgate | 10,023 | 1 | 0 |
| Feb 1, 2024 | Northgate | 9,885 | 1 | 0 |
| Mar 1, 2024 | Northgate | 10,497 | 1 | 0 |
| Apr 1, 2024 | Northgate | 9,773 | 1 | 0 |
| May 1, 2024 | Northgate | 9,409 | 1 | 0 |
| Jun 1, 2024 | Northgate | 10,909 | 1 | 0 |
| Jul 1, 2024 | Northgate | 12,520 | 1 | 0 |
| Aug 1, 2024 | Northgate | 11,946 | 1 | 0 |
| Sep 1, 2024 | Northgate | 9,624 | 1 | 0 |
| Oct 1, 2024 | Northgate | 9,568 | 1 | 0 |
| Nov 1, 2024 | Northgate | 10,091 | 1 | 0 |
| Dec 1, 2024 | Northgate | 8,837 | 1 | 0 |
| Jan 1, 2025 | Northgate | 11,298 | 1 | 0 |
| Feb 1, 2025 | Northgate | 10,697 | 1 | 0 |
| Mar 1, 2025 | Northgate | 10,883 | 1 | 0 |
| Apr 1, 2025 | Northgate | 10,624 | 1 | 0 |
| May 1, 2025 | Northgate | 9,828 | 1 | 0 |
| Jun 1, 2025 | Northgate | 11,436 | 1 | 0 |
| Jul 1, 2025 | Northgate | 13,628 | 1 | 0 |
| Aug 1, 2025 | Northgate | 12,122 | 1 | 0 |
| Sep 1, 2025 | Northgate | 9,572 | 1 | 0 |
| Oct 1, 2025 | Northgate | 11,130 | 1 | 0 |
| Nov 1, 2023 | Westbrook | 8,170 | 2 | 0 |
| Dec 1, 2023 | Westbrook | 7,361 | 2 | 0 |
First 50 of 288 rows.
Step 3
Index each panel to its own first year
On the shared axis, the small branches are flat lines. Switch the Y axis to the index and every branch starts near 100, so you compare shape, not size. Eastgate, the smallest branch, turns out to be the fastest-growing.
Tableau
100 * SUM([loans]) / MIN({ FIXED [branch] : SUM(IF [month] < #2024-11-01# THEN [loans] END) / 12 })SQL
WITH t AS (
SELECT
branch,
SUM(loans) AS total,
AVG(loans) FILTER (WHERE month < DATE '2024-11-01') AS base
FROM input
GROUP BY branch
), k AS (
SELECT
branch,
base,
ROW_NUMBER() OVER (ORDER BY total DESC, branch) - 1 AS idx
FROM t
)
SELECT
i.month,
i.branch,
i.loans,
ROUND(100.0 * i.loans / k.base, 1) AS indexed,
k.idx % 4 AS panel_col,
k.idx // {knob.cols} AS panel_row FROM input i JOIN k USING (branch) ORDER BY panel_row, panel_col, i.monthRows
| Month | Branch | Loans | Indexed | Panel col | Panel row |
|---|---|---|---|---|---|
| Nov 1, 2023 | Central | 19,653 | 93.3 | 0 | 0 |
| Dec 1, 2023 | Central | 17,412 | 82.7 | 0 | 0 |
| Jan 1, 2024 | Central | 21,891 | 104 | 0 | 0 |
| Feb 1, 2024 | Central | 21,622 | 103 | 0 | 0 |
| Mar 1, 2024 | Central | 21,386 | 102 | 0 | 0 |
| Apr 1, 2024 | Central | 19,637 | 93.2 | 0 | 0 |
| May 1, 2024 | Central | 19,433 | 92.3 | 0 | 0 |
| Jun 1, 2024 | Central | 22,525 | 107 | 0 | 0 |
| Jul 1, 2024 | Central | 24,819 | 118 | 0 | 0 |
| Aug 1, 2024 | Central | 24,166 | 115 | 0 | 0 |
| Sep 1, 2024 | Central | 19,878 | 94.4 | 0 | 0 |
| Oct 1, 2024 | Central | 20,354 | 96.6 | 0 | 0 |
| Nov 1, 2024 | Central | 18,900 | 89.7 | 0 | 0 |
| Dec 1, 2024 | Central | 18,668 | 88.6 | 0 | 0 |
| Jan 1, 2025 | Central | 12,641 | 60 | 0 | 0 |
| Feb 1, 2025 | Central | 12,625 | 59.9 | 0 | 0 |
| Mar 1, 2025 | Central | 13,705 | 65.1 | 0 | 0 |
| Apr 1, 2025 | Central | 13,011 | 61.8 | 0 | 0 |
| May 1, 2025 | Central | 12,691 | 60.2 | 0 | 0 |
| Jun 1, 2025 | Central | 14,171 | 67.3 | 0 | 0 |
| Jul 1, 2025 | Central | 15,637 | 74.2 | 0 | 0 |
| Aug 1, 2025 | Central | 14,751 | 70 | 0 | 0 |
| Sep 1, 2025 | Central | 12,150 | 57.7 | 0 | 0 |
| Oct 1, 2025 | Central | 12,553 | 59.6 | 0 | 0 |
| Nov 1, 2023 | Northgate | 8,948 | 88.4 | 1 | 0 |
| Dec 1, 2023 | Northgate | 8,364 | 82.6 | 1 | 0 |
| Jan 1, 2024 | Northgate | 10,023 | 99 | 1 | 0 |
| Feb 1, 2024 | Northgate | 9,885 | 97.7 | 1 | 0 |
| Mar 1, 2024 | Northgate | 10,497 | 104 | 1 | 0 |
| Apr 1, 2024 | Northgate | 9,773 | 96.6 | 1 | 0 |
| May 1, 2024 | Northgate | 9,409 | 93 | 1 | 0 |
| Jun 1, 2024 | Northgate | 10,909 | 108 | 1 | 0 |
| Jul 1, 2024 | Northgate | 12,520 | 124 | 1 | 0 |
| Aug 1, 2024 | Northgate | 11,946 | 118 | 1 | 0 |
| Sep 1, 2024 | Northgate | 9,624 | 95.1 | 1 | 0 |
| Oct 1, 2024 | Northgate | 9,568 | 94.5 | 1 | 0 |
| Nov 1, 2024 | Northgate | 10,091 | 99.7 | 1 | 0 |
| Dec 1, 2024 | Northgate | 8,837 | 87.3 | 1 | 0 |
| Jan 1, 2025 | Northgate | 11,298 | 112 | 1 | 0 |
| Feb 1, 2025 | Northgate | 10,697 | 106 | 1 | 0 |
| Mar 1, 2025 | Northgate | 10,883 | 108 | 1 | 0 |
| Apr 1, 2025 | Northgate | 10,624 | 105 | 1 | 0 |
| May 1, 2025 | Northgate | 9,828 | 97.1 | 1 | 0 |
| Jun 1, 2025 | Northgate | 11,436 | 113 | 1 | 0 |
| Jul 1, 2025 | Northgate | 13,628 | 135 | 1 | 0 |
| Aug 1, 2025 | Northgate | 12,122 | 12 | 1 | 0 |
| Sep 1, 2025 | Northgate | 9,572 | 94.6 | 1 | 0 |
| Oct 1, 2025 | Northgate | 11,130 | 110 | 1 | 0 |
| Nov 1, 2023 | Westbrook | 8,170 | 91.9 | 2 | 0 |
| Dec 1, 2023 | Westbrook | 7,361 | 82.8 | 2 | 0 |
First 50 of 288 rows.
Step 4
Color each panel by its year-over-year change
Ten panels go one color, two go the other. The system total fell because one big branch moved into a small building, not because people stopped borrowing.
Tableau
// [YoY change]
{ FIXED [branch] : SUM(IF [month] >= #2024-11-01# THEN [loans] END) }
/ { FIXED [branch] : SUM(IF [month] < #2024-11-01# THEN [loans] END) } - 1
// Color: [YoY change] > 0SQL
WITH t AS (
SELECT
branch,
SUM(loans) AS total,
AVG(loans) FILTER (WHERE month < DATE '2024-11-01') AS base,
SUM(loans) FILTER (WHERE month >= DATE '2024-11-01')
* 1.0
/ SUM(loans) FILTER (WHERE month < DATE '2024-11-01')
- 1 AS yoy_change
FROM input
GROUP BY branch
), k AS (
SELECT
branch,
base,
yoy_change,
ROW_NUMBER() OVER (ORDER BY total DESC, branch) - 1 AS idx
FROM t
)
SELECT
i.month,
i.branch,
i.loans,
ROUND(100.0 * i.loans / k.base, 1) AS indexed,
k.yoy_change,
k.idx % 4 AS panel_col,
k.idx // {knob.cols} AS panel_row FROM input i JOIN k USING (branch) ORDER BY panel_row, panel_col, i.monthRows
| Month | Branch | Loans | Indexed | YoY change | Panel col | Panel row |
|---|---|---|---|---|---|---|
| Nov 1, 2023 | Central | 19,653 | 93.3 | −32.2% | 0 | 0 |
| Dec 1, 2023 | Central | 17,412 | 82.7 | −32.2% | 0 | 0 |
| Jan 1, 2024 | Central | 21,891 | 104 | −32.2% | 0 | 0 |
| Feb 1, 2024 | Central | 21,622 | 103 | −32.2% | 0 | 0 |
| Mar 1, 2024 | Central | 21,386 | 102 | −32.2% | 0 | 0 |
| Apr 1, 2024 | Central | 19,637 | 93.2 | −32.2% | 0 | 0 |
| May 1, 2024 | Central | 19,433 | 92.3 | −32.2% | 0 | 0 |
| Jun 1, 2024 | Central | 22,525 | 107 | −32.2% | 0 | 0 |
| Jul 1, 2024 | Central | 24,819 | 118 | −32.2% | 0 | 0 |
| Aug 1, 2024 | Central | 24,166 | 115 | −32.2% | 0 | 0 |
| Sep 1, 2024 | Central | 19,878 | 94.4 | −32.2% | 0 | 0 |
| Oct 1, 2024 | Central | 20,354 | 96.6 | −32.2% | 0 | 0 |
| Nov 1, 2024 | Central | 18,900 | 89.7 | −32.2% | 0 | 0 |
| Dec 1, 2024 | Central | 18,668 | 88.6 | −32.2% | 0 | 0 |
| Jan 1, 2025 | Central | 12,641 | 60 | −32.2% | 0 | 0 |
| Feb 1, 2025 | Central | 12,625 | 59.9 | −32.2% | 0 | 0 |
| Mar 1, 2025 | Central | 13,705 | 65.1 | −32.2% | 0 | 0 |
| Apr 1, 2025 | Central | 13,011 | 61.8 | −32.2% | 0 | 0 |
| May 1, 2025 | Central | 12,691 | 60.2 | −32.2% | 0 | 0 |
| Jun 1, 2025 | Central | 14,171 | 67.3 | −32.2% | 0 | 0 |
| Jul 1, 2025 | Central | 15,637 | 74.2 | −32.2% | 0 | 0 |
| Aug 1, 2025 | Central | 14,751 | 70 | −32.2% | 0 | 0 |
| Sep 1, 2025 | Central | 12,150 | 57.7 | −32.2% | 0 | 0 |
| Oct 1, 2025 | Central | 12,553 | 59.6 | −32.2% | 0 | 0 |
| Nov 1, 2023 | Northgate | 8,948 | 88.4 | +7.1% | 1 | 0 |
| Dec 1, 2023 | Northgate | 8,364 | 82.6 | +7.1% | 1 | 0 |
| Jan 1, 2024 | Northgate | 10,023 | 99 | +7.1% | 1 | 0 |
| Feb 1, 2024 | Northgate | 9,885 | 97.7 | +7.1% | 1 | 0 |
| Mar 1, 2024 | Northgate | 10,497 | 104 | +7.1% | 1 | 0 |
| Apr 1, 2024 | Northgate | 9,773 | 96.6 | +7.1% | 1 | 0 |
| May 1, 2024 | Northgate | 9,409 | 93 | +7.1% | 1 | 0 |
| Jun 1, 2024 | Northgate | 10,909 | 108 | +7.1% | 1 | 0 |
| Jul 1, 2024 | Northgate | 12,520 | 124 | +7.1% | 1 | 0 |
| Aug 1, 2024 | Northgate | 11,946 | 118 | +7.1% | 1 | 0 |
| Sep 1, 2024 | Northgate | 9,624 | 95.1 | +7.1% | 1 | 0 |
| Oct 1, 2024 | Northgate | 9,568 | 94.5 | +7.1% | 1 | 0 |
| Nov 1, 2024 | Northgate | 10,091 | 99.7 | +7.1% | 1 | 0 |
| Dec 1, 2024 | Northgate | 8,837 | 87.3 | +7.1% | 1 | 0 |
| Jan 1, 2025 | Northgate | 11,298 | 112 | +7.1% | 1 | 0 |
| Feb 1, 2025 | Northgate | 10,697 | 106 | +7.1% | 1 | 0 |
| Mar 1, 2025 | Northgate | 10,883 | 108 | +7.1% | 1 | 0 |
| Apr 1, 2025 | Northgate | 10,624 | 105 | +7.1% | 1 | 0 |
| May 1, 2025 | Northgate | 9,828 | 97.1 | +7.1% | 1 | 0 |
| Jun 1, 2025 | Northgate | 11,436 | 113 | +7.1% | 1 | 0 |
| Jul 1, 2025 | Northgate | 13,628 | 135 | +7.1% | 1 | 0 |
| Aug 1, 2025 | Northgate | 12,122 | 12 | +7.1% | 1 | 0 |
| Sep 1, 2025 | Northgate | 9,572 | 94.6 | +7.1% | 1 | 0 |
| Oct 1, 2025 | Northgate | 11,130 | 110 | +7.1% | 1 | 0 |
| Nov 1, 2023 | Westbrook | 8,170 | 91.9 | +5.5% | 2 | 0 |
| Dec 1, 2023 | Westbrook | 7,361 | 82.8 | +5.5% | 2 | 0 |
First 50 of 288 rows.