Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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() of constrained_layout=True bij figuur.
  • Gebruik z‑order om lagen te sturen (lijnen voor patches of omgekeerd).

23.9 Samenvatting

  • GridSpec en inset/broken axes geven flexibiliteit voor complexe figuren.
  • Annotaties, patches en secundaire assen maken verhalen duidelijker.
  • Bouw kleine helpers voor consistente styling en hergebruik.