Seaborn
Seaborn
Core Principle: Seaborn provides high-level dataset-oriented plotting abstractions that automatically map variables from tidy DataFrames to graphical aesthetics using Matplotlib as the underlying rendering engine.
Version at time of writing: 0.13.2 · import seaborn as sns
Architectural Model
Seaborn is a dataset-oriented interface to Matplotlib. You do not tell it what to draw; you tell it which columns map to which visual channels, and Seaborn automatically computes statistical transformations, legend mappings, color palettes, and axis annotations.
sns.scatterplot(data=df, x="log2fc", y="neglog10p", hue="significant", size="baseMean")
Three things happened there that would have been 15 lines of matplotlib: the hue column was mapped to colours and a legend was built, the size column was mapped to marker areas with its own legend, and both axes were labelled from the column names.
The price of that convenience: your data must be tidy (long form). Seaborn's contract is "one row per observation, one column per variable". If your data is wide, melt it first.
Axes-Level vs. Figure-Level Functions
Seaborn has two kinds of function and distinguishing them is essential:
| Axes-level | Figure-level | |
|---|---|---|
| Examples | scatterplot, boxplot, histplot, lineplot, heatmap |
relplot, catplot, displot, lmplot, pairplot, jointplot, clustermap |
| Draws into | an existing Axes you pass via ax= |
a Figure it creates and owns |
| Returns | the Axes |
a FacetGrid / JointGrid / ClusterGrid |
Accepts ax= |
yes | No: passing ax= raises a TypeError |
| Sizing | figsize on your plt.subplots |
height= and aspect= |
| Can facet | no | yes, via col= / row= |
Rule of thumb: axes-level when the plot is one panel in a figure you are composing; figure-level when you want faceting. See Figure-level vs Axes-level.
Computational Relevance in Biology
Common biological visualizations, such as condition-grouped expression boxplots, batch-stratified distributions, correlation matrices, faceted tissue panels, and hierarchically clustered heatmaps, are expressed concisely through Seaborn high-level interfaces. clustermap in particular does hierarchical clustering, dendrograms and the heatmap in a single call.
Seaborn also does the statistical work you would otherwise get subtly wrong: bootstrap confidence intervals on aggregated lines, kernel density estimates with sensible bandwidth, and regression fits with CI bands.
Core Reference Modules
Figure-level vs Axes-level · Statistical Estimation in seaborn · Faceting · seaborn Themes and Palettes · seaborn objects Interface
Because seaborn is matplotlib, these matter too: Figure and Axes · Colormaps and Color · Saving Figures · Axes Styling and Annotation
Applied Workflows
Applied - Heatmaps and Clustermaps · Applied - Differential Expression Volcano Plot · Applied - Quality Control Plots
Installation and Verification
pip install "seaborn>=0.13,<0.14"
python -c "import seaborn as sns; print(sns.__version__)"
Seaborn maintains an intentional long-term stability cycle, prioritizing backward compatibility and reliable statistical defaults across major Python releases.
Essential API Patterns
import seaborn as sns
sns.set_theme(style="whitegrid", context="paper", palette="colorblind")
sns.boxplot(data=long, x="condition", y="expression", hue="tissue")
sns.histplot(data=df, x="af", bins=50, log_scale=(True, False))
sns.scatterplot(data=df, x="pc1", y="pc2", hue="batch", style="sex")
sns.heatmap(corr, cmap="vlag", center=0, square=True)
sns.clustermap(mat, z_score=0, cmap="vlag", figsize=(8, 10))
g = sns.relplot(data=long, x="dose", y="response", col="gene", col_wrap=4, kind="line")
g.set_axis_labels("Dose (µM)", "Response")
g.savefig("facets.pdf")
Calling sns.set_theme() once at script initialization ensures consistent typographic and aesthetic defaults across both Seaborn and direct Matplotlib figures.
Matplotlib Integration Workflow
This is the workflow that makes seaborn genuinely powerful:
fig, ax = plt.subplots(figsize=(5, 4))
sns.scatterplot(data=df, x="log2fc", y="neglog10p", ax=ax)
ax.axvline(0, color="grey", lw=0.8) # matplotlib
for _, r in top_hits.iterrows(): # matplotlib
ax.annotate(r["gene"], (r["log2fc"], r["neglog10p"]))
fig.savefig("volcano.pdf", bbox_inches="tight")
For figure-level functions the handles are g.figure, g.axes (an ndarray), and g.axes_dict (keyed by facet value).
Common Pitfalls & Behavioral Edge Cases
- Passing
ax=to a figure-level function →TypeError. Use the axes-level twin (relplot→scatterplot/lineplot). - Passing wide data and getting a nonsense plot. Melt first.
- Not realising the error bars are bootstrap 95% CIs by default, not SD or SEM. Set
errorbar=explicitly in anything you publish. See Statistical Estimation in seaborn. sns.heatmapdoes not cluster;sns.clustermapdoes.- KDE plots on bounded data (proportions, allele frequencies) bleed past 0 and 1. Use
histplotor setclip=.
Related References
Matplotlib · Tidy Data · Pandas · Ecosystem Map