Lesson 05
relplot and Small Multiples
Split one chart into a grid of small multiples with sns.relplot, using col, row, and col_wrap, and learn how figure-level functions differ from axes-level ones.
One crowded chart is often clearer as several small ones that share the same axes. Seaborn calls these facets. sns.relplot draws the same scatter or line chart once per group and lays the panels out in a grid for you.
Figure-level versus axes-level
scatterplot and lineplot are axes-level: they draw into one Matplotlib Axes and return it. relplot is figure-level: it creates a whole figure and returns a FacetGrid that owns every panel. That is why relplot has no ax= argument.
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns
rng = np.random.default_rng(26)
study = pd.DataFrame({
"track": rng.choice(["Python", "Data", "Web"], 120),
"mode": rng.choice(["online", "classroom"], 120),
"week": rng.integers(1, 7, 120),
})
study["hours"] = (rng.uniform(1, 6, 120) + study["week"] * 0.8).round(1)
study["score"] = (35 + study["hours"] * 4.5 + rng.normal(0, 7, 120)).clip(0, 100).round()
g = sns.relplot(data=study, x="hours", y="score", kind="scatter")
plt.show()
print(type(g).__name__)
print(g.axes.shape)Output:
FacetGrid
(1, 1)One panel per group with col
col="track" makes a column of panels, one per track. Every panel shares the x and y axes, so comparing positions across panels is fair.
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns
rng = np.random.default_rng(26)
study = pd.DataFrame({
"track": rng.choice(["Python", "Data", "Web"], 120),
"mode": rng.choice(["online", "classroom"], 120),
"week": rng.integers(1, 7, 120),
})
study["hours"] = (rng.uniform(1, 6, 120) + study["week"] * 0.8).round(1)
study["score"] = (35 + study["hours"] * 4.5 + rng.normal(0, 7, 120)).clip(0, 100).round()
g = sns.relplot(data=study, x="hours", y="score", col="track", hue="track", legend=False)
plt.show()
print(g.axes.shape)
print([ax.get_title() for ax in g.axes.flat])Output:
(1, 3)
['track = Web', 'track = Data', 'track = Python']Rows and columns together
Add row= for a second grouping. Two modes by three tracks gives a two by three grid. height sets each panel's height in inches and aspect its width relative to that height.
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns
rng = np.random.default_rng(26)
study = pd.DataFrame({
"track": rng.choice(["Python", "Data", "Web"], 120),
"mode": rng.choice(["online", "classroom"], 120),
"week": rng.integers(1, 7, 120),
})
study["hours"] = (rng.uniform(1, 6, 120) + study["week"] * 0.8).round(1)
study["score"] = (35 + study["hours"] * 4.5 + rng.normal(0, 7, 120)).clip(0, 100).round()
g = sns.relplot(data=study, x="hours", y="score", row="mode", col="track",
height=2.6, aspect=1.1)
plt.show()
print(g.axes.shape)Output:
(2, 3)Wrap a long row
Six weeks in one row would be squashed. col_wrap=3 starts a new row after three panels. kind="line" switches every panel to a line chart.
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns
rng = np.random.default_rng(26)
study = pd.DataFrame({
"track": rng.choice(["Python", "Data", "Web"], 120),
"mode": rng.choice(["online", "classroom"], 120),
"week": rng.integers(1, 7, 120),
})
study["hours"] = (rng.uniform(1, 6, 120) + study["week"] * 0.8).round(1)
study["score"] = (35 + study["hours"] * 4.5 + rng.normal(0, 7, 120)).clip(0, 100).round()
g = sns.relplot(data=study, x="hours", y="score", col="week", col_wrap=3,
height=2.4, s=20)
g.set_titles("week {col_name}")
plt.show()
print(len(g.axes.flat))Output:
6Label the whole grid
Because a FacetGrid owns many panels, it has its own labelling methods: set_axis_labels for every axis at once, set_titles with {col_name} and {row_name} placeholders, and figure.suptitle for one title over everything.
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns
rng = np.random.default_rng(26)
study = pd.DataFrame({
"track": rng.choice(["Python", "Data", "Web"], 120),
"mode": rng.choice(["online", "classroom"], 120),
"week": rng.integers(1, 7, 120),
})
study["hours"] = (rng.uniform(1, 6, 120) + study["week"] * 0.8).round(1)
study["score"] = (35 + study["hours"] * 4.5 + rng.normal(0, 7, 120)).clip(0, 100).round()
g = sns.relplot(data=study, x="week", y="score", col="mode", kind="line", height=3)
g.set_axis_labels("week", "quiz score")
g.set_titles("{col_name} learners")
g.figure.suptitle("Scores rise as the weeks go on", y=1.05)
plt.show()
print([ax.get_title() for ax in g.axes.flat])Output:
['classroom learners', 'online learners']Key takeaways
-
Axes-level functions draw into one Axes; figure-level ones build a whole figure
-
relplot returns a FacetGrid and has no ax= argument
-
col=, row=, and col_wrap= split the chart into small multiples
-
Use set_axis_labels, set_titles, and figure.suptitle on the grid
-
Next: Histograms with histplot
-
Previous: Line Plots and Error Bands
Loading playground…
Check your understanding
relplot and Small Multiples Quiz
What does relplot return?
1 / 10