Skip to content

How to create small-multiple scatterplots in Seaborn (with Code)

The Short Answer (TL;DR)

Use sns.relplot with kind="scatter" and col set to the grouping column to draw one scatterplot per group. Share the axes when the goal is to compare values across panels on the same scale.

import pandas as pd, seaborn as sns
data = pd.DataFrame({"x": [1, 2, 3, 1, 2, 3], "y": [2, 4, 5, 1, 3, 6], "group": ["A"] * 3 + ["B"] * 3})
sns.relplot(data=data, x="x", y="y", col="group", kind="scatter", facet_kws={"sharex": True, "sharey": True})

Detailed Implementation

This example uses synthetic data and does not need a network connection. Install the recorded package versions in a separate Python environment before running it.

python -m pip install numpy==2.5.4 pandas==3.0.6 matplotlib==3.11.2 seaborn==0.13.2
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

rng = np.random.default_rng(11)
x = np.tile(np.linspace(0, 10, 15), 3)
group = np.repeat(["A", "B", "C"], 15)
slopes = np.repeat([0.5, 1.0, 1.5], 15)
data = pd.DataFrame({"x": x, "y": slopes * x + rng.normal(size=45), "group": group})
grid = sns.relplot(data=data, x="x", y="y", col="group",
                   col_order=["A", "B", "C"], kind="scatter", height=3.1,
                   aspect=0.9, facet_kws={"sharex": True, "sharey": True})
grid.set_axis_labels("Input", "Synthetic response")
grid.set_titles("Group {col_name}")
grid.savefig("small-multiple-scatterplots.png", dpi=160)
plt.show()

The figure has three panels labelled Group A, Group B and Group C, each showing 15 observations with common axis limits.

Why use relplot instead of several scatterplot calls?

relplot creates and manages the FacetGrid and its figure. It is a figure-level function; it does not use an ax argument to draw into a pre-existing subplot. scatterplot is the axes-level alternative when an existing subplot layout needs to be reused.

When should axes be shared?

Keep sharex and sharey enabled when comparing magnitudes across groups. Independent limits can make small variation look as large as a substantial change. If different units or ranges require independent limits, label that choice clearly.

Does faceting fit a model?

A scatter facet displays observations; it does not estimate a regression line, a correlation, or a treatment effect. The toy data use different slopes to make the panels visually distinct, and the random seed makes this example reproducible.

Mathematical Context

Each panel displays the conditional observations {(xᵢ, yᵢ): gᵢ = g} for one group g. The synthetic response follows yᵢ = βg xᵢ + εᵢ with group slopes 0.5, 1.0 and 1.5. A common axis scale preserves the same mapping between numeric differences and distances on every panel.

\[ y_i=\beta_{g_i}x_i+\epsilon_i \]

Reproducibility

Executed with Python 3.12.14; numpy 2.5.4, pandas 3.0.6, matplotlib 3.11.2, seaborn 0.13.2. Automated checks confirm the stated output properties.

Primary documentation

Related guides