Annotations turn a chart into an argument by telling readers exactly where to look.
ax.text(x, y, "label") places text at data coordinates. Align it with ha (horizontal: "left", "center", "right") and va. To place text relative to the Axes box rather than the data, for example in the top-left corner regardless of limits, add transform=ax.transAxes and use coordinates between 0 and 1.
ax.annotate draws text with an optional arrow:
ax.annotate("peak", xy=(x0, y0), xytext=(x0 + 1, y0 + 2),
arrowprops=dict(arrowstyle="->"))xy is the point being annotated and xytext where the text sits. textcoords="offset points" makes xytext an offset in points, which keeps the label a fixed visual distance away however the data is scaled.
Reference lines and spans mark thresholds and periods:
ax.axhline(y)andax.axvline(x)span the whole Axes;ax.axhspan(y0, y1)andax.axvspan(x0, x1, alpha=0.2)shade a band;ax.fill_between(x, low, high, alpha=0.3)shades between curves, ideal for confidence bands.
For bar charts, ax.bar_label(bars) writes each bar's value on or above it; fmt="{:.1f}" and padding=3 adjust the format and spacing, and label_type="center" puts labels inside stacked segments.
Restraint matters: one or two annotations make a point, ten create clutter.
Example
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import numpy as np
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(9, 3.5), layout="constrained")
x = np.linspace(0, 10, 200)
y = np.sin(x) * np.exp(-x / 5)
i = y.argmax()
ax1.plot(x, y)
ax1.annotate("peak", xy=(x[i], y[i]), xytext=(20, -20),
textcoords="offset points", arrowprops=dict(arrowstyle="->"))
ax1.axhline(0, color="gray", linewidth=0.8)
ax1.axvspan(6, 8, alpha=0.15, color="C1")
ax1.text(0.02, 0.95, "damped", transform=ax1.transAxes, va="top")
bars = ax2.bar(["Q1", "Q2", "Q3"], [12.5, 18.25, 9.0])
labels = ax2.bar_label(bars, fmt="{:.1f}", padding=3)
print([t.get_text() for t in labels]) # ['12.5', '18.2', '9.0']
fig.savefig("annotated.png")Remember
ax.textplaces text;transform=ax.transAxesuses 0..1 Axes coordinatesax.annotate(text, xy=point, xytext=..., arrowprops=...)points at dataaxhline,axvspan,fill_betweenandbar_labelcover most chart callouts
Watch out for
- Positioning text in data coordinates that later fall outside the limits, so the label silently disappears.