Data Visualization
Matplotlib Fundamentals
Matplotlib supports two ways of building a plot — recognizing both matters, because you'll see each style in different real-world code (including throughout Mod
Jr Codex Data Science Notes
Level: Intermediate Prerequisites: Chapter 1 Time to complete: ~25 minutes
Table of Contents
- Matplotlib's Two Interfaces
- Figure & Axes — the Core Concepts
- The Essential Plot Types
- Styling a Plot
- Subplots — Multiple Charts in One Figure
- Saving Figures
- Summary & Next Steps
1. Matplotlib's Two Interfaces
Matplotlib supports two ways of building a plot — recognizing both matters, because you'll see each style in different real-world code (including throughout Modules 1-3 of these notes).
import matplotlib.pyplot as plt
# Interface 1: pyplot (state-based) — quick, implicit, good for one-off plots
plt.plot([1, 2, 3], [4, 5, 6])
plt.title("Quick Plot")
plt.show()
# Interface 2: object-oriented (explicit) — more control, better for multi-panel figures
fig, ax = plt.subplots()
ax.plot([1, 2, 3], [4, 5, 6])
ax.set_title("Object-Oriented Plot")
plt.show()Which to Use
─────────────────────────────────────────
pyplot (plt.___) → fine for quick, single EDA plots (Module 3's style)
object-oriented → preferred for anything with MULTIPLE subplots,
(fig, ax = ...) or reusable plotting functions — more predictable
and easier to compose
─────────────────────────────────────────
This chapter uses the object-oriented style going forward — it scales better once you're building anything beyond a single throwaway chart.
2. Figure & Axes — the Core Concepts
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(8, 5))Figure vs Axes
─────────────────────────────────────────
Figure: the ENTIRE window/canvas — can contain MULTIPLE axes (Section 5)
Axes: ONE individual plot within the figure — has its own
x-axis, y-axis, title, data
(NOTE: "Axes" ≠ "axis" — Axes is the whole plot object,
axis refers to just the x or y line)
─────────────────────────────────────────
fig, ax = plt.subplots(figsize=(8, 5)) # figsize is in INCHES (width, height)
ax.plot([1, 2, 3, 4], [10, 20, 25, 30])
ax.set_xlabel("X Axis Label")
ax.set_ylabel("Y Axis Label")
ax.set_title("Figure and Axes Example")
plt.show()3. The Essential Plot Types
import matplotlib.pyplot as plt
import numpy as np
fig, axes = plt.subplots(2, 2, figsize=(10, 8))
# Line plot — trends over a continuous variable (usually time)
x = np.arange(1, 13)
y = np.random.randint(40, 100, 12)
axes[0, 0].plot(x, y, marker="o")
axes[0, 0].set_title("Line Plot")
# Bar chart — comparing values across categories
categories = ["A", "B", "C", "D"]
values = [23, 45, 12, 38]
axes[0, 1].bar(categories, values, color="steelblue")
axes[0, 1].set_title("Bar Chart")
# Scatter plot — relationship between two numeric variables (Module 3, Ch.3)
x_scatter = np.random.normal(50, 10, 100)
y_scatter = x_scatter * 1.5 + np.random.normal(0, 10, 100)
axes[1, 0].scatter(x_scatter, y_scatter, alpha=0.5)
axes[1, 0].set_title("Scatter Plot")
# Histogram — distribution of a single numeric variable (Module 3, Ch.2)
data = np.random.normal(100, 15, 1000)
axes[1, 1].hist(data, bins=30, edgecolor="black")
axes[1, 1].set_title("Histogram")
plt.tight_layout()
plt.show()| Plot Type | Function | Answers |
|---|---|---|
| Line | ax.plot() | How does this change over time/sequence? |
| Bar | ax.bar() | How do categories compare? |
| Scatter | ax.scatter() | How do two numeric variables relate? |
| Histogram | ax.hist() | What's the shape of one variable's distribution? |
| Box plot | ax.boxplot() | Spread, median, and outliers (Module 1, Ch.1 & Module 3, Ch.4) |
4. Styling a Plot
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots(figsize=(8, 5))
x = np.arange(1, 13)
revenue = [45, 52, 48, 61, 58, 65, 70, 68, 72, 80, 78, 85]
target = [50] * 12
ax.plot(x, revenue, color="steelblue", linewidth=2, marker="o", label="Actual Revenue")
ax.plot(x, target, color="gray", linewidth=1, linestyle="--", label="Target")
ax.set_xlabel("Month")
ax.set_ylabel("Revenue ($k)")
ax.set_title("Monthly Revenue vs Target", fontsize=14, fontweight="bold")
ax.legend(loc="upper left")
# Applying Chapter 1's data-ink ratio principle
ax.spines["top"].set_visible(False)
ax.spines["right"].set_visible(False)
ax.grid(axis="y", alpha=0.3)
plt.show()Key Styling Parameters
─────────────────────────────────────────
color / linewidth / linestyle → visual appearance of a line
marker → shape at each data point ('o', 's', '^', ...)
label + ax.legend() → identifies multiple series on one chart
fontsize / fontweight → text emphasis for titles/labels
─────────────────────────────────────────
5. Subplots — Multiple Charts in One Figure
import matplotlib.pyplot as plt
import numpy as np
# A 2x2 grid — directly connects to Module 3's EDA habit of viewing several angles at once
fig, axes = plt.subplots(2, 2, figsize=(10, 8))
data = np.random.normal(100, 20, 1000)
axes[0, 0].hist(data, bins=30)
axes[0, 0].set_title("Distribution")
axes[0, 1].boxplot(data)
axes[0, 1].set_title("Box Plot")
axes[1, 0].plot(np.cumsum(np.random.randn(100)))
axes[1, 0].set_title("Random Walk")
axes[1, 1].scatter(np.random.rand(50), np.random.rand(50))
axes[1, 1].set_title("Random Scatter")
fig.suptitle("A 2x2 Grid of Related Views", fontsize=14)
plt.tight_layout()
plt.show()Indexing axes in a Grid
─────────────────────────────────────────
fig, axes = plt.subplots(2, 2)
axes[0, 0] → top-left axes[0, 1] → top-right
axes[1, 0] → bottom-left axes[1, 1] → bottom-right
(this is the same [row, column] indexing as a NumPy 2D array —
Python Notes' NumPy Primer)
─────────────────────────────────────────
plt.tight_layout() automatically adjusts spacing so titles/labels don't overlap between subplots — worth calling by habit on any multi-panel figure.
6. Saving Figures
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(8, 5))
ax.plot([1, 2, 3], [4, 5, 6])
ax.set_title("A Chart Worth Saving")
fig.savefig("revenue_chart.png", dpi=300, bbox_inches="tight")
fig.savefig("revenue_chart.pdf") # vector format — scales without quality loss, good for print/reports
fig.savefig("revenue_chart.svg") # also vector — good for web/editable graphics| Parameter | Purpose |
|---|---|
dpi=300 | Resolution for raster formats (PNG/JPG) — 300 is standard for print quality |
bbox_inches="tight" | Trims excess whitespace around the figure |
Format (.png, .pdf, .svg) | PNG/JPG for web/screens; PDF/SVG (vector) for print or infinite zoom without pixelation |
7. Summary & Next Steps
Key Takeaways
- Matplotlib has two interfaces — pyplot for quick single plots, object-oriented (
fig, ax) for anything more structured; this curriculum prefers the object-oriented style going forward. - A Figure is the overall canvas; Axes are individual plots within it —
fig, axes = plt.subplots(rows, cols)creates a grid, indexed like a NumPy array. - Line, bar, scatter, and histogram cover the vast majority of everyday plotting needs, each answering a different kind of question (Chapter 1).
- Apply the data-ink principle directly through styling: remove unnecessary spines/gridlines, use
label+legend()for multiple series. - Save with
dpi=300for raster formats destined for print, or use PDF/SVG for infinitely scalable vector output.
Concept Check
- What's the difference between a Figure and an Axes object in matplotlib?
- When would you reach for the object-oriented interface instead of plain
plt.plot()? - Why would you save a chart as
.svgor.pdfinstead of.pngfor a printed report?
Next Chapter
→ Chapter 3: Seaborn for Statistical Plots
Jr Codex — 1-on-1 Personalized Coaching | Back to Module Index