Data Visualization with Matplotlib and Seaborn
A wall of numbers hides its patterns; a picture reveals them. Matplotlib is the full-control canvas and brushes; Seaborn is the pre-stocked paint-by-numbers kit built on top of it. Together they turn data into EDA insight and model-report figures.
Seaborn Sits on Matplotlib
Seaborn provides high-level statistical plots that internally use the Matplotlib figure/axes objects, so you can always drop down to Matplotlib for fine control.
01.The Problem: A Wall of Numbers Hides Its Patterns
You have 10,000 numbers.
You can print them. You can compute the mean. But
does the distribution have two peaks?
does the error grow as predictions get bigger?
You simply cannot see that in a table.
So the question becomes
How do I turn numbers into pictures — both to find patterns myself (exploratory data analysis, EDA) and to show them in a report?
Python gives you two main tools for this: Matplotlib and Seaborn.
Keep this analogy in mind: Matplotlib is the blank canvas, brushes and paints — you control every stroke. Seaborn is a paint-by-numbers kit for common charts — you point at your data, and it paints a clean picture automatically.
02.Matplotlib in Plain Words: A Figure Holds Axes
Every Matplotlib plot follows one structure:
A Figure is the window (the picture frame). Axes are the individual plots inside it (each canvas on the frame).
- Create them once:
fig, ax = plt.subplots(). - Then draw on the axes:
ax.plot,ax.hist,ax.scatterand so on. - Annotate them:
ax.set_xlabel,ax.set_title.
This object-oriented style — create a figure and axes, then draw on the axes — is clearer and more scalable than the older pyplot state-machine style (where you call bare plt.plot and hope it targets the right canvas), especially for subplots.
A notebook line at the top, %matplotlib inline, renders plots directly in the cell output.
Tiny worked example: plotting a training loss over 4 epochs, from the code below — epochs [1, 2, 3, 4], losses [10, 20, 25, 18]:
codeloss 25 | * 20 | * * 15 | 10 | * +--+--+--+---> epoch 1 2 3 4
One call, ax.plot([1,2,3,4], [10,20,25,18]), produced that line. Your eyes instantly see the dip at epoch 4 — no table could show that this fast.
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(6, 4))
ax.plot([1, 2, 3, 4], [10, 20, 25, 18], marker="o")
ax.set_xlabel("epoch"); ax.set_ylabel("loss")
ax.set_title("Training loss")
plt.tight_layout(); plt.savefig("loss.png")03.Visual Intuition: The Frame and Its Canvases
Here is the Figure/Axes nesting, drawn as ASCII:
code+------ fig (Figure: the whole window) -------+ | +--- ax (Axes) ---+ +--- ax (Axes) ---+ | | | line plot | | histogram | | | | | | | | | +-----------------+ +-----------------+ | | title / labels live per-axes | +----------------------------------------------+
- You ask for a frame with 2 canvases:
fig, axes = plt.subplots(1, 2). - You paint on each canvas separately:
axes[0].plot(...),axes[1].hist(...). - Everything on a canvas — lines, labels, ticks — is an object you can reach in and change. That is the "pixel-level control" Matplotlib is known for.
04.Seaborn: The Paint-By-Numbers Kit on Top
Seaborn wraps Matplotlib with sensible defaults and a declarative API: you pass a DataFrame and column names, and it handles grouping, confidence intervals, color palettes and legends.
It excels at the statistical charts you reach for during EDA — distributions, relationships across categories, correlation heatmaps.
The mechanics:
- Call
sns.set_theme()once to apply its clean styling. - Use figure-level functions like
displot,relplotandcatplot(they can build multi-panel grids for you). - Or axes-level ones like
histplot,scatterplotandboxplot(they draw onto an Axes you control).
Tiny worked example — bill amounts [10, 12, 12, 15, 20, 30] as a histogram with bins of width 10:
codecount 4 | ██ 3 | ██ 2 | ██ 1 | ██ ██ ██ +-------------- 10 20 30 (total_bill bins)
The first bin (10–20) holds 10, 12, 12 and 15 → a bar of height 4. The 20–30 bin holds only 20, and the last holds 30 → bars of height 1.
Seaborn chose the bins, drew the bars and adds a smooth density curve (kde=True) that reveals shape, skew and how many peaks the data has.
import seaborn as sns
sns.set_theme()
tips = sns.load_dataset("tips")
sns.histplot(tips["total_bill"], kde=True)
sns.boxplot(data=tips, x="day", y="total_bill", hue="sex")
sns.heatmap(tips.corr(numeric_only=True), annot=True)05.Choosing the Right Chart
The goal dictates the chart, not the other way around.
- Distribution questions → histograms, KDE curves and violin plots.
- Relationship between two numeric variables → scatter plots and line plots.
- Comparison across groups → bar and box plots.
- Correlation matrix → heatmaps.
For a model-report figure, prefer the honest, high-encoding charts (scatter, line, bar) over pie charts or 3-D effects — a 3-D bar distorts how tall the bar looks, and a pie wastes your readers' attention.
06.Combining Both for Real Reports — and Why AI Cares
In practice you start with Seaborn for speed and drop to Matplotlib for the last 20 percent: adding reference lines, customizing ticks, arranging subplots, or exporting at a fixed DPI for a slide.
Because Seaborn returns the underlying Matplotlib axes, the two interoperate seamlessly in the same figure. Back to the studio analogy: the paint-by-numbers kit and the loose brushes both paint on the same canvas — Seaborn lays down the base picture, and Matplotlib adds the fine details.
Why AI cares — these are the recurring figures of every ML workflow:
- Training curves (loss vs epoch) — a Matplotlib line plot.
- Feature distributions before modeling — a Seaborn
histplot/displot. - Predicted vs actual scatter with a y=x reference line — Seaborn for the dots, Matplotlib for the line (see below).
- Correlation heatmaps for feature selection, and confusion matrices for classifiers.
fig, ax = plt.subplots()
sns.scatterplot(data=df, x="predicted", y="actual", ax=ax)
ax.plot([0, 1], [0, 1], "r--") # Matplotlib y=x line
ax.set_xlim(0, 1); ax.set_ylim(0, 1)
plt.show()Architectural Trade-offs & Production Realities
Architectural Advantages
- Matplotlib gives pixel-level control over every figure element.
- Seaborn produces publication-quality statistical plots in one line.
- Seaborn is DataFrame-native: pass column names, skip manual loops.
Trade-offs & Constraints
- Matplotlib defaults look dated and require boilerplate for styling.
- Seaborn abstractions can be hard to customize deeply.
- Both are static; interactive web dashboards need Plotly/Bokeh.
Grandmaster notebooks open with Seaborn pairplots, correlation heatmaps and target-distribution plots to justify feature choices, then fine-tune specific Matplotlib axes for the final published figure.
Staff+ Engineering Takeaways
- Matplotlib plots live in Figure/Axes objects; prefer the object-oriented style.
- Seaborn builds on Matplotlib and is DataFrame-aware with strong statistical defaults.
- Match the chart to the question: distribution, relationship, comparison, or correlation.
- The two interoperate because Seaborn returns Matplotlib axes.
- Label axes, avoid misleading scales, and export at fixed DPI for reports.
Topic Knowledge Check
Exercise 1 of 3 • Test your architectural comprehension.
What is the relationship between Seaborn and Matplotlib?
How clear and actionable was this distributed systems breakdown?