seaborn gets you 90% of the way; the last 10% (labels, layout, legends, highlights) is plain Matplotlib on the objects it returns.
Because seaborn draws with Matplotlib, everything from the Matplotlib lessons applies to its output:
- An axes-level call returns an
Axes: useax.set(xlabel=..., title=...), tick formatters,ax.annotate,ax.axhline. - A figure-level call returns a grid: loop over
g.axes.flat, or useg.figureforsuptitleand layout. - seaborn's legend is a normal Matplotlib legend:
ax.get_legend(),sns.move_legend(obj, loc, title=None, ncols=3, frameon=False). Moving it withsns.move_legendkeeps the handles that seaborn built, which re-callingax.legend()can lose.
Combining several seaborn plots in one custom figure is just passing different ax= values from plt.subplots or subplot_mosaic, then calling fig.savefig. layout="constrained" keeps legends and labels from overlapping.
Theme changes go through rcParams, so sns.set_theme affects pure Matplotlib charts too, and Matplotlib style sheets or rc_context affect seaborn. To use seaborn's style only for one figure, use with sns.axes_style("white"):.
seaborn adds artists in a known way: lines in ax.lines, bars in ax.patches, points in ax.collections. You can restyle a specific one afterwards, for example to highlight one bar, though relying on the exact order can break across versions; prefer parameters such as hue or palette when they exist.
Categorical axes place categories at 0, 1, 2 ...; use those positions to annotate.
Example
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
from matplotlib import ticker
import seaborn as sns
import pandas as pd
df = pd.DataFrame({"team": ["data", "web", "ops", "ml"],
"share": [0.31, 0.27, 0.12, 0.30]})
fig, ax = plt.subplots(figsize=(5, 3), layout="constrained")
sns.barplot(data=df, y="team", x="share", hue="team", legend=False,
order=df.sort_values("share", ascending=False)["team"],
palette={t: "C3" if t == "ml" else "0.7" for t in df.team}, ax=ax)
ax.xaxis.set_major_formatter(ticker.PercentFormatter(xmax=1))
for bars in ax.containers: # one container per hue level
ax.bar_label(bars, fmt="{:.0%}", padding=3)
ax.set(xlabel="Share of incidents", ylabel=None, title="Incidents by team")
sns.despine(left=True)
print([t.get_text() for t in ax.get_yticklabels()]) # ['data', 'ml', 'web', 'ops']
print(len(ax.containers)) # 4: one per hue level
fig.savefig("incidents.png")Remember
- seaborn returns Axes or grids; finish them with ordinary Matplotlib calls
- Use
sns.move_legendinstead of rebuilding seaborn legends - Compose several seaborn plots in one figure by passing
ax=
Watch out for
- Rebuilding the legend with
ax.legend()after a seaborn plot and losing the hue/size handles.