Data Science

Data Visualization

Seaborn for Statistical Plots

"region": ["North", "South", "East", "West"] * 25,

JrCodex·7 min read

Jr Codex Data Science Notes

Level: Intermediate Prerequisites: Chapter 2 Time to complete: ~25 minutes


Table of Contents

  1. Why Seaborn on Top of Matplotlib?
  2. Distribution Plots
  3. Categorical Plots
  4. Relationship Plots
  5. The Pair Plot
  6. The Heatmap, Properly Styled
  7. Seaborn Themes
  8. Summary & Next Steps

1. Why Seaborn on Top of Matplotlib?

Seaborn is built directly on matplotlib (Chapter 2) but is specifically designed for statistical visualization — it works natively with pandas DataFrames, handles grouping/coloring by category automatically, and applies more polished default styling out of the box.

import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
 
df = pd.DataFrame({
    "region": ["North", "South", "East", "West"] * 25,
    "spend": [100 + i * 2 for i in range(100)],
})
 
# The same bar chart in matplotlib takes more manual setup than in seaborn
sns.barplot(data=df, x="region", y="spend", errorbar="sd")      # includes error bars automatically
plt.title("Average Spend by Region (with std dev)")

Rule of thumb: reach for seaborn first when the plot is fundamentally statistical (distributions, categorical comparisons, correlations); drop to raw matplotlib (Chapter 2) when you need fine, custom control over a specific visual element seaborn doesn't expose directly.


2. Distribution Plots

Seaborn's distribution tools extend Module 3's histogram/box plot habits with more statistical nuance built in.

import seaborn as sns
import matplotlib.pyplot as plt
import numpy as np
 
data = np.random.normal(100, 15, 1000)
 
fig, axes = plt.subplots(1, 3, figsize=(15, 4))
 
# Histogram with an overlaid density curve (KDE)
sns.histplot(data, kde=True, ax=axes[0])
axes[0].set_title("Histogram + KDE")
 
# KDE alone — a smoothed estimate of the distribution's shape
sns.kdeplot(data, fill=True, ax=axes[1])
axes[1].set_title("KDE Plot")
 
# Box plot, seaborn style
sns.boxplot(y=data, ax=axes[2])
axes[2].set_title("Box Plot")
KDE (Kernel Density Estimate) — What It Adds
─────────────────────────────────────────
  A histogram's shape depends on bin width choice (Module 3, Ch.2).
  A KDE smooths this into a continuous curve, giving a cleaner
  sense of the underlying distribution's shape without that
  bin-width sensitivity.
─────────────────────────────────────────

3. Categorical Plots

Seaborn's categorical plots are the direct successor to Module 3, Chapter 3's grouped box plots — with more variety in how the comparison is shown.

import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
 
df = pd.DataFrame({
    "region": np.random.choice(["North", "South", "East", "West"], 500),
    "spend": np.random.gamma(2, 100, 500),      # naturally right-skewed, like real spend data
})
 
fig, axes = plt.subplots(1, 3, figsize=(15, 4))
 
# Box plot — five-number summary per category (Module 1, Ch.1)
sns.boxplot(data=df, x="region", y="spend", ax=axes[0])
axes[0].set_title("Box Plot by Region")
 
# Violin plot — box plot + KDE combined, shows the FULL distribution shape per category
sns.violinplot(data=df, x="region", y="spend", ax=axes[1])
axes[1].set_title("Violin Plot by Region")
 
# Strip/swarm plot — shows EVERY individual data point, good for smaller datasets
sns.stripplot(data=df, x="region", y="spend", alpha=0.3, ax=axes[2])
axes[2].set_title("Strip Plot by Region")
Box vs Violin vs Strip — When to Use Which
─────────────────────────────────────────
  Box plot:    compact, standard, good default for MOST comparisons
  Violin plot:  reveals BIMODAL or unusual shapes a box plot would hide
                (directly connects to Module 3, Ch.2's shape-recognition skill)
  Strip/swarm:   best for SMALL datasets where seeing every raw point matters
                  (gets cluttered/unreadable past a few hundred points)
─────────────────────────────────────────

4. Relationship Plots

import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
 
df = pd.DataFrame({
    "age": np.random.randint(20, 65, 300),
    "income": np.random.normal(60000, 20000, 300),
    "region": np.random.choice(["North", "South"], 300),
})
df["income"] = df["income"] + df["age"] * 300      # add a real relationship
 
# Scatter plot with a fitted regression line and confidence band — one line of code
sns.regplot(data=df, x="age", y="income")
plt.title("Age vs Income, with Linear Fit")
# scatterplot with color-coding by a THIRD variable — directly builds on
# Module 3, Chapter 3's multivariate analysis
sns.scatterplot(data=df, x="age", y="income", hue="region", style="region")
plt.title("Age vs Income, by Region")

sns.regplot's shaded band around the fitted line is a confidence interval — a visual representation of the uncertainty in that fitted relationship, connecting directly back to Module 1's sampling and hypothesis testing chapters.


5. The Pair Plot

sns.pairplot generates a full grid of scatter plots (every numeric column against every other) plus histograms on the diagonal — an extremely efficient first look at a new dataset's relationships, extending Module 3, Chapter 1's "first contact" habit.

import seaborn as sns
import pandas as pd
import numpy as np
 
df = pd.DataFrame({
    "age": np.random.randint(20, 65, 200),
    "income": np.random.normal(60000, 20000, 200),
    "spend": np.random.normal(300, 100, 200),
    "region": np.random.choice(["North", "South"], 200),
})
 
sns.pairplot(df, hue="region", diag_kind="kde")
Reading a Pair Plot
─────────────────────────────────────────
  Diagonal:      each variable's own distribution (KDE or histogram)
  Off-diagonal:   scatter plot of EVERY pair of numeric variables
  hue="region":    each point colored by category — reveals whether
                     relationships DIFFER by group (Module 3's
                     multivariate/Simpson's Paradox concern)
─────────────────────────────────────────

Practical tip: pairplot gets slow and visually cluttered past ~6-8 numeric columns — for larger datasets, select a focused subset of the most relevant columns first.


6. The Heatmap, Properly Styled

Extending Module 3, Chapter 3's correlation heatmap with better default styling:

import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
 
np.random.seed(0)
df = pd.DataFrame(np.random.randn(200, 5), columns=["A", "B", "C", "D", "E"])
df["B"] = df["A"] * 0.8 + np.random.randn(200) * 0.3      # force a real correlation
 
corr = df.corr()
 
plt.figure(figsize=(7, 6))
sns.heatmap(
    corr,
    annot=True,           # print the actual correlation VALUE in each cell
    fmt=".2f",              # 2 decimal places
    cmap="coolwarm",          # diverging color scale — blue (negative) to red (positive)
    center=0,                   # ensures 0 correlation maps to the MIDDLE of the color scale
    square=True,
    linewidths=0.5,
)
plt.title("Correlation Heatmap")

center=0 matters: without it, a diverging colormap can visually mislead by not centering the "neutral" color exactly on zero correlation — a subtle but important correctness detail directly tied to Chapter 1's "color should encode meaning accurately" principle.


7. Seaborn Themes

import seaborn as sns
 
sns.set_theme(style="whitegrid")     # sets a consistent look for ALL subsequent plots in the session
 
# Available built-in styles: "darkgrid", "whitegrid", "dark", "white", "ticks"
import seaborn as sns
import matplotlib.pyplot as plt
 
sns.set_theme(style="whitegrid", palette="deep", font_scale=1.1)
 
# Every plot from this point on in the script/notebook uses this consistent styling —
# a one-line way to apply Chapter 1's design principles across an entire report or notebook

8. Summary & Next Steps

Key Takeaways

  • Seaborn builds on matplotlib specifically for statistical visualization — it works directly with DataFrames and handles category-based grouping/coloring automatically.
  • histplot/kdeplot extend Module 3's distribution analysis; boxplot/violinplot/stripplot extend its categorical comparisons, each with different trade-offs for dataset size and shape visibility.
  • regplot and scatterplot with hue= extend Module 3's bivariate/multivariate analysis, adding fitted trend lines and confidence bands.
  • pairplot is the fastest way to see every numeric-numeric relationship at once; heatmap with center=0 is the properly-styled version of a correlation matrix.

Concept Check

  1. When would a violin plot reveal something a standard box plot would hide?
  2. Why does center=0 matter when building a correlation heatmap with a diverging colormap?
  3. What's a practical limitation of sns.pairplot on datasets with many numeric columns?

Next Chapter

Chapter 4: Interactive Visualization with Plotly


Jr Codex — 1-on-1 Personalized Coaching | Back to Module Index