Hoofdstuk 23 — Aangepaste visualisaties, annotaties en subplots
Let op: De tekst is in het Nederlands; alle Python codevoorbeelden zijn in het Engels.
Doel van dit hoofdstuk:
- Complexere composities maken met meerdere Axes en GridSpec.
- Annotaties, pijlen, tekstkaders en highlight‑technieken toepassen.
- Balken/pijlen/patches (Rectangle, Arrow), twin axes, inset axes en broken axes.
- Reusable functies en kleine helper‑API’s bouwen voor consistente visuals.
Aanbevolen voorkennis: Hoofdstuk 21–22.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
from matplotlib.patches import Rectangle, FancyArrow, Circle
23.1 Subplot‑composities met GridSpec
plt.subplots dekt veel gevallen. Voor asymmetrische layouts gebruik je GridSpec.
import matplotlib.gridspec as gridspec
fig = plt.figure(figsize=(8, 5))
G = gridspec.GridSpec(nrows=2, ncols=3, height_ratios=[2, 1], width_ratios=[1, 2, 1], figure=fig)
ax_main = fig.add_subplot(G[0, :]) # hele bovenste rij
ax_left = fig.add_subplot(G[1, 0])
ax_mid = fig.add_subplot(G[1, 1])
ax_right= fig.add_subplot(G[1, 2])
x = np.linspace(0, 10, 200)
ax_main.plot(x, np.sin(x))
ax_left.bar(['A','B','C'], [3,2,5])
ax_mid.plot(x, np.cos(x), color='C3')
ax_right.hist(np.random.default_rng(0).normal(size=1000), bins=30)
fig.suptitle('GridSpec compositie'); fig.tight_layout()
23.2 Inset Axes (zoom) en inset colorbar
from mpl_toolkits.axes_grid1.inset_locator import inset_axes, mark_inset
fig, ax = plt.subplots(figsize=(6, 4))
x = np.linspace(0, 4*np.pi, 400); y = np.sin(x) + 0.2*np.sin(10*x)
ax.plot(x, y)
ax.set(title='Inset demo')
# Inset
axins = inset_axes(ax, width="40%", height="40%", loc='upper right')
axins.plot(x, y, color='C1')
axins.set_xlim(2, 3); axins.set_ylim(-1.2, 1.2)
mark_inset(ax, axins, loc1=2, loc2=4, fc="none", ec="0.5")
23.3 Broken axes (gapped axis)
fig, (ax, ax2) = plt.subplots(2, 1, sharex=True, figsize=(6, 4))
y = np.concatenate([np.random.normal(10, 1, 100), np.random.normal(100, 5, 100)])
ax.boxplot(y)
ax2.boxplot(y)
ax.set_ylim(95, 110) # bovenste bereik
ax2.set_ylim(8, 12) # onderste bereik
# diagonale streepjes om de break te tonen
ax.spines['bottom'].set_visible(False)
ax2.spines['top'].set_visible(False)
ax.xaxis.tick_top(); ax.tick_params(labeltop=False)
ax2.xaxis.tick_bottom()
kwargs = dict(marker=[(-1, -1), (1, 1)], markersize=12, linestyle='none', color='k', mec='k', mew=1, clip_on=False)
ax.plot([0, 1], [0, 0], transform=ax.transAxes, **kwargs)
ax2.plot([0, 1], [1, 1], transform=ax2.transAxes, **kwargs)
fig.tight_layout()
23.4 Annotaties, pijlen en tekstkaders
fig, ax = plt.subplots(figsize=(6, 4))
x = np.linspace(0, 2*np.pi, 400); y = np.sin(x)
ax.plot(x, y)
ax.annotate('maximum', xy=(np.pi/2, 1.0), xytext=(2.5, 1.2),
arrowprops=dict(arrowstyle='->', lw=1.5),
bbox=dict(boxstyle='round,pad=0.2', fc='w', ec='0.5'))
ax.text(0.1, -1.1, 'Note: sample', fontsize=10, color='0.2')
23.5 Patches: rechthoeken, cirkels, highlighters
fig, ax = plt.subplots(figsize=(6, 4))
ax.plot(np.arange(10), np.arange(10)**0.5)
# highlight bereik x in [2,5]
ax.add_patch(Rectangle((2, ax.get_ylim()[0]), width=3, height=np.diff(ax.get_ylim())[0],
color='yellow', alpha=0.2, zorder=0))
# markeer punt met cirkel
ax.add_patch(Circle((6, np.sqrt(6)), radius=0.2, color='C3', alpha=0.5))
23.6 Twin axes en secundaire as met functies
fig, ax1 = plt.subplots()
x = np.linspace(0.1, 10, 200)
y = np.log(x)
ax1.plot(x, y, color='C0'); ax1.set_ylabel('log(x)')
ax2 = ax1.secondary_yaxis('right', functions=(np.exp, np.log))
ax2.set_ylabel('exp(y)')
23.7 Kleine helper‑functies voor herbruikbaarheid
def theme_axes(ax, title=None, xlabel=None, ylabel=None):
ax.grid(True, ls=':', alpha=0.4)
if title: ax.set_title(title)
if xlabel: ax.set_xlabel(xlabel)
if ylabel: ax.set_ylabel(ylabel)
return ax
fig, ax = plt.subplots()
ax.plot(np.linspace(0,1,50), np.linspace(0,1,50)**2, label='x^2')
ax = theme_axes(ax, title='Demo', xlabel='x', ylabel='y')
ax.legend()
23.8 Valkuilen en tips
- Te veel annotaties → visuele ruis. Kies spaarzaam en gericht.
- Inset axes kunnen overlap veroorzaken; gebruik
tight_layout()ofconstrained_layout=Truebij figuur. - Gebruik z‑order om lagen te sturen (lijnen voor patches of omgekeerd).
23.9 Samenvatting
GridSpecen inset/broken axes geven flexibiliteit voor complexe figuren.- Annotaties, patches en secundaire assen maken verhalen duidelijker.
- Bouw kleine helpers voor consistente styling en hergebruik.