Hinweis
Zum Ende gehen, um den gesamten Beispielcode herunterzuladen.
Pfad-Tutorial#
Definieren von Pfaden in Ihrer Matplotlib-Visualisierung.
Das Objekt, das allen matplotlib.patches-Objekten zugrunde liegt, ist Path, welches den Standard-Satz von Moveto-, Lineto-, Curveto-Befehlen unterstützt, um einfache und zusammengesetzte Umrisse aus Liniensegmenten und Splines zu zeichnen. Das Path wird mit einem (N, 2) Array von (x, y) Vertices und einem N-langen Array von Pfad-Codes instanziiert. Um zum Beispiel das Einheitsrechteck von (0, 0) bis (1, 1) zu zeichnen, könnten wir diesen Code verwenden:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as patches
from matplotlib.path import Path
verts = [
(0., 0.), # left, bottom
(0., 1.), # left, top
(1., 1.), # right, top
(1., 0.), # right, bottom
(0., 0.), # ignored
]
codes = [
Path.MOVETO,
Path.LINETO,
Path.LINETO,
Path.LINETO,
Path.CLOSEPOLY,
]
path = Path(verts, codes)
fig, ax = plt.subplots()
patch = patches.PathPatch(path, facecolor='orange', lw=2)
ax.add_patch(patch)
ax.set_xlim(-2, 2)
ax.set_ylim(-2, 2)
plt.show()

Die folgenden Pfad-Codes werden erkannt:
Code |
Vertices |
Beschreibung |
|---|---|---|
|
1 (ignoriert) |
Eine Markierung für das Ende des gesamten Pfades (derzeit nicht erforderlich und ignoriert). |
|
1 |
Holen Sie den Stift auf und bewegen Sie sich zum angegebenen Vertex. |
|
1 |
Zeichnen Sie eine Linie von der aktuellen Position zum angegebenen Vertex. |
|
2: 1 Kontrollpunkt, 1 Endpunkt |
Zeichnen Sie eine quadratische Bézierkurve von der aktuellen Position mit dem angegebenen Kontrollpunkt zum angegebenen Endpunkt. |
|
3: 2 Kontrollpunkte, 1 Endpunkt |
Zeichnen Sie eine kubische Bézierkurve von der aktuellen Position mit den angegebenen Kontrollpunkten zum angegebenen Endpunkt. |
|
1 (der Punkt wird ignoriert) |
Zeichnen Sie ein Liniensegment zum Startpunkt der aktuellen Polylinie. |
Bézier-Beispiel#
Einige der Pfadkomponenten erfordern mehrere Vertices zur Spezifikation: Zum Beispiel ist CURVE 3 eine Bézier-Kurve mit einem Kontrollpunkt und einem Endpunkt, und CURVE4 hat drei Vertices für die beiden Kontrollpunkte und den Endpunkt. Das folgende Beispiel zeigt eine CURVE4 Bézier-Spline -- die Bézier-Kurve wird innerhalb der konvexen Hülle des Startpunkts, der beiden Kontrollpunkte und des Endpunkts liegen.
verts = [
(0., 0.), # P0
(0.2, 1.), # P1
(1., 0.8), # P2
(0.8, 0.), # P3
]
codes = [
Path.MOVETO,
Path.CURVE4,
Path.CURVE4,
Path.CURVE4,
]
path = Path(verts, codes)
fig, ax = plt.subplots()
patch = patches.PathPatch(path, facecolor='none', lw=2)
ax.add_patch(patch)
xs, ys = zip(*verts)
ax.plot(xs, ys, 'x--', lw=2, color='black', ms=10)
ax.text(-0.05, -0.05, 'P0')
ax.text(0.15, 1.05, 'P1')
ax.text(1.05, 0.85, 'P2')
ax.text(0.85, -0.05, 'P3')
ax.set_xlim(-0.1, 1.1)
ax.set_ylim(-0.1, 1.1)
plt.show()

Zusammengesetzte Pfade#
Alle einfachen Patch-Primitive in Matplotlib, Rectangle, Circle, Polygon usw., werden mit einfachen Pfaden implementiert. Plotting-Funktionen wie hist() und bar(), die eine Anzahl von Primitiven erzeugen, z.B. eine Menge von Rechtecken, können normalerweise effizienter mit einem zusammengesetzten Pfad implementiert werden. Der Grund, warum bar eine Liste von Rechtecken und keinen zusammengesetzten Pfad erzeugt, ist weitgehend historisch: der Path-Code ist vergleichsweise neu und bar existierte bereits davor. Obwohl wir es jetzt ändern könnten, würde dies alten Code brechen, daher werden wir hier abdecken, wie zusammengesetzte Pfade erstellt werden, um die Funktionalität von bar zu ersetzen, falls Sie dies aus Effizienzgründen in Ihrem eigenen Code tun müssen, z.B. wenn Sie ein animiertes Balkendiagramm erstellen.
Wir erstellen das Histogramm, indem wir für jeden Histogrammbalken eine Reihe von Rechtecken erstellen: Die Breite des Rechtecks ist die Bin-Breite und die Höhe des Rechtecks ist die Anzahl der Datenpunkte in diesem Bin. Zuerst erstellen wir einige zufällig normalverteilte Daten und berechnen das Histogramm. Da NumPy die Bin-Ränder und nicht die Zentren zurückgibt, ist die Länge von bins um eins größer als die Länge von n im folgenden Beispiel.
# histogram our data with numpy
data = np.random.randn(1000)
n, bins = np.histogram(data, 100)
Wir extrahieren nun die Ecken der Rechtecke. Jedes der unten stehenden Arrays left, bottom usw. hat die Länge len(n), wobei n das Array der Zählungen für jeden Histogrammbalken ist.
Jetzt müssen wir unseren zusammengesetzten Pfad konstruieren, der aus einer Reihe von MOVETO, LINETO und CLOSEPOLY für jedes Rechteck besteht. Für jedes Rechteck benötigen wir fünf Vertices: einen für das MOVETO, drei für die LINETO und einen für das CLOSEPOLY. Wie in der obigen Tabelle angegeben, wird der Vertex für das CLOSEPOLY ignoriert, aber wir benötigen ihn trotzdem, um die Codes mit den Vertices abzugleichen.
nverts = nrects*(1+3+1)
verts = np.zeros((nverts, 2))
codes = np.ones(nverts, int) * path.Path.LINETO
codes[0::5] = path.Path.MOVETO
codes[4::5] = path.Path.CLOSEPOLY
verts[0::5, 0] = left
verts[0::5, 1] = bottom
verts[1::5, 0] = left
verts[1::5, 1] = top
verts[2::5, 0] = right
verts[2::5, 1] = top
verts[3::5, 0] = right
verts[3::5, 1] = bottom
Alles, was bleibt, ist die Erstellung des Pfades, das Anhängen an ein PathPatch und das Hinzufügen zu unseren Achsen.
barpath = path.Path(verts, codes)
patch = patches.PathPatch(barpath, facecolor='green',
edgecolor='yellow', alpha=0.5)
ax.add_patch(patch)
fig, ax = plt.subplots()
# Fixing random state for reproducibility
np.random.seed(19680801)
# histogram our data with numpy
data = np.random.randn(1000)
n, bins = np.histogram(data, 100)
# get the corners of the rectangles for the histogram
left = np.array(bins[:-1])
right = np.array(bins[1:])
bottom = np.zeros(len(left))
top = bottom + n
nrects = len(left)
nverts = nrects*(1+3+1)
verts = np.zeros((nverts, 2))
codes = np.full(nverts, Path.LINETO, dtype=int)
codes[0::5] = Path.MOVETO
codes[4::5] = Path.CLOSEPOLY
verts[0::5, 0] = left
verts[0::5, 1] = bottom
verts[1::5, 0] = left
verts[1::5, 1] = top
verts[2::5, 0] = right
verts[2::5, 1] = top
verts[3::5, 0] = right
verts[3::5, 1] = bottom
barpath = Path(verts, codes)
patch = patches.PathPatch(barpath, facecolor='green',
edgecolor='yellow', alpha=0.5)
ax.add_patch(patch)
ax.set_xlim(left[0], right[-1])
ax.set_ylim(bottom.min(), top.max())
plt.show()