Figure-Level Functions & Faceting
Axes-Level vs. Figure-Level
Axes-level functions (scatterplot, boxplot, histplot) draw onto a single existing Matplotlib axes — pass ax= to place one into a custom subplot grid. Figure-level functions (relplot, catplot, displot) manage their OWN entire figure and handle faceting automatically. Mixing the two without knowing which is which — e.g. trying to plug a figure-level function into an existing plt.subplots() axes — is a common source of "why do I have two figures" confusion.
Faceting
# One small scatter plot per distinct 'region' value, arranged in a grid
sns.relplot(data=df, x='month', y='sales', col='region', hue='product', kind='line')
# catplot — several categorical plot types via kind=, with the same faceting support
sns.catplot(data=df, x='day', y='total_bill', col='sex', kind='box')Overriding Defaults
# Defaults are a starting point, not a substitute for understanding the data.
# Override the aggregation/binning when it doesn't fit the actual dataset:
sns.lineplot(data=df, x='x', y='y', estimator='median', errorbar=('pi', 90))
sns.histplot(data=df, x='value', bins=50) # more/fewer bins than the auto defaultCombining with Matplotlib Subplots
fig, axes = plt.subplots(1, 2, figsize=(12, 5))
sns.boxplot(data=df, x='category', y='value', ax=axes[0]) # axes-level — fits fine
sns.histplot(data=df, x='value', ax=axes[1])
# A figure-level function (relplot/catplot/displot) does NOT accept ax= —
# it always creates its own figure.Keep your own version of these notes — editable, searchable, and organised by your stack.
Start free