Imposta la dimensione della barra dei colori di Matplotlib in modo che corrisponda al grafico


161

Non riesco a far sì che la barra dei colori nei grafici imshow come questa abbia la stessa altezza del grafico, a meno di usare Photoshop dopo il fatto. Come faccio ad abbinare le altezze?Esempio di mancata corrispondenza delle dimensioni della barra dei colori


Hai provato i suggerimenti da stackoverflow.com/questions/16702479/...
lmjohns3

@ imjohns3 Nulla in quel post sembra fare nulla alla barra dei colori. Rimane della stessa dimensione, qualunque cosa io abbia impostato. Se imposto la frazione e la restringimento, tuttavia, la dimensione del grafico cambierà mentre la barra dei colori rimane invariata, finché non torniamo a ciò che ho già, quindi smettono di fare qualsiasi cosa.
Elliot,

Dai un'occhiata ai documenti - matplotlib.org/api/colorbar_api.html - e usa fractiono shrinkargs.
BoltzmannBrain,

Risposte:


194

Puoi farlo facilmente con un AxisDivider matplotlib .

L'esempio della pagina collegata funziona anche senza l'utilizzo di sottotrame:

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)

inserisci qui la descrizione dell'immagine


1
Non sto lavorando all'interno di una sottotrama, quindi questo non è applicabile.
Elliot,

Dopo aver armeggiato molto, è riuscito a farlo funzionare. Ha molti problemi a interagire con subplot_adjust, devi ricevere le chiamate nei posti giusti l'una rispetto all'altra.
Elliot,

11
Questo sta leggermente cambiando il dimensionamento dei grafici. Ne ho 4 in una griglia 2x2, ma voglio solo che i due a destra abbiano delle barre (la scala si applica per riga). Tuttavia, ciò non li rende delle stesse dimensioni. Ho provato a non avere la chiamata della barra dei colori (con la chiamata del divisore), ma ovviamente questo lascia una casella bianca vuota e numeri sul lato. Come faccio a farli avere una dimensione coerente senza mettere le barre su tutti loro?
Elliot,

@bogatron Purtroppo questo non funziona con gli assi proiettati
Bogdan,

Se si desidera aggiungere un titolo utilizzando plt.title, verrà visualizzato scambiato a destra. C'è un modo per superare questo?
user2820579,

225

Questa combinazione (e valori vicini a questi) sembra "magicamente" funzionare per me per mantenere la barra dei colori adattata alla trama, indipendentemente dalle dimensioni del display.

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

Inoltre non richiede la condivisione dell'asse che può far uscire il diagramma dal quadrato.


4
Questo può funzionare in alcuni casi, ma in generale no. Prova, ad esempio, a tracciare qualcosa di simile alla domanda originale, che ha una larghezza doppia rispetto all'altezza.
Matthias,

L'opzione frazione sembra funzionare nel caso in cui menzioni, se ridimensionata per adattarsi all'altezza della trama. (mpl v1.4.3)
skytaker

6
Questo è l'unico modo universale per farlo. Le soluzioni con axex_grid1 non funzioneranno con assi proiettati come GeoAxes.
Bogdan,

OMG questo è fantastico. Grazie mille per la soluzione
2D_

3
In risposta al commento di @Matthias. Puoi correggere il caso in cui l'immagine è troppo ampia usando questo trucco: im_ratio = data.shape[0]/data.shape[1] plt.colorbar(im,fraction=0.046*im_ratio, pad=0.04)dov'è la datatua immagine.
eindzl,

30

@bogatron ha già dato la risposta suggerita dai documenti matplotlib , che produce la giusta altezza, ma introduce un problema diverso. Ora la larghezza della barra dei colori (così come lo spazio tra la barra dei colori e la trama) cambia con la larghezza della trama. In altre parole, le proporzioni della barra dei colori non sono più fisse.

Per ottenere sia la giusta altezza che un determinato formato, devi scavare un po 'più a fondo nel axes_grid1modulo misterioso .

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)

Si noti che questo specifica la larghezza della barra colorata rispetto all'altezza della trama (in contrasto con la larghezza della figura, come era prima).

La spaziatura tra la barra dei colori e la trama può ora essere specificata come una frazione della larghezza della barra dei colori, che è IMHO un numero molto più significativo di una frazione della larghezza della figura.

trama immagine con barra dei colori

AGGIORNARE:

Ho creato un notebook IPython sull'argomento , in cui ho inserito il codice sopra in una funzione facilmente riutilizzabile:

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)

Può essere usato in questo modo:

im = plt.imshow(np.arange(200).reshape((20, 10)))
add_colorbar(im)

1
Questa è una piccola funzione davvero utile! Un avvertimento è che non funziona quando si desidera aggiungere più barre dei colori, perché appaiono uno sopra l'altro.
David Hall,

22

Apprezzo tutte le risposte sopra. Tuttavia, come alcune risposte e commenti hanno sottolineato, il axes_grid1modulo può non GeoAxes di indirizzo, mentre la regolazione fraction, pad, shrink, e altri parametri simili può non necessariamente dare l'ordine ben preciso, che in realtà mi disturba. Credo che dare il colorbarproprio axespotrebbe essere una soluzione migliore per affrontare tutti i problemi che sono stati menzionati.

Codice

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)

Risultato

inserisci qui la descrizione dell'immagine

In seguito, trovo matplotlib.pyplot.colorbarche anche la documentazione ufficiale offra l' axopzione, che sono assi esistenti che offriranno spazio per la barra dei colori. Pertanto, è utile per più sottotrame, vedere di seguito.

Codice

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)

Risultato

inserisci qui la descrizione dell'immagine

Ancora una volta, puoi anche ottenere effetti simili specificando cax, un modo più accurato dal mio punto di vista.

Codice

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)

Risultato

inserisci qui la descrizione dell'immagine


@ HS-nebula Grazie per i tuoi commenti e sono lieto che ti piaccia. :)
Fei Yao,

Risposta davvero sorprendente. Grazie!!
episodeyang

11

Quando si crea il file colorbar tentativo, utilizzare i parametri frazione e / o riduzione.

Dai documenti:

frazione 0,15; frazione degli assi originali da utilizzare per la barra dei colori

ridurre 1.0; frazione con cui ridurre la barra dei colori


1
Se imposto la riduzione di 1.0 e la frazione su qualsiasi cosa, restringe il grafico, senza influenzare affatto la dimensione della barra dei colori, fino a quando la modifica della frazione non fa sì che sia esattamente quello che ho già, a quel punto cambiarli smette di fare qualsiasi cosa.
Elliot,

Dove esattamente li stai specificando, devono essere parametri della colorbar()funzione o del metodo.
Steve Barnes,

Grazie. ho solo bisogno di specificare il parametro shrink e funziona come per magia!
CodingNow

11

Tutte le soluzioni di cui sopra sono buone, ma mi piacciono le migliori di @ Steve e @ bejota in quanto non prevedono chiamate fantasiose e sono universali.

Con universale intendo che funziona con qualsiasi tipo di assi compreso GeoAxes. Ad esempio, hai degli assi proiettati per la mappatura:

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

una chiamata a

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

fallirà con: KeyException: map_projection

Pertanto, l'unico modo universale di trattare le dimensioni della barra dei colori con tutti i tipi di assi è:

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

Lavora con una frazione da 0,035 a 0,046 per ottenere la tua taglia migliore. Tuttavia, i valori per la frazione e il paddig dovranno essere regolati per adattarsi al meglio alla trama e differiranno a seconda che l'orientamento della barra dei colori sia in posizione verticale o orizzontale.


1
Possiamo anche aggiungere shrinkparametri quando fractioninsieme padnon producono abbastanza risultati desiderati.
Fei Yao,
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.