Définir la gamme de barres de couleurs dans matplotlib

156

J'ai le code suivant:

import matplotlib.pyplot as plt

cdict = {
  'red'  :  ( (0.0, 0.25, .25), (0.02, .59, .59), (1., 1., 1.)),
  'green':  ( (0.0, 0.0, 0.0), (0.02, .45, .45), (1., .97, .97)),
  'blue' :  ( (0.0, 1.0, 1.0), (0.02, .75, .75), (1., 0.45, 0.45))
}

cm = m.colors.LinearSegmentedColormap('my_colormap', cdict, 1024)

plt.clf()
plt.pcolor(X, Y, v, cmap=cm)
plt.loglog()
plt.xlabel('X Axis')
plt.ylabel('Y Axis')

plt.colorbar()
plt.show()

Cela produit donc un graphique des valeurs «v» sur les axes X vs Y, en utilisant la palette de couleurs spécifiée. Les axes X et Y sont parfaits, mais la palette de couleurs se propage entre le minimum et le maximum de v. Je voudrais forcer la palette de couleurs à se situer entre 0 et 1.

J'ai pensé à utiliser:

plt.axis(...)

Pour définir les plages des axes, mais cela ne prend que des arguments pour le min et le max de X et Y, pas la palette de couleurs.

Éditer:

Pour plus de clarté, disons que j'ai un graphique dont les valeurs varient (0 ... 0,3), et un autre graphique dont les valeurs (0,2 ... 0,8).

Dans les deux graphiques, je veux que la plage de la barre de couleurs soit (0 ... 1). Dans les deux graphiques, je veux que cette gamme de couleurs soit identique en utilisant la gamme complète de cdict ci-dessus (donc 0,25 dans les deux graphiques sera la même couleur). Dans le premier graphique, toutes les couleurs comprises entre 0,3 et 1,0 ne figureront pas dans le graphique, mais figureront dans la barre de couleurs située sur le côté. Dans l'autre, toutes les couleurs comprises entre 0 et 0,2 et entre 0,8 et 1 ne figureront pas dans le graphique, mais figureront dans la barre de couleurs sur le côté.

Paul
la source

Réponses:

177

Utiliser vminet vmaxforce la plage des couleurs. Voici un exemple:

entrez la description de l'image ici

import matplotlib as m
import matplotlib.pyplot as plt
import numpy as np

cdict = {
  'red'  :  ( (0.0, 0.25, .25), (0.02, .59, .59), (1., 1., 1.)),
  'green':  ( (0.0, 0.0, 0.0), (0.02, .45, .45), (1., .97, .97)),
  'blue' :  ( (0.0, 1.0, 1.0), (0.02, .75, .75), (1., 0.45, 0.45))
}

cm = m.colors.LinearSegmentedColormap('my_colormap', cdict, 1024)

x = np.arange(0, 10, .1)
y = np.arange(0, 10, .1)
X, Y = np.meshgrid(x,y)

data = 2*( np.sin(X) + np.sin(3*Y) )

def do_plot(n, f, title):
    #plt.clf()
    plt.subplot(1, 3, n)
    plt.pcolor(X, Y, f(data), cmap=cm, vmin=-4, vmax=4)
    plt.title(title)
    plt.colorbar()

plt.figure()
do_plot(1, lambda x:x, "all")
do_plot(2, lambda x:np.clip(x, -4, 0), "<0")
do_plot(3, lambda x:np.clip(x, 0, 4), ">0")
plt.show()
tom10
la source
3
Pourquoi cette réponse est-elle meilleure que celle utilisant plt.clim postée par @Amro?
Alex Lamson
90

Utilisez la fonction CLIM (équivalente à la fonction CAXIS dans MATLAB):

plt.pcolor(X, Y, v, cmap=cm)
plt.clim(-4,4)  # identical to caxis([-4,4]) in MATLAB
plt.show()
Amro
la source
2
Je crois que clim () met à l'échelle les axes des couleurs, mais les couleurs elles-mêmes changent de valeur. Le point à une certaine fraction le long de l'échelle sera de la même couleur quelle que soit l'échelle, mais la valeur qu'il représente changera.
Paul
4
Oui. C'est le comportement souhaité du demandeur, donc résout le problème: que l'échelle de couleur soit identique entre les graphiques.
Excalabur
16

Je ne sais pas si c'est la solution la plus élégante (c'est ce que j'ai utilisé), mais vous pouvez mettre à l'échelle vos données dans la plage comprise entre 0 et 1, puis modifier la barre de couleurs:

import matplotlib as mpl
...
ax, _ = mpl.colorbar.make_axes(plt.gca(), shrink=0.5)
cbar = mpl.colorbar.ColorbarBase(ax, cmap=cm,
                       norm=mpl.colors.Normalize(vmin=-0.5, vmax=1.5))
cbar.set_clim(-2.0, 2.0)

Avec les deux limites différentes, vous pouvez contrôler la plage et la légende de la barre de couleurs. Dans cet exemple, seule la plage comprise entre -0,5 et 1,5 est affichée dans la barre, tandis que la palette de couleurs couvre -2 à 2 (il peut donc s'agir de votre plage de données, que vous enregistrez avant la mise à l'échelle).

Ainsi, au lieu de mettre à l'échelle la palette de couleurs, vous mettez à l'échelle vos données et adaptez la barre de couleurs à cela.

nikow
la source
1
Je pense que cela fait quelque chose de subtilement différent… désolé, je n'étais probablement pas assez précis dans ma question. Votre solution mettra à l'échelle les couleurs de sorte que ce qui représentait la valeur 1.0 représentera désormais la valeur maximale dans mes données. La barre de couleur affichera 0..1 comme j'en ai besoin (avec vmin = 0, vmax = 1), mais tout ce qui dépasse cette valeur maximale sera de la même couleur ...
Paul
1
... J'ai mis à jour ma question pour montrer plus clairement ce que je recherche. Désolé si j'étais trop vague.
Paul
10

Utilisation de l'environnement figure et .set_clim ()

Cette alternative pourrait être plus simple et plus sûre si vous avez plusieurs parcelles:

import matplotlib as m
import matplotlib.pyplot as plt
import numpy as np

cdict = {
  'red'  :  ( (0.0, 0.25, .25), (0.02, .59, .59), (1., 1., 1.)),
  'green':  ( (0.0, 0.0, 0.0), (0.02, .45, .45), (1., .97, .97)),
  'blue' :  ( (0.0, 1.0, 1.0), (0.02, .75, .75), (1., 0.45, 0.45))
}

cm = m.colors.LinearSegmentedColormap('my_colormap', cdict, 1024)

x = np.arange(0, 10, .1)
y = np.arange(0, 10, .1)
X, Y = np.meshgrid(x,y)

data = 2*( np.sin(X) + np.sin(3*Y) )
data1 = np.clip(data,0,6)
data2 = np.clip(data,-6,0)
vmin = np.min(np.array([data,data1,data2]))
vmax = np.max(np.array([data,data1,data2]))

fig = plt.figure()
ax = fig.add_subplot(131)
mesh = ax.pcolormesh(data, cmap = cm)
mesh.set_clim(vmin,vmax)
ax1 = fig.add_subplot(132)
mesh1 = ax1.pcolormesh(data1, cmap = cm)
mesh1.set_clim(vmin,vmax)
ax2 = fig.add_subplot(133)
mesh2 = ax2.pcolormesh(data2, cmap = cm)
mesh2.set_clim(vmin,vmax)
# Visualizing colorbar part -start
fig.colorbar(mesh,ax=ax)
fig.colorbar(mesh1,ax=ax1)
fig.colorbar(mesh2,ax=ax2)
fig.tight_layout()
# Visualizing colorbar part -end

plt.show()

entrez la description de l'image ici

Une seule barre de couleurs

La meilleure alternative est alors d'utiliser une seule barre de couleur pour l'ensemble du tracé. Il existe différentes manières de le faire, ce tutoriel est très utile pour comprendre la meilleure option. Je préfère cette solution que vous pouvez simplement copier et coller au lieu de la partie précédente de la barre de couleurs de visualisation du code.

fig.subplots_adjust(bottom=0.1, top=0.9, left=0.1, right=0.8,
                    wspace=0.4, hspace=0.1)
cb_ax = fig.add_axes([0.83, 0.1, 0.02, 0.8])
cbar = fig.colorbar(mesh, cax=cb_ax)

entrez la description de l'image ici

PS

Je suggérerais d'utiliser pcolormeshau lieu de pcolorcar c'est plus rapide (plus d' infos ici ).

GM
la source