The Artist hierarchy

Matplotlib · Expert · 14 min

When no keyword argument does what you need, walking the Artist tree lets you change any detail of any chart, including those made by pandas or seaborn.

Everything drawn in Matplotlib is an Artist. The tree looks like this:

  • Figure contains Axes, figure-level text, legends and patches (the background fig.patch).
  • Axes contains its two Axis objects (with Ticks, which hold Line2D tick marks and Text labels), spines, the title texts and the data artists in ax.lines, ax.patches, ax.collections, ax.images and ax.texts.

Primitives are Line2D, Rectangle and other Patches, Text, AxesImage and Collections (many similar shapes drawn efficiently, as scatter returns). Containers (Figure, Axes, Axis, Tick) hold other artists.

Every Artist shares an interface: get_*/set_* properties, set(**kwargs) for several at once, set_visible, set_zorder (drawing order), set_alpha, set_clip_on, get_children() and findobj(match) to search the subtree. plt.getp(artist) lists all properties, a quick way to discover what is settable.

Plotting helpers are just factories: ax.bar creates Rectangle patches and adds them with ax.add_patch. You can do the same, building custom shapes with matplotlib.patches and adding them yourself.

Artists only describe what to draw; nothing is rendered until the canvas draws the figure, calling each artist's draw(renderer) in z-order. That is why some values, such as text extents or automatic tick labels, are only accurate after fig.canvas.draw().

Example

import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle
from matplotlib.text import Text

fig, ax = plt.subplots()
ax.bar(["a", "b", "c"], [3, 5, 2])
ax.set_title("Sales")

print(type(ax.patches[0]).__name__, len(ax.patches))  # Rectangle 3
ax.patches[1].set(color="tab:red", hatch="//")        # restyle one bar
ax.add_patch(Rectangle((-0.5, 4), 3, 0.1, color="gray", alpha=0.5))

texts = fig.findobj(Text)
print(any(t.get_text() == "Sales" for t in texts))   # True
for s in ("top", "right"):
    ax.spines[s].set_visible(False)
print([type(c).__name__ for c in ax.get_children()][:4])
# ['Rectangle', 'Rectangle', 'Rectangle', 'Rectangle']
fig.savefig("artists.png")

Remember

  • Every drawn element is an Artist in a tree rooted at the Figure
  • All Artists share get/set properties, visibility, z-order and findobj
  • Plot functions create primitives you can later restyle or add yourself

Watch out for

  • Reading text sizes or tick labels before the figure has been drawn, and getting placeholder values.

Check yourself

  1. A seaborn function returned an Axes, and you want to recolor just the second bar. Where is it?

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

Official docs: matplotlib.org/stable/users/explain/artists/artist_intro.html