Stellen Sie die Größe des Matplotlib-Farbbalkens so ein, dass er mit dem Diagramm übereinstimmt

160

Ich kann nicht erreichen, dass die Farbleiste in Imshow-Diagrammen wie diesem die gleiche Höhe wie das Diagramm hat, ohne dass Photoshop nachträglich verwendet wird. Wie bekomme ich die passenden Höhen?Beispiel für die Nichtübereinstimmung der Farbleistengröße

Elliot
quelle
Haben Sie die Vorschläge von stackoverflow.com/questions/16702479/…
lmjohns3
@ imjohns3 Nichts in diesem Beitrag scheint etwas mit der Farbleiste zu tun zu haben. Es bleibt gleich groß, egal was ich einstelle. Wenn ich jedoch den Bruch einstelle und verkleinere, ändert sich die Größe des Diagramms, während der Farbbalken gleich bleibt, bis wir zu dem zurückkehren, was ich bereits habe. Dann hören sie auf, irgendetwas zu tun.
Elliot
Überprüfen Sie die Dokumente - matplotlib.org/api/colorbar_api.html - und verwenden Sie fractionoder shrinkargs.
BoltzmannBrain

Antworten:

194

Sie können dies einfach mit einem matplotlib AxisDivider tun .

Das Beispiel auf der verlinkten Seite funktioniert auch ohne Verwendung von Nebenhandlungen:

import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable
import numpy as np

plt.figure()
ax = plt.gca()
im = ax.imshow(np.arange(100).reshape((10,10)))

# create an axes on the right side of ax. The width of cax will be 5%
# of ax and the padding between cax and ax will be fixed at 0.05 inch.
divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="5%", pad=0.05)

plt.colorbar(im, cax=cax)

Geben Sie hier die Bildbeschreibung ein

Bogatron
quelle
1
Ich arbeite nicht in einer Nebenhandlung, daher gilt dies nicht.
Elliot
Nach langem Basteln ging es los. Wenn Sie Probleme mit der Interaktion mit subplot_adjust haben, müssen Sie die Anrufe an genau den richtigen Stellen relativ zueinander abrufen.
Elliot
11
Dadurch wird die Größe der Diagramme geringfügig geändert. Ich habe 4 in einem 2x2-Raster, möchte aber nur, dass die beiden rechts Balken haben (Skalierung gilt nach Zeilen). Dies macht sie jedoch nicht gleich groß. Ich habe versucht, den Colorbar-Aufruf (mit dem Divider-Aufruf) nicht zu haben, aber dies lässt natürlich ein leeres weißes Kästchen und Zahlen auf der Seite. Wie kann ich erreichen, dass sie eine einheitliche Größe haben, ohne sie alle mit Balken zu versehen?
Elliot
@ Bogatron Leider funktioniert dies nicht mit projizierten Achsen
Bogdan
Wenn Sie einen Titel mit hinzufügen möchten plt.title, wird dieser nach rechts vertauscht angezeigt. Gibt es eine Möglichkeit, dies zu überwinden?
user2820579
224

Diese Kombination (und Werte in der Nähe dieser Werte) scheint für mich "magisch" zu funktionieren, um die Farbleiste auf das Diagramm skaliert zu halten, unabhängig von der Größe der Anzeige.

plt.colorbar(im,fraction=0.046, pad=0.04)

Es ist auch nicht erforderlich, die Achse zu teilen, wodurch das Diagramm aus dem Quadrat geraten kann.

Skytaker
quelle
4
Dies kann in einigen Fällen funktionieren, im Allgemeinen jedoch nicht. Versuchen Sie beispielsweise, etwas wie in der ursprünglichen Frage zu zeichnen, deren Breite doppelt so hoch ist.
Matthias
Die Bruchoption scheint in dem von Ihnen erwähnten Fall immer noch zu funktionieren, wenn sie an die Höhe des Diagramms angepasst wird. (mpl v1.4.3)
Skytaker
6
Dies ist der einzige universelle Weg, dies zu tun. Die Lösungen mit axex_grid1 funktionieren nicht für projizierte Achsen wie GeoAxes.
Bogdan
Oh mein Gott, das ist großartig. Vielen Dank für die Lösung
2D_
3
Als Antwort auf @Matthias Kommentar. Mit diesem Trick können Sie den Fall korrigieren, dass das Bild zu breit ist: im_ratio = data.shape[0]/data.shape[1] plt.colorbar(im,fraction=0.046*im_ratio, pad=0.04)Wo dataist Ihr Bild ?
eindzl
29

@bogatron gab bereits die Antwort, die von den matplotlib-Dokumenten vorgeschlagen wurde , wodurch die richtige Höhe erzeugt wird, aber es kommt zu einem anderen Problem. Jetzt ändert sich die Breite der Farbleiste (sowie der Abstand zwischen Farbleiste und Plot) mit der Breite des Plots. Mit anderen Worten, das Seitenverhältnis der Farbleiste ist nicht mehr festgelegt.

Um sowohl die richtige Höhe als auch ein bestimmtes Seitenverhältnis zu erhalten, müssen Sie etwas tiefer in das mysteriöse axes_grid1Modul eintauchen.

import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid1 import make_axes_locatable, axes_size
import numpy as np

aspect = 20
pad_fraction = 0.5

ax = plt.gca()
im = ax.imshow(np.arange(200).reshape((20, 10)))
divider = make_axes_locatable(ax)
width = axes_size.AxesY(ax, aspect=1./aspect)
pad = axes_size.Fraction(pad_fraction, width)
cax = divider.append_axes("right", size=width, pad=pad)
plt.colorbar(im, cax=cax)

Beachten Sie, dass dies die Breite des Farbbalkens in Bezug auf die Höhe des Diagramms angibt (im Gegensatz zur Breite der Abbildung wie zuvor).

Der Abstand zwischen Farbbalken und Plot kann jetzt als Bruchteil der Breite des Farbbalkens angegeben werden, was meiner Meinung nach eine viel aussagekräftigere Zahl ist als ein Bruchteil der Figurenbreite.

Bilddiagramm mit Farbleiste

AKTUALISIEREN:

Ich habe ein IPython-Notizbuch zu diesem Thema erstellt , in dem ich den obigen Code in eine leicht wiederverwendbare Funktion gepackt habe:

import matplotlib.pyplot as plt
from mpl_toolkits import axes_grid1

def add_colorbar(im, aspect=20, pad_fraction=0.5, **kwargs):
    """Add a vertical color bar to an image plot."""
    divider = axes_grid1.make_axes_locatable(im.axes)
    width = axes_grid1.axes_size.AxesY(im.axes, aspect=1./aspect)
    pad = axes_grid1.axes_size.Fraction(pad_fraction, width)
    current_ax = plt.gca()
    cax = divider.append_axes("right", size=width, pad=pad)
    plt.sca(current_ax)
    return im.axes.figure.colorbar(im, cax=cax, **kwargs)

Es kann folgendermaßen verwendet werden:

im = plt.imshow(np.arange(200).reshape((20, 10)))
add_colorbar(im)
Matthias
quelle
1
Dies ist eine wirklich hilfreiche kleine Funktion! Ein Wort der Warnung ist, dass es nicht funktioniert, wenn Sie mehrere Farbleisten hinzufügen möchten, da diese übereinander angezeigt werden.
David Hall
22

Ich schätze alle obigen Antworten. Jedoch, wie einige Antworten und Kommentare darauf hingewiesen, das axes_grid1kann Modul nicht - Adresse GeoAxes, während Einstellung fraction, pad, shrinkund andere ähnliche Parameter nicht unbedingt gibt die sehr präzise Ordnung, die wirklich stört mich. Ich glaube, dass es eine bessere Lösung colorbarsein axeskönnte , das Eigene zu geben, um alle genannten Probleme anzugehen.

Code

import matplotlib.pyplot as plt
import numpy as np

fig=plt.figure()
ax = plt.axes()
im = ax.imshow(np.arange(100).reshape((10,10)))

# Create an axes for colorbar. The position of the axes is calculated based on the position of ax.
# You can change 0.01 to adjust the distance between the main image and the colorbar.
# You can change 0.02 to adjust the width of the colorbar.
# This practice is universal for both subplots and GeoAxes.

cax = fig.add_axes([ax.get_position().x1+0.01,ax.get_position().y0,0.02,ax.get_position().height])
plt.colorbar(im, cax=cax) # Similar to fig.colorbar(im, cax = cax)

Ergebnis

Geben Sie hier die Bildbeschreibung ein

Später finde ich, dass die matplotlib.pyplot.colorbaroffizielle Dokumentation auch axOptionen bietet , bei denen es sich um vorhandene Achsen handelt, die Platz für die Farbleiste bieten. Daher ist es nützlich für mehrere Unterzeichnungen, siehe unten.

Code

fig, ax = plt.subplots(2,1,figsize=(12,8)) # Caution, figsize will also influence positions.
im1 = ax[0].imshow(np.arange(100).reshape((10,10)), vmin = -100, vmax =100)
im2 = ax[1].imshow(np.arange(-100,0).reshape((10,10)), vmin = -100, vmax =100)
fig.colorbar(im1, ax=ax)

Ergebnis

Geben Sie hier die Bildbeschreibung ein

Auch hier können Sie ähnliche Effekte erzielen, indem Sie cax angeben, was aus meiner Sicht genauer ist.

Code

fig, ax = plt.subplots(2,1,figsize=(12,8))
im1 = ax[0].imshow(np.arange(100).reshape((10,10)), vmin = -100, vmax =100)
im2 = ax[1].imshow(np.arange(-100,0).reshape((10,10)), vmin = -100, vmax =100)
cax = fig.add_axes([ax[1].get_position().x1-0.25,ax[1].get_position().y0,0.02,ax[0].get_position().y1-ax[1].get_position().y0])
fig.colorbar(im1, cax=cax)

Ergebnis

Geben Sie hier die Bildbeschreibung ein

Fei Yao
quelle
@ HS-nebula Danke für deine Kommentare und ich freue mich, dass es dir gefällt. :)
Fei Yao
Wirklich erstaunliche Antwort. Danke dir!!
Folgeyang
11

Wenn Sie den colorbarVersuch mit den Bruch- und / oder Verkleinerungsparametern erstellen .

Aus den Dokumenten:

Fraktion 0,15; Bruchteil der ursprünglichen Achsen, die für die Farbleiste verwendet werden sollen

schrumpfen 1,0; Bruchteil, um den der Farbbalken verkleinert werden soll

Steve Barnes
quelle
1
Wenn ich "Verkleinern 1.0" und "Bruch" auf irgendetwas setze, wird das Diagramm verkleinert, was sich überhaupt nicht auf die Größe des Farbbalkens auswirkt, bis das Ändern des Bruches genau das ist, was ich bereits habe. An diesem Punkt hört das Ändern des Bruches auf, irgendetwas zu tun.
Elliot
Wo genau Sie sie angeben, müssen sie Parameter für die colorbar()Funktion oder Methode sein.
Steve Barnes
Vielen Dank. Sie müssen nur den Shrink-Parameter angeben und es funktioniert wie von Zauberhand!
CodingNow
11

Alle oben genannten Lösungen sind gut, aber ich mag @ Steve's und @ bejota's am besten, da sie keine ausgefallenen Anrufe beinhalten und universell sind.

Mit universell meine ich, dass es mit jeder Art von Achsen funktioniert, einschließlich GeoAxes. Sie haben beispielsweise Achsen für die Zuordnung projiziert:

projection = cartopy.crs.UTM(zone='17N')
ax = plt.axes(projection=projection)
im = ax.imshow(np.arange(200).reshape((20, 10)))

ein Anruf bei

cax = divider.append_axes("right", size=width, pad=pad)

wird scheitern mit: KeyException: map_projection

Daher ist die einzige universelle Möglichkeit, die Farbbalkengröße mit allen Arten von Achsen zu behandeln, folgende:

ax.colorbar(im, fraction=0.046, pad=0.04)

Arbeiten Sie mit einem Bruchteil von 0,035 bis 0,046, um die beste Größe zu erhalten. Die Werte für Bruch und Paddig müssen jedoch angepasst werden, um die beste Anpassung für Ihr Diagramm zu erzielen. Sie unterscheiden sich je nachdem, ob die Ausrichtung der Farbleiste vertikal oder horizontal ist.

Bogdan
quelle
1
Wir können auch shrinkParameter hinzufügen , wenn fractionzusammen mit padnicht genügend gewünschte Ergebnisse erzielt werden.
Fei Yao