44 · Customization: labels, legends, styles
A correct plot and a readable plot are not the same thing. Titles, axis labels, legends, grids, color choices, and consistent styles are what separate exploratory sketches from figures you'd put in a paper or slide deck.
Every element of a matplotlib figure is an **Artist** object with settable properties. Axis labels (`ax.set_xlabel`), title (`ax.set_title`), tick marks (`ax.set_xticks`), grid lines (`ax.grid`), and legend (`ax.legend`) are all independent layers you add to an `Axes` object. The OO interface makes this layering explicit: you hold a reference to `ax` and call methods on it in any order you like before saving.
Without this:
An unlabeled loss curve is almost useless for communication — you don't know which line is train vs. validation, what the axes represent, or what scale you're on. Every figure you share with a collaborator or manager needs at minimum: a title, labeled axes, and a legend if there are multiple lines.
Once you can draw a chart, the next skill is making it readable. This lesson covers the full customization toolkit for matplotlib's OO interface:
- Titles & axis labels —
ax.set_title('...'),ax.set_xlabel('...'),ax.set_ylabel('...') - Legends — add
label='...'to each.plot()call, then callax.legend(loc='upper right')to render it - Axis limits —
ax.set_xlim(lo, hi),ax.set_ylim(lo, hi)to control the visible range - Ticks —
ax.set_xticks([...]),ax.set_xticklabels([...])for custom tick positions and labels - Grid —
ax.grid(True, alpha=0.3)adds a subtle reference grid without dominating the data - Colors & linestyles —
color=,linestyle='--',linewidth=,marker='o' - Styles —
plt.style.use('ggplot')applies a global theme before any drawing tight_layout()— fixes label overlap automatically; call it before everysavefig
The canonical ML use case for all of this is the train vs. validation loss curve — the single most important diagnostic plot in deep learning.
Python (in browser)
A `label=` argument on each `.plot()` call registers that line with the legend. `ax.legend()` renders all registered labels. Without `label=`, `ax.legend()` produces an empty legend box — a common mistake.
Python runs entirely in your browser via Pyodide (~6 MB on first Run, cached after).
Python (in browser)
`axes[row, col]` indexes into a 2D subplot grid. `fig.suptitle()` adds a figure-level title above all subplots. `ax.fill_between(x, y1, y2)` fills the area between two curves — great for showing confidence bands or gaps. `ax.axhline(0)` draws a horizontal reference line.
Python runs entirely in your browser via Pyodide (~6 MB on first Run, cached after).
Styles must be set before drawing. `seaborn-v0_8` is the current name for the old `seaborn` style string — the rename happened in matplotlib 3.6 when seaborn updated its own default theme.
You plot two lines with `ax.plot(x, y1)` and `ax.plot(x, y2)` — no `label=` argument on either. Then you call `ax.legend()`. What happens?
- `ax.set_title`, `ax.set_xlabel`, `ax.set_ylabel` add text to the figure — always include them before sharing.
- Set `label='...'` on every plotted artist you want in the legend, then call `ax.legend()`.
- `ax.grid(True, alpha=0.3)` adds a subtle reference grid. `ax.set_xlim` / `ax.set_ylim` control the visible range.
- Call `fig.tight_layout()` before `fig.savefig()` to automatically fix label overlap in subplot grids.
Train-vs-validation loss curves are the primary diagnostic for overfitting — you can't interpret them without labeled axes and a legend. Subplot grids of multiple metrics (loss, accuracy, learning rate) are standard in experiment dashboards. Well-formatted figures with `dpi=300` are what you submit with papers.
If you remove it: Without customization skills, every plot you share is an unlabeled sketch — your collaborators can't tell which line is train vs. val, what the axes measure, or what scale you're on. Even for yourself, axes labels and a legend are the difference between a plot you can interpret in six months and one you can't.