Module 4 · Section 5 of 10
Lesson 4.4 - Seaborn for Statistical Plots
Target: ~9 min read - 20 min hands-on
Overview
Seaborn builds on matplotlib with higher-level statistical chart types: boxplots and violin plots for comparing distributions across categories, heatmaps for correlation matrices, and pairplots for scanning relationships across many variables. We'll visualize supplier-to-supplier variation in a measured component dimension.
Why This Matters (Engineering Context)
A boxplot comparing a measured property across suppliers or batches makes QA/QC variability immediately visible in a way a table of numbers doesn't - exactly the chart that supports (or challenges) a supplier's quality claim.
Code-Along
import seaborn as sns # statistical charts built on top of matplotlib
# Build a long-format DataFrame: one row per (supplier, batch) measurement
np.random.seed(15)
suppliers = ["Supplier A", "Supplier B", "Supplier C"]
means = {"Supplier A": 25.02, "Supplier B": 25.00, "Supplier C": 24.98}
stds = {"Supplier A": 0.020, "Supplier B": 0.045, "Supplier C": 0.015}
batch_rows = []
for sup in suppliers:
for batch in range(20):
batch_rows.append((sup, batch, round(np.random.normal(means[sup], stds[sup]), 3)))
parts_df = pd.DataFrame(batch_rows, columns=["supplier", "batch", "diameter_mm"])
# seaborn takes data=DataFrame + column names for x / y; it groups by x automatically
fig, axes = plt.subplots(1, 2, figsize=(12, 5))
sns.boxplot(data=parts_df, x="supplier", y="diameter_mm", ax=axes[0]) # box = quartiles
axes[0].axhline(25.00, color="red", linestyle="--", label="nominal") # horizontal reference line
axes[0].set_title("Component Diameter by Supplier (Boxplot)"); axes[0].legend()
sns.violinplot(data=parts_df, x="supplier", y="diameter_mm", ax=axes[1]) # violin = full density shape
axes[1].axhline(25.00, color="red", linestyle="--")
axes[1].set_title("Component Diameter by Supplier (Violin)")
plt.tight_layout(); plt.show()
# --- Heatmap of a correlation matrix ---
corr_df = df[["energy_kwh", "ambient_c"]].copy()
corr_df["day_of_year"] = df["date"].dt.dayofyear
fig, ax = plt.subplots(figsize=(5, 4))
# .corr() -> pairwise correlation table; annot=True prints the numbers in each cell
sns.heatmap(corr_df.corr(), annot=True, cmap="coolwarm", vmin=-1, vmax=1, ax=ax)
ax.set_title("Correlation Matrix")
plt.tight_layout(); plt.show()
# pairplot: a grid of scatter plots for every pair of numeric columns,
# with histograms on the diagonal; hue colours the points by a category
sns.pairplot(parts_df[["batch", "diameter_mm"]].assign(supplier=parts_df["supplier"]),
hue="supplier", height=2.2)
plt.show()
Run it: the boxplot and violin plot both show Supplier B with the widest spread
(largest std, 0.045 vs 0.020 and 0.015) - the violin additionally shows the shape of
that spread. The heatmap shows a mild positive correlation between energy_kwh and
day_of_year (the cooling-season pattern) and a stronger one between energy_kwh and
ambient_c. The pairplot renders a grid of scatter/histogram combinations, colored by
supplier.
Practice Exercises
- Add a 4th supplier with a mean of 24.90 mm (biased low) and re-run the boxplot - how obvious is the problem visually?
- Compute the exact correlation coefficient between
energy_kwhandambient_cwith.corr()and compare it to the heatmap. - Try
sns.stripplot()instead of boxplot/violin - what does showing every point add that the boxplot hides?
# Try the practice exercises here
Knowledge Check
- What does a violin plot show that a boxplot doesn't?
- What does a heatmap of a correlation matrix visualize?
- What is a pairplot useful for with several numeric variables?
Answer key
- The estimated shape (density) of the full distribution, not just quartiles
- The strength and direction of pairwise linear relationships, color-coded
- Quickly scanning scatter relationships and individual distributions across every pair at once
38 / 63 sections · Course home · Join the coaching cohort