Skip to course content
Free data visualization course

Data Visualization and Dashboard Storytelling

Unit 09.02: Annotating in data coordinates

An annotation anchored in data coordinates stays on the point it describes.

Data coordinates, not pixels

An arrow anchored to a specific week and value, with a target line.

The code places both and reports where they are anchored.

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

weeks = list(range(1, 15))
rate = [2.1, 2.0, 1.9, 2.2, 2.0, 1.8, 1.9, 2.1, 2.0, 1.9, 2.3, 3.4, 3.1, 2.2]

fig, ax = plt.subplots()
ax.plot(weeks, rate)
ax.annotate("supplier change", xy=(12, 3.4), xytext=(7, 3.2),
            arrowprops={"arrowstyle": "->"})
ax.axhline(2.0, linestyle="--", linewidth=1)

annotation = ax.texts[0]
print(f"annotation text   : {annotation.get_text()!r}")
print(f"anchored at data  : {annotation.xy}")
print(f"label sits at data: {annotation.get_position()}")
print(f"target line at y  : {ax.lines[1].get_ydata()[0]}")
plt.close(fig)

print("\nAnchoring in DATA coordinates means the arrow stays on week 12 when")
print("the figure is resized. Anchoring in pixels means it drifts off.")

The annotation is anchored at week 12 in data terms, so it stays there when the figure is resized for a slide, a report or a phone. Anchored in pixels or in fractions of the axes, it drifts.

The target line is the other half of the same idea: drawn at a data value rather than at a position, so it remains correct if the axis limits change.

The mistake this prevents

The mistake is positioning annotations by eye and then resizing the figure for a different medium. Everything moves, and the arrow that pointed at the spike now points beside it - which is worse than no annotation.

Takeaway

Anchor annotations and reference lines in data coordinates. They then survive resizing, which every figure eventually undergoes.