Imshow: estensione e aspetto


86

Sto scrivendo un sistema software che visualizza sezioni e proiezioni attraverso un set di dati 3D. Sto usando matplotlibe specificatamente imshowper visualizzare i buffer di immagine che ricevo dal mio codice di analisi.

Poiché vorrei annotare le immagini con gli assi del grafico, utilizzo la parola chiave extent che imshowfornisce per mappare le coordinate dei pixel del buffer dell'immagine su un sistema di coordinate dello spazio dati.

Sfortunatamente, matplotlibnon conosce le unità. Di '(prendendo un esempio artificiale) che voglio tracciare un'immagine con dimensioni di 1000 m X 1 km. In tal caso l'estensione sarebbe qualcosa di simile [0, 1000, 0, 1]. Anche se la matrice dell'immagine è quadrata, poiché le proporzioni implicite dalla parola chiave extent è 1000, anche gli assi del grafico risultanti hanno una proporzione di 1000.

È possibile forzare le proporzioni del grafico mantenendo i segni di graduazione e le etichette principali generati automaticamente che ottengo utilizzando la parola chiave extent?

Risposte:


144

Puoi farlo impostando manualmente l'aspetto dell'immagine (o lasciandolo ridimensionare automaticamente per riempire l'estensione della figura).

Per impostazione predefinita, imshowimposta l'aspetto del grafico su 1, poiché questo è spesso ciò che le persone desiderano per i dati dell'immagine.

Nel tuo caso, puoi fare qualcosa come:

import matplotlib.pyplot as plt
import numpy as np

grid = np.random.random((10,10))

fig, (ax1, ax2, ax3) = plt.subplots(nrows=3, figsize=(6,10))

ax1.imshow(grid, extent=[0,100,0,1])
ax1.set_title('Default')

ax2.imshow(grid, extent=[0,100,0,1], aspect='auto')
ax2.set_title('Auto-scaled Aspect')

ax3.imshow(grid, extent=[0,100,0,1], aspect=100)
ax3.set_title('Manually Set Aspect')

plt.tight_layout()
plt.show()

inserisci qui la descrizione dell'immagine


Grazie. Buffo che i documenti non dicano nulla scalarsull'opzione. Sembra scalare lo y-axisscalare dato.
orodbhen

@ JoeKington è possibile ottenere la dimensione dei singoli pixel. Questa dimensione dipende dalla dimensione del set di dati e può andare da un mosaico di piastrelle a una trama continua come nel tuo caso.
Alexander Cska

4

Dalla plt.imshow()guida ufficiale, sappiamo che l'aspetto controlla le proporzioni degli assi. Bene, nelle mie parole, l'aspetto è esattamente il rapporto tra unità x e unità y . La maggior parte delle volte vogliamo mantenerlo come 1 poiché non vogliamo distorcere le cifre involontariamente. Tuttavia, ci sono effettivamente casi in cui abbiamo bisogno di specificare un valore diverso da 1. L'interrogante ha fornito un buon esempio che gli assi xey possono avere unità fisiche differenti. Supponiamo che x sia in km ey in m. Quindi per un dato 10x10, l'estensione dovrebbe essere [0,10km, 0,10m] = [0, 10000m, 0, 10m]. In tal caso, se continuiamo a utilizzare l'aspetto predefinito = 1, la qualità della figura è davvero pessima. Possiamo quindi specificare aspect = 1000 per ottimizzare la nostra figura. I seguenti codici illustrano questo metodo.

%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
rng=np.random.RandomState(0)
data=rng.randn(10,10)
plt.imshow(data, origin = 'lower',  extent = [0, 10000, 0, 10], aspect = 1000)

inserisci qui la descrizione dell'immagine

Tuttavia, penso che ci sia un'alternativa in grado di soddisfare la domanda dell'interrogante. Possiamo semplicemente impostare l'estensione come [0,10,0,10] e aggiungere ulteriori etichette dell'asse xy per denotare le unità. Codici come segue.

plt.imshow(data, origin = 'lower',  extent = [0, 10, 0, 10])
plt.xlabel('km')
plt.ylabel('m')

inserisci qui la descrizione dell'immagine

Per fare una figura corretta , dobbiamo sempre tenerlo presentex_max-x_min = x_res * data.shape[1] e y_max - y_min = y_res * data.shape[0], dove extent = [x_min, x_max, y_min, y_max]. Per impostazione predefinita, aspect = 1ciò significa che l'unità pixel è quadrata. Questo comportamento predefinito funziona bene anche per x_res e y_res che hanno valori diversi. Estendendo l'esempio precedente, supponiamo che x_res sia 1.5 mentre y_res sia 1. Quindi l'estensione dovrebbe essere uguale a [0,15,0,10]. Utilizzando l'aspetto predefinito, possiamo avere pixel di colore rettangolari, mentre l'unità pixel è ancora quadrata!

plt.imshow(data, origin = 'lower',  extent = [0, 15, 0, 10])
# Or we have similar x_max and y_max but different data.shape, leading to different color pixel res.
data=rng.randn(10,5)
plt.imshow(data, origin = 'lower',  extent = [0, 5, 0, 5])

inserisci qui la descrizione dell'immagine inserisci qui la descrizione dell'immagine

L'aspetto del pixel a colori è x_res / y_res. impostando il suo aspetto sull'aspetto dell'unità pixel (cioè aspect = x_res / y_res = ((x_max - x_min) / data.shape[1]) / ((y_max - y_min) / data.shape[0])) darebbe sempre un pixel di colore quadrato. Possiamo cambiare aspetto = 1,5 in modo che l'unità dell'asse x sia 1,5 volte l'unità dell'asse y, portando a un pixel di colore quadrato e una figura intera quadrata ma un'unità di pixel rettangolare. A quanto pare, normalmente non è accettato.

data=rng.randn(10,10)
plt.imshow(data, origin = 'lower',  extent = [0, 15, 0, 10], aspect = 1.5)

inserisci qui la descrizione dell'immagine

Il caso più indesiderato è quello di impostare l'aspetto su un valore arbitrario, come 1.2, che non porterà a pixel di unità quadrate né pixel di colore quadrati.

plt.imshow(data, origin = 'lower',  extent = [0, 15, 0, 10], aspect = 1.2)

inserisci qui la descrizione dell'immagine

Per farla breve, è sempre sufficiente impostare l'estensione corretta e lasciare che matplotlib faccia le cose rimanenti per noi (anche se x_res! = Y_res)! Cambia aspetto solo quando è d'obbligo.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.