Nota
Fare clic qui per scaricare il codice di esempio completo
Percorso Tutorial #
Definizione di percorsi nella visualizzazione Matplotlib.
L'oggetto sottostante a tutti gli matplotlib.patches
oggetti è Path
, che supporta l'insieme standard di comandi moveto, lineto, curveto per disegnare contorni semplici e composti costituiti da segmenti di linea e spline. Viene istanziato con un array ( Path
N, 2) di vertici (x, y) e un array di codici di percorso di lunghezza N. Ad esempio per disegnare il rettangolo unitario da (0, 0) a (1, 1), potremmo usare questo codice:
import matplotlib.pyplot as plt
from matplotlib.path import Path
import matplotlib.patches as patches
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()
Vengono riconosciuti i seguenti codici di percorso
Codice |
Vertici |
Descrizione |
---|---|---|
|
1 (ignorato) |
Un indicatore per la fine dell'intero percorso (attualmente non richiesto e ignorato). |
|
1 |
Prendi la penna e spostati sul vertice dato. |
|
1 |
Traccia una linea dalla posizione corrente al vertice dato. |
|
2: 1 punto di controllo, 1 punto finale |
Disegna una curva di Bézier quadratica dalla posizione corrente, con il dato punto di controllo, al dato punto finale. |
|
3: 2 punti di controllo, 1 punto finale |
Disegna una curva di Bézier cubica dalla posizione corrente, con i punti di controllo dati, al punto finale dato. |
|
1 (il punto è ignorato) |
Disegna un segmento di linea fino al punto iniziale della polilinea corrente. |
Bézier esempio #
Alcuni dei componenti del percorso richiedono più vertici per specificarli: ad esempio CURVE 3 è una curva di Bézier con un punto di controllo e un punto finale e CURVE4 ha tre vertici per i due punti di controllo e il punto finale. L'esempio seguente mostra una spline di Bézier CURVE4 -- la curva di Bézier sarà contenuta nello scafo convesso del punto iniziale, i due punti di controllo e il punto finale
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()
Percorsi composti #
Tutte le semplici primitive di patch in matplotlib, Rectangle, Circle, Polygon, ecc., sono implementate con percorso semplice. Funzioni di plottaggio come hist()
e
bar()
, che creano un certo numero di primitive, ad esempio un gruppo di rettangoli, di solito possono essere implementate in modo più efficiente utilizzando un percorso composto. Il motivo per cui bar
viene creato un elenco di rettangoli e non un percorso composto è in gran parte storico: il
Path
codice è relativamente nuovo e bar
lo precede. Mentre potremmo cambiarlo ora, romperebbe il vecchio codice, quindi qui tratteremo come creare percorsi composti, sostituendo la funzionalità in bar, nel caso in cui sia necessario farlo nel proprio codice per motivi di efficienza, ad esempio, si sta creando una trama da bar animata.
Realizzeremo il grafico dell'istogramma creando una serie di rettangoli per ogni barra dell'istogramma: la larghezza del rettangolo è la larghezza del contenitore e l'altezza del rettangolo è il numero di punti dati in quel contenitore. Per prima cosa creeremo alcuni dati casuali normalmente distribuiti e calcoleremo l'istogramma. Poiché numpy restituisce i bordi del contenitore e non i centri, la lunghezza di bins
è 1 maggiore della lunghezza di n
nell'esempio seguente:
# histogram our data with numpy
data = np.random.randn(1000)
n, bins = np.histogram(data, 100)
Ora estrarremo gli angoli dei rettangoli. Ciascuno degli
array left
, bottom
, ecc. di seguito è len(n)
, dove n
è l'array di conteggi per ciascuna barra dell'istogramma:
Ora dobbiamo costruire il nostro percorso composto, che consisterà in una serie di MOVETO
, LINETO
e CLOSEPOLY
per ogni rettangolo. Per ogni rettangolo, abbiamo bisogno di 5 vertici: 1 per MOVETO
, 3 per LINETO
, e 1 per CLOSEPOLY
. Come indicato nella tabella sopra, il vertice per il closepoly viene ignorato ma ne abbiamo ancora bisogno per mantenere i codici allineati con i vertici:
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
Non resta che creare il percorso, collegarlo a un
PathPatch
e aggiungerlo ai nostri assi:
barpath = path.Path(verts, codes)
patch = patches.PathPatch(barpath, facecolor='green',
edgecolor='yellow', alpha=0.5)
ax.add_patch(patch)
import numpy as np
import matplotlib.patches as patches
import matplotlib.path as path
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.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
barpath = path.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()