Dataslope logoDataslope

Facets and Grids

Small multiples — splitting data by category into a grid of panels with col and row, the FacetGrid workflow underneath, and when a grid becomes too much.

One of the most powerful moves in all of visualization is the small multiple: instead of cramming every group onto one busy chart, draw the same chart many times — once per group — and lay the copies out in a grid. The eye compares panels effortlessly, because only the data changes from cell to cell, never the encoding.

Seaborn calls this faceting, and it's built into every figure-level function through two keywords: col and row.

Faceting is just col and row

We've used col already. Add row and you get a 2-D grid — one panel for every combination of the two faceting variables:

Code Block
Python 3.13.2

Each panel holds the same scatter plot for its slice of the data, and — crucially — every panel shares the same axes by default, so a point in one cell is directly comparable to a point in another. That shared scale is what makes small multiples honest.

hue overlays; col/row separate

hue draws groups on top of each other in one panel (good for direct overlap and a few groups). col/row give each group its own panel (good for many groups, or when overlap would be a mess). You can combine them: color by hue and split by col. Choosing between overlay and separation is one of the everyday judgment calls of faceting.

Wrapping many categories with col_wrap

A single faceting variable with many levels would stretch into one very wide row. col_wrap wraps the panels after N columns into a tidy block:

Code Block
Python 3.13.2

The FacetGrid workflow underneath

The figure-level functions do their faceting through a class called FacetGrid. You rarely call it directly, but understanding its three-step workflow demystifies what relplot and friends are doing — and lets you build custom grids when you need them.

In code, those steps look like this:

Code Block
Python 3.13.2

That is exactly the machinery sns.relplot(..., col="time", hue="sex") runs for you. Reach for an explicit FacetGrid only when you want to map a custom function or layer several plots per panel; otherwise let the figure-level function do it.

Three grid classes, one idea

Seaborn has three grid classes: FacetGrid (same plot across category panels — this page), PairGrid (every variable against every other — the pair-plots chapter), and JointGrid (one center plot with marginal distributions — the joint-plots chapter). All three follow the same "set up the grid, then map plots onto it" pattern.

Shared scales — usually keep them

By default facets share x- and y-limits. That's almost always what you want, because it keeps panels comparable. Occasionally one group's range dwarfs the others and you'll want to free a scale with sharey=False (via facet_kws={"sharey": False} on the figure-level functions) — but do it consciously, and tell your reader, because un-shared axes make panels look similar when they aren't.

QuestionSelect one

Why does Seaborn make facets share the same axis limits by default?

To make the figure render faster.

So panels are directly comparable — a position in one panel means the same as the same position in another.

Because Seaborn cannot compute separate limits per panel.

To save vertical space.

When a grid becomes too much

Faceting multiplies panels: col levels × row levels. That's its weakness as well as its strength.

  • Too many facets. Twenty tiny panels are as hard to read as one overcrowded chart. Keep a facet variable to a handful of levels; use col_wrap to keep the block compact.
  • A high-cardinality facet variable. Faceting on something with 50+ categories produces 50+ unreadable thumbnails. Group rare categories together, filter to the ones you care about, or pick a different view.
  • Sparse cells. If some category combinations have almost no data, those panels are nearly empty and waste space — consider a single faceting dimension instead of two.

Facet count = col × row

Before adding a row, do the multiplication. A col with 4 levels and a row with 5 is already 20 panels. Small multiples are a scalpel, not a firehose — a few well-chosen facets beat a wall of thumbnails.

Your turn

Challenge
Python 3.13.2
Build a 2-by-2 facet grid

Using tips, draw a scatter of total_bill (x) vs tip (y) with sns.relplot, faceted into a grid with:

  • one column per time (Lunch, Dinner), and
  • one row per sex (Male, Female).

Assign the result to g. Since each variable has two levels, you should get a 2 × 2 grid of panels.

Check your understanding

QuestionSelect one

What is "faceting" (drawing small multiples) in Seaborn?

Overlaying every group's data in a single set of axes using different colors.

Splitting the data by one or two categorical variables and drawing the same plot once per group, arranged in a grid.

Computing summary statistics for each group.

Changing the color palette across the figure.

QuestionSelect one

You facet with col (3 levels) and row (4 levels). How many panels do you get?

7, one per category level.

12 — the product of the levels (3 × 4).

1, with all groups overlaid.

3, ignoring the row variable.

QuestionSelect one

In the explicit FacetGrid workflow, what does the map (or map_dataframe) step do?

It creates the grid of empty axes.

It applies a plotting function to each data subset, drawing the same plot in every panel.

It adds the legend to the figure.

It melts the data into long form.

QuestionSelect one

You facet a plot on a column that has 60 distinct values. What's the likely result, and a better approach?

A single clear chart; no problem at all.

About 60 tiny, unreadable panels — better to filter to a few categories of interest or group the rare ones.

Seaborn automatically picks the 5 most important categories.

The panels will overlap into one.

You can now break a dataset into comparable panels and know when not to. Two specialized grids remain — the all-pairs pair plot and the margin-equipped joint plot — which apply this same "set up a grid, map plots onto it" idea to specific questions.

On this page