Data Science

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

JrCodex·6 min read

Jr Codex Data Science Notes

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


Table of Contents

  1. Matplotlib's Two Interfaces
  2. Figure & Axes — the Core Concepts
  3. The Essential Plot Types
  4. Styling a Plot
  5. Subplots — Multiple Charts in One Figure
  6. Saving Figures
  7. 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 TypeFunctionAnswers
Lineax.plot()How does this change over time/sequence?
Barax.bar()How do categories compare?
Scatterax.scatter()How do two numeric variables relate?
Histogramax.hist()What's the shape of one variable's distribution?
Box plotax.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
ParameterPurpose
dpi=300Resolution 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=300 for raster formats destined for print, or use PDF/SVG for infinitely scalable vector output.

Concept Check

  1. What's the difference between a Figure and an Axes object in matplotlib?
  2. When would you reach for the object-oriented interface instead of plain plt.plot()?
  3. Why would you save a chart as .svg or .pdf instead of .png for a printed report?

Next Chapter

Chapter 3: Seaborn for Statistical Plots


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