🎨 Transform Figma mockups into production-ready Dash apps. Join us November 10. Save your spot.

Chris Parmer

Chris Parmer

October 27, 2026

Small Multiples - A Complete Guide (with 13 Examples)

TL;DR

  • Small multiples repeat the same small chart once per group, with the same axes and encoding, so the eye compares panels instead of untangling lines.
  • Small multiples are also known as trellis charts, lattice charts, panel charts and facet plots, and are similar to ridgeline plots and scatter plot matrices.
  • Use them when one chart would hold more than about five overlapping series, or when each group needs its own reference band, map position or distribution.
  • Share the axes unless the sizes differ so much that the small groups go flat, then label every panel's scale, index each series to a common base, or draw every other group in gray behind each panel.
  • In Python, px.line(df, x=..., y=..., facet_col="group", facet_col_wrap=4) makes one in one line of code, and make_subplots handles custom grids such as a map of US states.

What is a small multiple chart?

Small multiples look like this:

A grid of 51 small area charts of the monthly unemployment rate from January 2007 to September 2026, one per state, placed roughly where each state is on a US map. Every panel shares a 0 to 32% scale and shows the spike of spring 2020, when every state reached its highest rate (in South Carolina, equal to its 2009 peak of 11.7%). Nevada, Michigan and Hawaii are orange because they peaked above 20%, and each label gives the latest rate, from 2.0% in South Dakota to 5.6% in DC

Data: BLS Local Area Unemployment Statistics via FRED.

How do you read small multiples? In the example above, notice these things:

  • Each panel is the same small area chart, one state's monthly unemployment rate, and the panels sit roughly where the states are on a US map, so Alaska is in the top left and Maine in the top right.
  • Every panel shares the same time axis and the same 0 to 32% scale, so a taller line means a higher rate and you can compare any two states by eye without reading their axes.
  • Because the panels repeat one design, the eye picks up the shared shape first. Almost every state has a wide hump during the Great Recession and a sharp spike in spring 2020, so a state that breaks the pattern stands out, like South Carolina, whose earlier hump reached the same 11.7% as its pandemic spike.
  • Color picks out the panels worth a second look. Nevada, Michigan and Hawaii are orange because their peaks went above 20%, and the number next to each state's name is its latest rate.
  • The shared scale has a cost, since states with low rates such as North Dakota and South Dakota draw nearly flat lines whose small changes are hard to see. Switch to independent y axes when the shape within each state matters more than the comparison between them.

It's often used for charts like these:

Twelve US industry drawdown charts from 1990 to 2026 in a 3 by 4 grid, ordered from the deepest drawdown. In each panel one industry is a blue line and the other 11 are light gray behind it. Business equipment (tech) fell 80% by 2002, followed by consumer durables (-74%), finance (-72%) and telecom (-72%); consumer staples fell at most 34%

Highlighting one series against all the others. Tech stocks fell 80% from March 2000 and took until July 2016 to recover, the longest drawdown of 12 US industries since 1990. Data: Kenneth R. French Data Library (CRSP).

A market dashboard table with 12 rows: S&P 500, VIX, 2-year and 10-year Treasury, 30-year mortgage, Baa corporate spread, US dollar index, euro, bitcoin, WTI crude, Brent crude and Henry Hub gas. Each row has the latest value, a one-year sparkline with a dotted line at the starting value, the change and the 12-month range. Brent crude rose 89.8% and is highlighted in orange; the 2-year Treasury yield rose 133 basis points and bitcoin fell 23.5%

Sparklines in a table. Brent crude rose 89.8% in the year to October 20, 2026, more than any other series on a 12-row market dashboard. Data: FRED.

Eleven histograms of daily US stock market returns, one per decade from the 1920s to the 2020s, on the same axes from -6% to +6%. Days with moves of 2% or more are orange. The 1930s histogram is wide with 532 such days, while the 1950s is a narrow spike with 25

Distributions by group. The 1930s had 532 trading days when US stocks moved 2% or more, and the 1950s had 25. Data: Kenneth R. French Data Library (CRSP).

A short history

Edward Tufte named and popularized small multiples in The Visual Display of Quantitative Information (1983). William Cleveland and colleagues at Bell Labs turned them into the trellis display, a grid of panels conditioned on one or two variables (Becker, Cleveland and Shyu, 1996). Cleveland's best-known example, in Visualizing Data (1993), used barley yields from six Minnesota sites (Immer, Hayes and Powers, 1934):

Cleveland's barley trellis display redrawn with Plotly: six dot-plot panels, one per Minnesota site, with 10 barley varieties on the y axis and yield in bushels per acre on the x axis, 1931 as filled blue dots and 1932 as open orange circles. At Waseca, Crookston, Duluth and Grand Rapids nearly every variety yielded less in 1932, while at Morris all 10 yielded more

At Morris all 10 varieties yielded more in 1932 than in 1931, while at the other five sites at most one did. Laid out in panels, the exception is obvious, and Cleveland suggested the two years may have been swapped in the records.

Alternatives to small multiples

Here's the same monthly crude oil production of eight states drawn four ways. Some are better for the question, some worse, some just different:

The crude oil production of eight US states from 2005 to 2026 drawn four ways: one line chart with eight colored lines where the smaller states tangle near the bottom, a stacked area chart rising to about 11 million barrels a day, a heatmap of each state's production as a percent of its own peak, and small multiples with one panel per state on a shared axis
  • One line chart (works too, for a few series). Up to four or five lines it is the most compact choice. With eight states, the five smaller ones overlap below 1,000 thousand barrels a day and the colors become a legend lookup.
  • Stacked area chart (different). Shows the total, about 11 million barrels a day for these eight states, but only the bottom band has a flat baseline, so the other states' trends are hard to read.
  • Heatmap (better for many series and timing). Scaled to each state's peak, it shows when each state grew in one compact block, and it fits hundreds of rows. Color is less precise than position, so exact values are hard to read. See our heatmap guide.
  • Small multiples (better for comparing shapes). Each state's line is readable on its own and comparable with the others on the shared axis. They take more room, and you lose the exact overlap of two series in one panel.

For distributions by group, a ridgeline plot is a compact alternative to faceted histograms (see our ridgeline plot guide), and a scatter plot matrix is small multiples of every pair of variables (see our scatter plot matrix guide).

How to make small multiples

With AI

ChatGPT, Claude Code, GitHub Copilot, Cursor and other AI tools are excellent at writing Plotly code. Name Plotly in the prompt, say what one panel shows, how to lay out and order the panels and whether the axes are shared:

Make plotly small multiples from production.csv (columns: date, state, kbd).
- One line chart per state with px.line and facet_col="state", facet_col_wrap=4.
- Order the panels by the latest value, largest first (category_orders).
- Shared y axis starting at zero, labeled once as "Thousand barrels a day".
- Panel titles show only the state name and its latest value, without "state=".
- One color for every line; show year tick labels only on the bottom row.
- A title that states the main takeaway and a muted subtitle with the source.
- Save it as small_multiples.html and as a PNG at 2x scale.

With Plotly Studio

Plotly Studio is a desktop app where you point an AI at a dataset and it builds charts and a Dash app around your questions. Ask for small multiples the same way:

Show the weekly flu hospitalization rate for every state as a grid of small area charts, sorted by each state's peak, with the national rate as a dotted gray line in every panel. Add a dropdown to switch between flu, COVID-19 and RSV.

Make small multiples in Python or JavaScript

This is the code AI tools write under the hood. In Python, Plotly Express makes a faceted chart from a long table with one row per point:

import plotly.express as px
df = px.data.stocks().melt("date", var_name="ticker", value_name="price")
fig = px.line(df, x="date", y="price", facet_col="ticker", facet_col_wrap=3)
fig.for_each_annotation(lambda a: a.update(text=a.text.split("=")[-1]))
fig.show()

Plotly Express and make_subplots both build small multiples as a grid of ordinary subplots, one pair of axes per panel. For layouts px can't make, this helper places each panel at a grid position (a map of states, as in the first chart on this page) and can draw every other group in gray behind each panel:

import plotly.express as px
import plotly.graph_objects as go
from plotly.subplots import make_subplots
def make_small_multiples(df, facet, x, y, cols=4, positions=None, shared_y=True, context=False):
"""One line chart per group, at positions={group: (row, col)} counted from 0."""
if positions is None:
positions = {g: divmod(i, cols) for i, g in enumerate(dict.fromkeys(df[facet]))}
rows = max(r for r, c in positions.values()) + 1
cols = max(c for r, c in positions.values()) + 1
titles = [""] * (rows * cols) # one title per grid cell, blank for empty cells
for g, (r, c) in positions.items():
titles[r * cols + c] = g
fig = make_subplots(rows=rows, cols=cols, shared_xaxes="all",
shared_yaxes="all" if shared_y else False, subplot_titles=titles)
for g, (r, c) in positions.items():
if context: # every other group in light gray, as one trace with None between groups
xs, ys = [], []
for _, d in df[df[facet] != g].groupby(facet):
xs += [*d[x], None]
ys += [*d[y], None]
fig.add_trace(go.Scatter(x=xs, y=ys, mode="lines", line=dict(color="#d4d3cd", width=1)),
row=r + 1, col=c + 1)
d = df[df[facet] == g]
fig.add_trace(go.Scatter(x=d[x], y=d[y], mode="lines", line=dict(color="#2a78d6", width=2)),
row=r + 1, col=c + 1)
fig.update_layout(template="simple_white", showlegend=False)
return fig
df = px.data.gapminder().query("country in ['Canada', 'United States', 'Mexico', 'Brazil', 'Chile']")
grid = {"Canada": (0, 1), "United States": (1, 1), "Mexico": (2, 0), "Brazil": (3, 2), "Chile": (4, 1)}
fig = make_small_multiples(df, "country", "year", "lifeExp", positions=grid, context=True)
fig.show()

In JavaScript, plotly.js puts each trace on its own xaxis/yaxis pair, layout.grid lays the pairs out, and matches shares an axis:

<div id="chart"></div>
<script src="https://cdn.plot.ly/plotly-4.1.1.min.js"></script>
<script>
// annual average crude oil production, thousand barrels a day (EIA)
const years = [2005, 2010, 2015, 2020, 2025];
const states = {
"Texas": [1076, 1169, 3460, 4851, 5760],
"New Mexico": [167, 180, 406, 1033, 2205],
"North Dakota": [98, 308, 1177, 1199, 1171],
"Alaska": [864, 600, 483, 448, 422],
};
const names = Object.keys(states);
const traces = names.map((name, i) => ({
x: years, y: states[name], mode: "lines", line: {color: "#2a78d6"},
xaxis: "x" + (i + 1), yaxis: "y" + (i + 1)
}));
const layout = {
grid: {rows: 1, columns: 4, pattern: "independent"},
showlegend: false,
annotations: names.map((name, i) => ({
text: "<b>" + name + "</b>", showarrow: false, x: 0, y: 1.12,
xref: "x" + (i + 1) + " domain", yref: "y" + (i + 1) + " domain"
}))
};
for (let i = 2; i <= names.length; i++) layout["yaxis" + i] = {matches: "y"}; // shared y axis
Plotly.newPlot("chart", traces, layout);
</script>

Share it

Every Plotly chart has a Share chart button (the cloud icon in its toolbar) that uploads it to Plotly Cloud and gives you a link. Only you can see it until you change its visibility.

For a live app, put the chart in a Dash app and publish it with the Plotly Cloud CLI. Coding agents can run these commands for you:

pip install "dash[cloud]"
plotly user login
plotly app publish

If your data has to stay in your own cloud or data center, publish to Dash Enterprise instead.

Dos and don'ts

Plotly Express gives you a working grid in one line, and most of the work for a published chart is in the axes, the order and the panel labels. Here is the crude oil production of eight states both ways, with the same color.

Don't hide the scales of independent y axes, sort the panels alphabetically, keep the "area=" prefixes or repeat the axis titles under every panel:

Eight small line charts of state crude oil production in alphabetical order, titled area=Alaska, area=California and so on in a serif font, each with its own y scale and no y tick labels, so Alaska's falling line and Texas's rising line look about the same size, and the titles kbd and date repeated on every row and column

Do share and label the y axis, order the panels by size, and put the name and the latest value in each panel title:

The same eight states on one labeled scale from 0 to 6,000 thousand barrels a day, ordered from Texas (5,768) and New Mexico (2,420) down to California (245), with each title giving the state and its July 2026 production

Shared, independent or indexed axes

The axis choice decides what the panels compare. Here are four options on the same data.

Shared axes. Panels compare sizes, and it's the right default. Texas dwarfs everything, so the small states look flat.

The eight states on a shared scale of thousand barrels a day; Texas rises to about 5,800 while Alaska, Oklahoma, Wyoming and California are nearly flat lines near the bottom

Independent axes. Every shape is readable, but panels no longer compare by height, so every panel needs its own labeled scale. In Plotly Express, use fig.update_yaxes(matches=None, showticklabels=True).

The eight states with one y scale per panel, labeled from 0 to 6,000 for Texas and from 0 to about 300 for Wyoming, so Alaska's decline and Oklahoma's 2019 peak are clearly visible

Indexed to a common base. Each state as a percent of its own peak shares one axis again and compares timing: New Mexico and Wyoming are at their peaks now, Texas is 1% below its peak, North Dakota peaked in 2019 and Alaska in 2005.

The eight states as a percent of each state's peak month, all on a 0 to 100% scale, with Texas, New Mexico and Wyoming ending near 100%, North Dakota and Colorado near 75 to 80%, and Alaska and California between 38% and 46%

Indexed, with the others in gray. Adds every other state behind each panel, so you can see whether a state is typical or an outlier.

The same indexed panels with the other seven states drawn as light gray lines behind each blue line, showing Alaska and California declining while most other states rose

Checklist

Do

  • Write a title that states the takeaway, and put the panel's key number in each panel title.
  • Share the axes by default, and say so when they aren't shared.
  • Order the panels by something meaningful: size, peak, change or geography.
  • Label each axis once, and show tick labels only on the outer panels.
  • Use one color for the main series, and save other colors for a highlight.

Don't

  • Hide the scale of independent axes.
  • Leave "column=value" in the panel titles.
  • Sort panels alphabetically when the ranking matters.
  • Add a legend for something the panel titles already say.
  • Make panels so small that the lines can't show a shape.

Options to customize

These are the Plotly Express and make_subplots options that matter most for small multiples. The full lists are in the Plotly facet plots documentation and the subplots documentation.

  1. facet_col, facet_row (px): one column or row of panels per value of a column; use both for a grid of two variables.
  2. facet_col_wrap (px): wraps a single facet variable into rows of N panels.
  3. category_orders (px): the panel order, for example {"state": ["Texas", "New Mexico", ...]} sorted by size.
  4. facet_col_spacing, facet_row_spacing (px): gaps between panels, as a fraction of the figure; lower them for big grids.
  5. fig.for_each_annotation(...): rewrites the panel titles, for example to drop the "column=" prefix.
  6. fig.update_yaxes(matches=None): gives every panel its own y range; add showticklabels=True so each scale is labeled.
  7. make_subplots(rows, cols): the grid for custom layouts; place each trace with row= and col=.
  8. shared_xaxes, shared_yaxes: True shares within a row or column, "all" across the whole grid.
  9. subplot_titles: one title per grid cell, in row order, with "" for empty cells.
  10. horizontal_spacing, vertical_spacing: gaps between make_subplots panels.
  11. specs: cells that span several columns or rows, or that hold a map, a table or a polar chart.
  12. row="all", col="all": add the same reference line or shape to every panel with add_hline or add_shape.
  13. xref="x2 domain": places an annotation relative to one panel, for labels inside the panel.
  14. layout.grid (plotly.js): lays out axis pairs in rows and columns without Python.

More small multiple examples

Nine more small multiples built from real public data, each with its source, the technique that makes it work and a prompt to rebuild it.

1. Daily electricity demand for seven US grids

Seven small line charts of average electricity demand by hour of day in 2025 for ISO-NE, NYISO, PJM, SPP, MISO, ERCOT and CAISO, each as a percent of the grid's 2025 average, with lines for January, April, July and October. July is the highest line in every panel and peaks at 149% in ISO-NE, 148% in NYISO, 143% in PJM and 130% in CAISO

Each grid's demand is divided by its own 2025 average, so PJM (96 GW) and ISO New England (13 GW) share one axis and the panels compare shapes. In July the daily peak ran 30% to 49% above each grid's average, the most in New England. Data: EIA Hourly Electric Grid Monitor (Form EIA-930), 2025.

Tip: indexing every series to its own average lets very different sizes share one axis, so you don't need independent scales.

Get the data from the EIA Hourly Electric Grid Monitor (Form EIA-930) six-month balance files for 2025
(eia.gov/electricity/gridmonitor) for the balancing authorities CISO, ERCO, ISNE, MISO, NYIS, PJM and SWPP
and shape it into a table
(columns: iso, month, hour, demand_gw, pct_of_annual_mean; mean hourly demand by month and local hour,
and that mean as a percent of the grid's 2025 average).
Make plotly small multiples with px.line and facet_col="iso", facet_col_wrap=4.
- One line per month for January, April, July and October in four colors.
- Shared y axis in percent of the annual average, with a dotted line at 100%.
- Order the panels by the July peak and put it in each panel title, without "iso=".
- Hour ticks at 12am, 6am, 12pm and 6pm; the legend in the empty eighth cell.
- Title with the takeaway; subtitle with each grid's size in GW and the source.

2. Crude oil production by state, on independent axes

Twelve small line charts of crude oil production from January 2005 to July 2026 for the 12 largest producing areas, each on its own y scale starting at zero. Texas (5,768 thousand barrels a day, 5.3x 2005), New Mexico (2,420, 14.0x) and North Dakota (1,158, 12.9x) rise in blue, while Alaska (-54%), California (-61%) and Kansas (-16%) fall in orange

With each panel on its own scale, every state's shape is readable, and the latest value and the ratio to 2005 in each title carry the size. New Mexico now pumps 14 times as much crude as in January 2005, while Alaska and California pump less than half. Data: EIA Petroleum Supply Monthly.

Tip: fig.update_yaxes(matches=None, showticklabels=True) frees and labels every y axis, and rangemode="tozero" keeps each one honest from zero.

Get the data from the EIA Petroleum Supply Monthly crude oil production by state
(eia.gov/dnav/pet, PET_CRD_CRPDN_ADC_MBBLPD_M)
and shape it into a table
(columns: date, area, kbd; thousand barrels a day for each state and the federal offshore Gulf of America).
Make plotly small multiples with px.line, facet_col="area", facet_col_wrap=4, for the 12 largest areas.
- Independent y axes from zero, each with tick labels (matches=None, showticklabels=True).
- Panels ordered by the latest month's production; each title gives it and the ratio to January 2005.
- Blue for areas above their 2005 level, orange for those below; no legend, explain it in the subtitle.
- Say in the subtitle that each panel has its own scale.

3. A cycle plot of US natural gas use

Twelve small line charts, one per calendar month, of US natural gas consumption from 2001 to 2025 on a shared axis in billion cubic feet a day, each with a gray line at that month's 25-year average. Winter months are highest; every month rose, July the most (+70%) and March the least (+23%), and June to September are orange

A cycle plot gives each calendar month its own panel with the years from left to right, so the seasons and the trend show up at once. July consumption rose 70% from 2001 to 2025, the most of any month, while January rose 46% and March 23%. Data: EIA Natural Gas Monthly.

Tip: make_subplots(rows=1, cols=12, shared_yaxes=True) with year labels only under the first panel keeps twelve narrow panels readable.

Get the data from the EIA Natural Gas Monthly, US total natural gas consumption (series N9140US2, eia.gov)
and shape it into a table
(columns: date, year, month, bcf_per_day; monthly consumption in billion cubic feet a day, 2001-2025).
Make a plotly cycle plot with make_subplots(rows=1, cols=12, shared_yaxes=True).
- One panel per calendar month with that month's values from 2001 to 2025 as a line.
- A gray horizontal line at each month's 25-year average.
- Panel titles: the month and its change from 2001 to 2025 in percent.
- Summer months (June to September) in orange, the rest in blue.
- Year labels only under the first panel; y axis titled once.

Another way to see it: the same data as one line chart shows the seasons as a zigzag, and the faster growth of summer consumption is hard to see.

A single line chart of US natural gas consumption by month from 2001 to 2025, zigzagging between summer lows near 46 and winter highs up to 126.5 billion cubic feet a day

4. Every Treasury yield curve since 2019

Eight panels of US Treasury yield curves, one per year from 2019 to 2026, with maturities from 3 months to 30 years on the x axis. Every trading day is a thin line, orange when the 10-year yield was below the 3-month yield, with the last trading day in black. 2023 is all orange (250 of 250 days inverted) and 2024 nearly so (238 of 250), while 2021 and 2026 have no inverted days

Each panel draws every trading day's yield curve in a year, orange when the 10-year yield was below the 3-month yield. The curve was inverted on all 250 trading days of 2023 and 238 of 250 in 2024, and on none so far in 2026. Data: US Treasury, Daily Treasury Par Yield Curve Rates.

Tip: all the days of one color go into one trace with None between curves, so 1,955 curves need 24 traces instead of 1,955.

Get the data from the US Treasury's Daily Treasury Par Yield Curve Rates for 2019 to 2026 (home.treasury.gov)
and shape it into a table
(columns: date, maturity, years, yield_pct; maturities 3 Mo, 6 Mo, 1, 2, 3, 5, 7, 10, 20 and 30 Yr).
Make plotly small multiples with make_subplots(rows=2, cols=4), one panel per year.
- Every day's curve as a thin line; days with the 10-year below the 3-month in translucent orange,
the rest in translucent blue. Put all the days of one color in one trace with None between days.
- The last trading day of each year as a black line with small markers.
- Maturities as evenly spaced categories; shared y axis from 0 to 6%.
- Panel titles: the year and the number of inverted days out of trading days.

5. Clinical trial starts by phase and sponsor

A grid of six line charts with Phase 1, Phase 2 and Phase 3 as rows and industry and academic sponsors as columns, showing interventional trials started each year from 2010 to 2025 on a shared axis. Industry Phase 1 starts rose from 1,471 to 2,121 (+44%), academic Phase 2 from 1,795 to 3,002 (+67%), while Phase 3 barely moved for industry (982 to 1,011, +3%) and academic sponsors (873 to 949, +9%)

Phases run down the rows and sponsor classes across the columns, so you can compare along either. Industry started 44% more Phase 1 trials in 2025 than in 2010, but only 3% more Phase 3 trials. Data: ClinicalTrials.gov API v2.

Tip: facet_row and facet_col together make a two-way grid, and moving the row labels to the left side makes it read like a table.

Get the data from the ClinicalTrials.gov API v2 (clinicaltrials.gov/api/v2/studies, countTotal=true):
interventional trials by start year 2010-2025, phase (PHASE1, PHASE2, PHASE3) and lead sponsor class
(INDUSTRY, OTHER)
and shape it into a table (columns: year, phase, sponsor, trials).
Make a plotly grid with px.line, facet_row="phase" and facet_col="sponsor", markers on.
- Shared y axis from zero; one color per sponsor class.
- Print the 2010 value at the start of each line and the 2025 value with its percent change at the end.
- Column titles on top, row titles as horizontal labels on the left, both without "phase=" or "sponsor=".
- Note in the subtitle that a Phase 1/2 trial counts in both rows.

6. Flu hospitalizations in every state, ranked

A grid of 51 small area charts of weekly flu hospital admissions per 100,000 people from October 2025 to May 2026, sorted by each state's peak from Rhode Island (26.1) and Pennsylvania (25.6) down to Washington (4.3), with the national rate as a dotted gray line in every panel. Oregon, Oklahoma, Arizona, California and Washington are orange because they peaked in February

Sorting 51 sparklines by their peak turns the grid into a ranking. Rhode Island peaked at 26.1 admissions per 100,000, six times Washington's 4.3, and the five orange states peaked in February, weeks after the national peak in the week ending January 3. Data: CDC National Healthcare Safety Network (NHSN), 2025-26 season.

Tip: the national series as a dotted gray line in every panel gives each state a reference without a second axis.

Get the data from the CDC NHSN Weekly Hospital Respiratory Data by jurisdiction (data.cdc.gov, dataset ua7e-t2fy),
column totalconfflunewadmper100k, weeks ending 2025-10-04 to 2026-05-30
and shape it into a table (columns: state, week, per_100k; the 50 states, DC and USA).
Make plotly small multiples with px.area, facet_col="state", facet_col_wrap=9.
- Order the panels by each state's peak (category_orders) and put the peak in each title.
- Same y scale everywhere, no tick labels inside the grid.
- Add the national series as a dotted gray line to every panel that has a state.
- Color states that peaked in February orange, the rest blue.

Another way to see it: a heatmap with the states in the same order shows the timing of each peak more clearly, but the size of each peak is harder to judge from color.

A heatmap of weekly flu admissions per 100,000 for 51 states sorted by peak, with dark cells concentrated in late December 2025 and early January 2026 and a later band for Oregon in February

7. Daily highs in eight cities against their normal range

Eight panels of 2025 daily high temperatures for Houston, Phoenix, Denver, Minneapolis, Chicago, Seattle, Miami and New York, each with a gray band for the 10th to 90th percentile of 1991-2020 highs. Orange dots mark days above the band: 79 in Houston, 66 in Phoenix, 55 in Denver, 50 in Minneapolis, 47 in Chicago, 39 in Seattle and 27 in Miami and New York

Each city gets its own band of normal daily highs, the 10th to 90th percentile for 1991-2020, so a hot day means hot for that city. By chance about 10% of days fall above the band, but Houston had 79 such days in 2025, more than twice that. Data: NOAA GHCN-Daily.

Tip: two invisible lines with fill="tonexty" draw the band, and the 2025 line goes on top so it stays visible.

Get the data from NOAA GHCN-Daily (ncei.noaa.gov) daily maximum temperature, 1991-2025, for the stations
USW00094728, USW00094846, USW00012960, USW00023183, USW00003017, USW00024233, USW00012839, USW00014922
and shape it into a table
(columns: city, doy, date, tmax_2025, p10, p50, p90; percentiles of 1991-2020 highs within 7 days of each date).
Make plotly small multiples with make_subplots(rows=2, cols=4, shared axes).
- A gray band from p10 to p90 (fill="tonexty"), the 2025 daily high as a thin black line.
- Orange markers on days above p90, blue on days below p10.
- Order panels by the number of days above p90 and put it in each title.

8. CO2 and income by continent

Five log-log scatter panels of fossil CO2 emissions per person against GDP per person in 2022, one per continent, ordered by population-weighted emissions: North America (10.5 t a person), Europe (7.0), Asia and Oceania (4.7), South America (2.5) and Africa (1.0). The United States emits 14.9 t a person, Switzerland 3.7 t at a similar income, China 8.0 t and India 2.0 t

One scatter panel per continent with the same log axes shows each region's spread without five colors piled on top of each other. Americans emit 14.9 tonnes of CO2 a person and the Swiss 3.7, at about the same income. Data: Our World in Data (Global Carbon Budget, Maddison Project Database, UN), 2022.

Tip: log_x=True, log_y=True in px.scatter applies to every facet, and labels added with xref="x3" need log10 positions on a log axis.

Get the data from Our World in Data's CO2 and Greenhouse Gas Emissions dataset (github.com/owid/co2-data),
year 2022, with continents from Our World in Data
and shape it into a table
(columns: country, iso3, continent, population, gdp_per_capita, co2_per_capita).
Make plotly small multiples with px.scatter and facet_col="continent" (Oceania merged into Asia).
- Log x and log y axes, shared; markers sized by population.
- Order panels by population-weighted CO2 per person and put it in each title.
- Label about 15 well-known countries, nudging labels that overlap.

9. Unemployment maps for four months

Four maps of the US state unemployment rate on one color scale from 0 to 30.5%: January 2007 (median state 4.4%), January 2010 (8.8%), April 2020 (13.3%, with Nevada, Michigan and Hawaii darkest) and September 2026 (3.9%)

A series of maps on one color scale is the classic small multiple, used in the Statistical Atlas of the United States for the 1870 census. Four maps of the state unemployment rate show the spread after the Great Recession and the spike of April 2020, when the median state's rate reached 13.3%. Data: BLS Local Area Unemployment Statistics via FRED.

Tip: px.choropleth takes facet_col and facet_col_wrap like the other Plotly Express functions, and range_color keeps one color scale across every map. See our choropleth map guide for more.

Get the data from FRED (the <ST>UR series for every state and DC, e.g. TXUR)
and shape it into a table (columns: state, date, rate).
Make plotly small multiple maps with px.choropleth: locationmode="USA-states", scope="usa",
facet_col for four months (January 2007, January 2010, April 2020, September 2026), facet_col_wrap=2,
one color scale from 0 to the highest rate, and the median state's rate in each panel title.

FAQ

bluesly
x
instagram
youtube
medium
fcaebook

Product

© 2026
Plotly. All rights reserved.
Cookie Preferences
aicpa/soc2