Skip to main content
Back to module
Data Visualization & Storytelling · Charts in Python

Small multiples

Reading55mLesson 3 of 3 in this module

Compare many groups with a grid of small, consistent charts instead of one tangled chart.

Why it matters

Plot monthly sales for five regions on one line chart and you get five crossing lines in five colours, a legend, and a reader squinting to work out which line is South. Plot 20 regions and the chart is unreadable. Small multiples, a term popularised by Edward Tufte, solve this: draw one small chart per group, with identical axes and scales, arranged in a grid. The reader learns how to read one panel, then compares all of them at a glance. Analysts also call these facet plots, trellis charts or panel charts.

What makes small multiples work

  1. Same chart type in every panel. Every panel is a line chart, or every panel is a histogram.
  2. Shared scales. The y-axis must run from the same minimum to the same maximum in every panel. Otherwise a flat line in one panel can look as steep as a big rise in another. This is the most important rule.
  3. Meaningful order. Order panels by something useful (largest total first, or geography), not alphabetically by default.
  4. Minimal labels. Put axis labels only on the outer edge of the grid and a short title on each panel.
  5. A shared highlight or reference when useful, such as the company average drawn in grey in every panel.

Small multiples in matplotlib

import math
import matplotlib.pyplot as plt

regions = ["North", "West", "South", "East", "Central"]   # ordered by total
ncols = 3
nrows = math.ceil(len(regions) / ncols)
fig, axes = plt.subplots(nrows, ncols, figsize=(10, 5), sharex=True, sharey=True)

for ax, region in zip(axes.flat, regions):
    data = sales[sales["region"] == region].sort_values("month")
    ax.plot(data["month"], data["units"], color="#1b9e77")
    ax.set_title(region, loc="left", fontsize=10)
    ax.set_ylim(0, 200)
    ax.tick_params(axis="x", labelrotation=45)

for ax in axes.flat[len(regions):]:
    ax.set_visible(False)          # hide the unused sixth panel

fig.suptitle("North is growing fastest; West is declining", x=0.01, ha="left")
fig.tight_layout()

sharex=True, sharey=True keeps scales identical and removes repeated tick labels. The loop over axes.flat fills the grid row by row. Five panels in a 3-column grid need 2 rows, leaving one empty panel to hide.

Small multiples in seaborn

seaborn's figure-level functions do the grid for you with col= (and row=):

import seaborn as sns

g = sns.relplot(
    data=sales, x="month", y="units", col="region",
    col_wrap=3, kind="line", height=2.5,
    col_order=["North", "West", "South", "East", "Central"],
)
g.set_titles("{col_name}")
g.set_axis_labels("", "Units sold")

col_wrap=3 wraps panels into rows of three. displot(..., col="region") does the same for histograms, and catplot for bar and box plots. These functions share axes by default; pass facet_kws={"sharey": False} only if you have a strong reason, and say so on the chart.

Worked example: when to share and when not

Five regions sell between 45 and 171 units a month. With a shared y-axis from 0 to 200, the reader immediately sees North growing, West shrinking and Central small but steady.

Now imagine one region sells 10,000 units and the others about 100. A shared axis squashes the small regions into flat lines at the bottom. Options:

  • Show the big region separately and share the axis across the rest.
  • Plot percentage change from the first month instead of raw units, so every region is on a comparable scale.
  • Use independent axes, but label clearly ("each panel has its own scale").

Common mistakes

  • Independent y-axes by accident. Many tools default to auto-scaling each panel. Check.
  • Too many panels. Beyond about 20 to 30, consider grouping or showing the top ones plus "all others".
  • Panels that are too small to read. Each one should still show its pattern; drop tick labels before shrinking further.
  • Alphabetical ordering when a value-based order would make the pattern obvious.
  • Colour that means different things in different panels. Keep encodings identical.

Quick recap

  • Small multiples are a grid of identical small charts, one per group.
  • Share scales, order panels meaningfully, and keep labels on the outer edge.
  • matplotlib: plt.subplots(rows, cols, sharex=True, sharey=True); seaborn: relplot/displot/catplot with col= and col_wrap=.

Try it

In the Do tab, prepare the data for a small-multiples chart: per-panel series, a shared y-limit, the grid shape and the panel order.

Also in this lesson: