43 · Matplotlib basics: plot, scatter, bar, hist
Matplotlib is the plotting foundation everything else builds on — from a quick loss curve during training to a polished figure for a paper. Line plots, scatter charts, bar charts, histograms, and the object-oriented `fig, ax` interface that scales.
Matplotlib exposes **two interfaces**: an implicit state-machine API (`plt.plot(...)`, `plt.show()`) and an explicit object-oriented API (`fig, ax = plt.subplots(); ax.plot(...)`). They produce identical output, but the OO form wins for any code that lasts longer than a REPL session — you always know which axes you're drawing on, you can pass `ax` objects between functions, and subplot grids become trivial. Every serious ML codebase uses the OO API.
Without this:
Without matplotlib fundamentals, you can't inspect what your model is doing: no loss curves, no decision boundary plots, no distribution checks. You'll spend hours debugging numerically what you could see visually in five seconds.
Matplotlib is the foundational plotting library for Python's scientific stack. NumPy gives you the numbers; pandas gives you the table; matplotlib turns both into pictures. Nearly every other visualization library — Seaborn, Plotly, pandas .plot() — is a wrapper around matplotlib under the hood.
The universal import alias is import matplotlib.pyplot as plt. The pyplot module is the part you'll actually use in almost every script.
Matplotlib has two ways to draw the same chart:
- State-machine / pyplot interface —
plt.plot(x, y),plt.title(...),plt.show(). Quick for one-off interactive use, but fragile when you have multiple subplots or need to pass plot objects around. - Object-oriented (OO) interface —
fig, ax = plt.subplots(); ax.plot(x, y); ax.set_title(...). Explicit:figis the whole canvas,axis a single plot panel. Preferred in any code that other humans (or future you) will read.
This lesson covers the four core chart types plus the OO interface. Next lesson covers customization (labels, legends, styles, saving at publication quality).
Python (in browser)
`np.linspace(start, stop, n)` produces `n` evenly spaced points — perfect for function plots. `plt.savefig` writes the figure to disk; `plt.close()` frees memory. We use `bbox_inches='tight'` so axis labels are never clipped.
Python runs entirely in your browser via Pyodide (~6 MB on first Run, cached after).
Python (in browser)
`plt.scatter` accepts arrays of x/y coordinates and optionally a `c=` color. Setting `alpha=0.6` makes overlapping points visible. The two-cluster pattern here is what a linearly separable dataset looks like — a straight decision boundary can split them.
Python runs entirely in your browser via Pyodide (~6 MB on first Run, cached after).
Python (in browser)
`plt.subplots(rows, cols)` returns a `(fig, axes)` tuple. `axes` is a 2D array for grids larger than 1×1. `fig.tight_layout()` automatically adjusts padding so subplot titles and labels don't overlap — call it before every `savefig`.
Python runs entirely in your browser via Pyodide (~6 MB on first Run, cached after).
Always pass `dpi` and `bbox_inches='tight'`. The defaults (72 dpi, no crop) produce blurry, clipped figures.
What is the key behavioral difference between `plt.plot(x, y)` and `plt.scatter(x, y)`?
- Import as `import matplotlib.pyplot as plt` — the alias `plt` is universal.
- Use `plt.savefig('/tmp/plot.png', dpi=150, bbox_inches='tight')` instead of `plt.show()` in scripts and notebooks that run headlessly.
- Prefer the OO interface: `fig, ax = plt.subplots()` then `ax.plot(...)` — it scales to subplots and is easier to test.
- `plt.subplots(rows, cols)` returns a `(fig, axes)` pair; iterate over `axes.flat` to loop over all panels.
Every training run produces a loss curve — `ax.plot(epochs, train_loss); ax.plot(epochs, val_loss)`. Scatter plots of two features colored by class reveal separability before you train a single model. Histograms of a feature, plotted per class, expose distribution shift between train and test sets — one of the most common reasons a model fails in production.
If you remove it: Without matplotlib you debug ML training blind — you can only inspect scalar summaries, not the shape of loss curves, the spread of weight distributions, or the clustering structure of embeddings. Visual debugging catches problems in seconds that numeric logs miss for hours.