Définir la taille de la barre de couleurs Matplotlib pour qu'elle corresponde au graphique

161

Je ne peux pas obtenir la barre de couleurs sur les graphiques imshow comme celui-ci à la même hauteur que le graphique, à moins d'utiliser Photoshop après coup. Comment faire correspondre les hauteurs?Exemple de non-concordance de taille de barre de couleur

Elliot
la source
Avez-vous essayé les suggestions de stackoverflow.com/questions/16702479/…
lmjohns3
@ imjohns3 Rien dans ce message ne semble faire quoi que ce soit à la barre de couleurs. Il reste la même taille, peu importe ce que j'ai défini. Si je règle la fraction et la réduction, la taille du graphique changera alors que la barre de couleur restera la même, jusqu'à ce que nous revenions à ce que j'ai déjà, alors ils cesseront de faire quoi que ce soit.
Elliot
Consultez la documentation - matplotlib.org/api/colorbar_api.html - et utilisez fractionou shrinkargs.
BoltzmannBrain

Réponses:

194

Vous pouvez le faire facilement avec un AxisDivider matplotlib .

L'exemple de la page liée fonctionne également sans utiliser de sous-graphiques:

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)

entrez la description de l'image ici

Bogatron
la source
1
Je ne travaille pas dans une sous-parcelle, donc cela ne s'applique pas.
Elliot
Après beaucoup de bricolage, je l'ai fait fonctionner. A beaucoup de mal à interagir avec subplot_adjust, vous devez recevoir les appels aux bons endroits les uns par rapport aux autres.
Elliot
11
Cela modifie légèrement la taille des graphiques. J'ai 4 dans une grille 2x2, mais je veux seulement que les deux à droite aient des barres (l'échelle s'applique par ligne). Cependant, cela ne les rend pas de la même taille. J'ai simplement essayé de ne pas avoir l'appel de la barre de couleurs (avec l'appel du diviseur), mais bien sûr, cela laisse une boîte blanche vide et des chiffres sur le côté. Comment les faire avoir une taille cohérente sans mettre de barres sur chacun d'eux?
Elliot
@bogatron Malheureusement, cela ne fonctionne pas avec les axes projetés
Bogdan
Si vous souhaitez ajouter un titre en utilisant plt.title, il sera affiché inversé vers la droite. Y a-t-il un moyen de surmonter cela?
user2820579
225

Cette combinaison (et des valeurs proches de celles-ci) semble fonctionner "comme par magie" pour que je garde la barre de couleurs à l'échelle du tracé, quelle que soit la taille de l'affichage.

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

Il ne nécessite pas non plus de partager l'axe qui peut extraire le tracé du carré.

skytaker
la source
4
Cela peut fonctionner dans certains cas, mais en général, ce n'est pas le cas. Essayez, par exemple, de tracer quelque chose comme dans la question d'origine, qui a une largeur deux fois la hauteur.
Matthias
L'option de fraction semble toujours fonctionner dans le cas que vous mentionnez, si elle est mise à l'échelle pour correspondre à la hauteur du tracé. (mpl v1.4.3)
skytaker
6
C'est la seule manière universelle de le faire. Les solutions avec axex_grid1 ne fonctionneront pas pour les axes projetés tels que GeoAxes.
Bogdan
OMG c'est génial. Merci beaucoup pour la solution
2D_
3
En réponse au commentaire de @Matthias. Vous pouvez corriger le cas où l'image est trop large en utilisant cette astuce: im_ratio = data.shape[0]/data.shape[1] plt.colorbar(im,fraction=0.046*im_ratio, pad=0.04)dataest votre image.
eindzl
30

@bogatron a déjà donné la réponse suggérée par la documentation matplotlib , qui produit la bonne hauteur, mais cela introduit un problème différent. Désormais, la largeur de la barre de couleurs (ainsi que l'espace entre la barre de couleurs et le tracé) change avec la largeur du tracé. En d'autres termes, le rapport hauteur / largeur de la barre de couleurs n'est plus fixe.

Pour obtenir à la fois la bonne hauteur et un rapport hauteur / largeur donné, vous devez creuser un peu plus le axes_grid1module mystérieux .

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)

Notez que cela spécifie la largeur de la barre de couleurs par rapport à la hauteur du tracé (contrairement à la largeur de la figure, comme avant).

L'espacement entre la barre de couleur et le tracé peut maintenant être spécifié comme une fraction de la largeur de la barre de couleur, qui est à mon humble avis un nombre beaucoup plus significatif qu'une fraction de la largeur de la figure.

tracé d'image avec barre de couleurs

METTRE À JOUR:

J'ai créé un cahier IPython sur le sujet , dans lequel j'ai emballé le code ci-dessus dans une fonction facilement réutilisable:

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)

Il peut être utilisé comme ceci:

im = plt.imshow(np.arange(200).reshape((20, 10)))
add_colorbar(im)
Matthias
la source
1
C'est une petite fonction vraiment utile! Un mot d'avertissement est que cela ne fonctionne pas lorsque vous souhaitez ajouter plusieurs barres de couleurs, car elles apparaissent les unes sur les autres.
David Hall
22

J'apprécie toutes les réponses ci-dessus. Cependant, comme certaines réponses et commentaires ont fait remarquer, le axes_grid1module ne peut répondre à GeoAxes, alors que le réglage fraction, pad, shrinket d' autres paramètres similaires ne peut pas donner nécessairement l'ordre très précis, ce qui me dérange vraiment. Je pense que donner le colorbarsien axespourrait être une meilleure solution pour résoudre tous les problèmes qui ont été mentionnés.

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)

Résultat

entrez la description de l'image ici

Plus tard, je trouve matplotlib.pyplot.colorbarque la documentation officielle donne égalementax options, qui sont des axes existants qui fourniront de la place pour la barre de couleurs. Par conséquent, il est utile pour plusieurs sous-graphiques, voir ci-dessous.

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)

Résultat

entrez la description de l'image ici

Encore une fois, vous pouvez également obtenir des effets similaires en spécifiant cax, une manière plus précise de mon point de vue.

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)

Résultat

entrez la description de l'image ici

Fei Yao
la source
@ HS-nébuleuse Merci pour vos commentaires et je suis ravi que vous l'appréciez. :)
Fei Yao
Réponse vraiment incroyable. Je vous remercie!!
episodeyang
11

Lorsque vous créez le colorbar essai à l'aide des paramètres de fraction et / ou de réduction.

À partir des documents:

fraction 0,15; fraction d'axes d'origine à utiliser pour la barre de couleurs

rétrécir 1,0; fraction par laquelle réduire la barre de couleurs

Steve Barnes
la source
1
Si je règle shrink 1.0 et fraction sur n'importe quoi, cela réduit le graphique, sans affecter du tout la taille de la barre de couleur, jusqu'à ce que le changement de fraction le fasse être exactement ce que j'ai déjà, à quel point les changer cesse de faire quoi que ce soit.
Elliot
Où exactement les spécifiez-vous, ils doivent être des paramètres de la colorbar()fonction ou de la méthode.
Steve Barnes
Merci. il suffit de spécifier le paramètre shrink et cela fonctionne comme par magie!
CodingNow
11

Toutes les solutions ci-dessus sont bonnes, mais j'aime les meilleures de @ Steve et @ bejota car elles n'impliquent pas d'appels sophistiqués et sont universelles.

Par universel, je veux dire qui fonctionne avec tout type d'axes, y compris GeoAxes. Par exemple, si vous avez des axes projetés pour le mappage:

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

un appel à

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

échouera avec: KeyException: map_projection

Par conséquent, le seul moyen universel de gérer la taille de la barre de couleurs avec tous les types d'axes est:

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

Travaillez avec une fraction de 0,035 à 0,046 pour obtenir votre meilleure taille. Cependant, les valeurs de la fraction et du paddig devront être ajustées pour obtenir le meilleur ajustement pour votre tracé et différeront selon si l'orientation de la barre de couleurs est en position verticale ou horizontale.

Bogdan
la source
1
Nous pouvons également ajouter le shrinkparamètre lorsque fractionainsi padne produisent pas assez les résultats souhaités.
Fei Yao