Imshow: Umfang und Aspekt

82

Ich schreibe ein Softwaresystem, das Schnitte und Projektionen durch einen 3D-Datensatz visualisiert. Ich verwende matplotlibund imshowvisualisiere speziell die Bildpuffer, die ich von meinem Analysecode zurückerhalte.

Da ich die Bilder mit Plotachsen kommentieren möchte, verwende ich das Schlüsselwort Extent, das imshowbereitgestellt wird, um die Bildpuffer-Pixelkoordinaten einem Datenraumkoordinatensystem zuzuordnen.

Leider matplotlibweiß nicht über Einheiten. Sagen Sie (ein künstliches Beispiel), dass ich ein Bild mit den Abmessungen von zeichnen möchte 1000 m X 1 km. In diesem Fall wäre das Ausmaß so etwas wie [0, 1000, 0, 1]. Obwohl das Bildarray quadratisch ist, haben die resultierenden Plotachsen auch ein Seitenverhältnis von 1000, da das durch das Schlüsselwort Extent implizierte Seitenverhältnis 1000 beträgt.

Ist es möglich, das Seitenverhältnis des Diagramms zu erzwingen, während die automatisch generierten Hauptmarkierungen und Beschriftungen, die ich mit dem Schlüsselwort Extent erhalte, beibehalten werden?

ngoldbaum
quelle

Antworten:

138

Sie können dies tun, indem Sie den Aspekt des Bildes manuell einstellen (oder indem Sie es automatisch skalieren lassen, um den Umfang der Abbildung auszufüllen).

Standardmäßig wird imshowder Aspekt des Diagramms auf 1 gesetzt, da dies häufig für Bilddaten gewünscht wird.

In Ihrem Fall können Sie Folgendes tun:

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()

Geben Sie hier die Bildbeschreibung ein

Joe Kington
quelle
Vielen Dank. Komisch, dass die Dokumente nichts über die scalarOption sagen . Es scheint den y-axisum den gegebenen Skalar zu skalieren .
Orodbhen
@ JoeKington ist es möglich, die Größe der einzelnen Pixel zu erhalten. Diese Größe hängt von der Größe des Datensatzes ab und kann wie in Ihrem Fall ein Flickenteppich aus Kacheln zu einem fortlaufenden Diagramm bilden.
Alexander Cska
3

Aus dem plt.imshow()offiziellen Leitfaden wissen wir, dass der Aspekt das Seitenverhältnis der Achsen steuert. In meinen Worten ist der Aspekt genau das Verhältnis von x- Einheit und y- Einheit . Meistens wollen wir es als 1 behalten, da wir Zahlen nicht unbeabsichtigt verzerren wollen. Es gibt jedoch tatsächlich Fälle, in denen wir einen anderen Aspekt als 1 angeben müssen. Der Fragesteller lieferte ein gutes Beispiel dafür, dass die x- und y-Achse unterschiedliche physikalische Einheiten haben können. Nehmen wir an, dass x in km und y in m ist. Daher sollte für 10x10-Daten die Ausdehnung [0,10 km, 0,10 m] = [0, 10000 m, 0, 10 m] sein. In diesem Fall ist die Qualität der Figur wirklich schlecht, wenn wir weiterhin den Standardaspekt = 1 verwenden. Wir können daher Aspekt = 1000 angeben, um unsere Zahl zu optimieren. Die folgenden Codes veranschaulichen diese Methode.

%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)

Geben Sie hier die Bildbeschreibung ein

Dennoch denke ich, dass es eine Alternative gibt, die die Nachfrage des Fragestellers befriedigen kann. Wir können einfach die Ausdehnung auf [0,10,0,10] einstellen und zusätzliche Beschriftungen für die xy-Achse hinzufügen, um die Einheiten zu kennzeichnen. Codes wie folgt.

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

Geben Sie hier die Bildbeschreibung ein

Um eine korrekte Zahl zu erhalten, sollten wir immer daran denken, dass x_max-x_min = x_res * data.shape[1]und y_max - y_min = y_res * data.shape[0]wo extent = [x_min, x_max, y_min, y_max]. Standardmäßig aspect = 1bedeutet dies, dass das Einheitspixel quadratisch ist. Dieses Standardverhalten funktioniert auch für x_res und y_res mit unterschiedlichen Werten. Nehmen wir an, dass x_res 1,5 ist, während y_res 1 ist. Daher sollte die Ausdehnung gleich [0,15,0,10] sein. Mit dem Standardaspekt können wir rechteckige Farbpixel haben, während das Einheitspixel immer noch quadratisch ist!

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])

Geben Sie hier die Bildbeschreibung ein Geben Sie hier die Bildbeschreibung ein

Der Aspekt des Farbpixels ist x_res / y_res. Das Setzen seines Aspekts auf den Aspekt des Einheitspixels (dh aspect = x_res / y_res = ((x_max - x_min) / data.shape[1]) / ((y_max - y_min) / data.shape[0])) würde immer ein quadratisches Farbpixel ergeben. Wir können Aspekt = 1,5 so ändern, dass die x-Achseneinheit die 1,5-fache y-Achseneinheit ist, was zu einem quadratischen Farbpixel und einer quadratischen ganzen Figur, aber einer rechteckigen Pixeleinheit führt. Anscheinend wird es normalerweise nicht akzeptiert.

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

Geben Sie hier die Bildbeschreibung ein

Der unerwünschteste Fall ist, dass für den eingestellten Aspekt ein beliebiger Wert wie 1,2 festgelegt wird, der weder zu quadratischen Einheitspixeln noch zu quadratischen Farbpixeln führt.

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

Geben Sie hier die Bildbeschreibung ein

Kurz gesagt, es reicht immer aus, das richtige Ausmaß einzustellen und die Matplotlib die restlichen Dinge für uns erledigen zu lassen (obwohl x_res! = Y_res)! Ändern Sie den Aspekt nur, wenn dies ein Muss ist.

Fei Yao
quelle