Titles, labels and legends

Matplotlib · Essentials · 8 min

A chart without labels and units is a puzzle; these few calls are what makes a plot usable by someone else.

Three calls cover most labelling: ax.set_title("..."), ax.set_xlabel("...") and ax.set_ylabel("..."). Put units in the axis label, for example "Latency (ms)", so readers do not have to guess. ax.set(title=..., xlabel=..., ylabel=...) sets several properties in one call.

A legend names each series. Give each plotting call a label=, then call ax.legend(); only artists with a label appear, and labels starting with an underscore are ignored. Useful options:

  • loc="upper left" or the default "best", which searches for the emptiest spot (slow with very many points).
  • ncols=2 to lay entries out in columns.
  • frameon=False for a lighter look.
  • bbox_to_anchor=(1.02, 1), loc="upper left" to put the legend outside the plot on the right.

For the whole figure, fig.suptitle("...") adds a title above all subplots, and fig.legend() builds one legend from every Axes.

Text accepts a subset of LaTeX-style math between dollar signs: ax.set_xlabel(r"$\alpha$ (rad)"). Use raw strings so backslashes survive.

If labels overlap or get cut off when saving, the fix is layout, not font size: use layout="constrained" when creating the figure, or bbox_inches="tight" when saving.

Example

import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt

epochs = [1, 2, 3, 4, 5]
fig, ax = plt.subplots(layout="constrained")
ax.plot(epochs, [0.9, 0.6, 0.45, 0.4, 0.38], label="train")
ax.plot(epochs, [0.95, 0.7, 0.6, 0.58, 0.6], label="validation")
ax.plot(epochs, [0.5] * 5, "k:", label="_target")   # hidden from legend
ax.set(title="Training loss", xlabel="Epoch", ylabel="Loss")
leg = ax.legend(loc="upper right", frameon=False)

print([t.get_text() for t in leg.get_texts()])  # ['train', 'validation']
print(ax.get_title())                            # Training loss
fig.savefig("loss.png")

Remember

  • Label both axes and include units
  • Give each series label= then call ax.legend()
  • Labels starting with _ are left out of the legend

Watch out for

  • Calling ax.legend() before plotting, or without any label=, which gives an empty legend and a warning.

Check yourself

  1. You plotted three lines but only passed `label=` to two of them. What does `ax.legend()` show?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: matplotlib.org/stable/users/explain/axes/legend_guide.html