Seaborn for statistical plots
Seaborn is a high-level library built on Matplotlib. It takes a tidy pandas DataFrame, maps columns to x, y, colour and facets, and computes statistics (means, confidence intervals, density curves) for you. Because every seaborn plot draws on Matplotlib Axes, everything from the object-model lesson still applies.
Tidy data first
Seaborn expects long (tidy) data: one row per observation, one column per variable.
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
rng = np.random.default_rng(1)
n = 600
df = pd.DataFrame({
"city": rng.choice(["Bengaluru", "Ahmedabad", "Kolkata"], n),
"channel": rng.choice(["App", "Store"], n, p=[0.6, 0.4]),
"basket": rng.gamma(4, 180, n).round(), # order value in INR
})
df["items"] = (df["basket"] / 150 + rng.normal(0, 1, n)).clip(1).round()
If your data is wide (one column per month), convert it with df.melt(...) before plotting.
Axes-level vs figure-level functions
| Question | Axes-level | Figure-level |
|---|---|---|
| Distribution of one variable | histplot, kdeplot |
displot |
| Numeric vs category | boxplot, violinplot, barplot |
catplot |
| Two numeric variables | scatterplot, regplot |
relplot, lmplot |
Axes-level functions accept ax= so they fit into your own subplot grids. Figure-level functions create their own Figure and can split data into panels with col= and row=.
fig, axes = plt.subplots(1, 2, figsize=(11, 4))
sns.histplot(data=df, x="basket", hue="channel", element="step", ax=axes[0])
sns.boxplot(data=df, x="city", y="basket", ax=axes[1])
axes[1].set_ylabel("Basket value (INR)")
fig.tight_layout()
Statistics built in
sns.barplot plots the mean with a 95% confidence interval by default - not totals. Say so in your caption, or pass estimator="sum" and errorbar=None if you want totals.
sns.barplot(data=df, x="city", y="basket", hue="channel", errorbar=("ci", 95))
sns.regplot(data=df, x="items", y="basket") fits and draws a linear regression line with a confidence band - a quick visual check before formal modelling.
Facets for comparison
g = sns.displot(data=df, x="basket", col="city", kind="hist", height=3, aspect=1.2)
g.set_axis_labels("Basket value (INR)", "Orders")
g.savefig("basket_by_city.png", dpi=150)
Faceting shows each group on its own panel with shared axes, which is often clearer than overlapping colours.
Themes
sns.set_theme(style="whitegrid", context="talk") changes Matplotlib defaults globally - context scales fonts for paper, notebook, talk or poster. Call it once at the top of a notebook.
Common mistakes
- Passing wide data and wondering why
huedoes nothing. - Reading
barplotbars as totals when they are means. - Using a violin plot for tiny groups (under ~30 points); show the raw points with
stripplotinstead. - Trying
ax=on a figure-level function likerelplot- it is not supported.
Practice
Using the generated DataFrame, build a 1x3 figure: a KDE of basket value by channel, a violin plot of
basket value by city, and a regplot of items versus basket. Then use catplot with col="channel"
to compare cities, and write a one-line insight as the figure title.