Stellen Sie den Farbbalkenbereich in matplotlib ein

155

Ich habe folgenden Code:

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

Dies erzeugt also ein Diagramm der Werte 'v' auf den Achsen X gegen Y unter Verwendung der angegebenen Farbkarte. Die X- und Y-Achse sind perfekt, aber die Farbkarte verteilt sich zwischen min und max von v. Ich möchte die Farbkarte zwingen, zwischen 0 und 1 zu liegen.

Ich dachte an:

plt.axis(...)

Um die Bereiche der Achsen festzulegen, werden jedoch nur Argumente für min und max von X und Y verwendet, nicht für die Farbkarte.

Bearbeiten:

Nehmen wir zur Verdeutlichung an, ich habe ein Diagramm, dessen Wertebereich (0 ... 0,3) beträgt, und ein anderes Diagramm, dessen Werte (0,2 ... 0,8).

In beiden Diagrammen soll der Bereich der Farbleiste (0 ... 1) sein. In beiden Diagrammen möchte ich, dass dieser Farbbereich unter Verwendung des gesamten obigen Bereichs von cdict identisch ist (daher haben 0,25 in beiden Diagrammen dieselbe Farbe). Im ersten Diagramm werden nicht alle Farben zwischen 0,3 und 1,0 im Diagramm angezeigt, sondern in der Farbbalken-Taste an der Seite. Im anderen Fall werden alle Farben zwischen 0 und 0,2 sowie zwischen 0,8 und 1 nicht im Diagramm angezeigt, sondern in der Farbleiste an der Seite.

Paul
quelle

Antworten:

177

Verwenden vminund vmaxerzwingen Sie den Bereich für die Farben. Hier ist ein Beispiel:

Geben Sie hier die Bildbeschreibung ein

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
quelle
3
Warum ist diese Antwort besser als die mit plt.clim von @Amro?
Alex Lamson
88

Verwenden Sie die CLIM- Funktion (entspricht der CAXIS- Funktion in MATLAB):

plt.pcolor(X, Y, v, cmap=cm)
plt.clim(-4,4)  # identical to caxis([-4,4]) in MATLAB
plt.show()
Amro
quelle
2
Ich glaube, klim () skaliert die Farbachsen, aber die Farben selbst ändern ihre Werte. Der Punkt an einem bestimmten Bruchteil entlang der Skala hat unabhängig von der Skala dieselbe Farbe, aber der Wert, den er darstellt, ändert sich.
Paul
4
Ja. Dies ist das gewünschte Verhalten des Fragestellers, wodurch das Problem gelöst wird: Die Farbskala ist zwischen den Diagrammen identisch.
Excalabur
16

Ich bin mir nicht sicher, ob dies die eleganteste Lösung ist (das habe ich verwendet), aber Sie können Ihre Daten auf den Bereich zwischen 0 und 1 skalieren und dann die Farbleiste ändern:

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)

Mit den zwei verschiedenen Grenzwerten können Sie den Bereich und die Legende der Farbleiste steuern. In diesem Beispiel wird in der Leiste nur der Bereich zwischen -0,5 und 1,5 angezeigt, während die Farbkarte -2 bis 2 abdeckt (dies könnte also Ihr Datenbereich sein, den Sie vor der Skalierung aufzeichnen).

Anstatt die Farbkarte zu skalieren, skalieren Sie Ihre Daten und passen die Farbleiste daran an.

Nikow
quelle
1
Ich denke, das macht etwas subtil anderes… Entschuldigung, ich war in meiner Frage wahrscheinlich nicht präzise genug. Ihre Lösung skaliert die Farben so, dass das, was früher den Wert 1.0 darstellte, jetzt den Maximalwert in meinen Daten darstellt. Die Farbleiste zeigt 0..1 an, wie ich es brauche (mit vmin = 0, vmax = 1), aber alles über diesem Maximalwert hat dieselbe Farbe ...
Paul
1
... Ich habe meine Frage aktualisiert, um klarer zu zeigen, wonach ich suche. Entschuldigung, wenn ich zu vage war.
Paul
10

Verwenden der Figurenumgebung und .set_clim ()

Diese Alternative könnte einfacher und sicherer sein, wenn Sie mehrere Grundstücke haben:

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

Geben Sie hier die Bildbeschreibung ein

Eine einzelne Farbleiste

Die beste Alternative ist dann, einen einzelnen Farbbalken für das gesamte Diagramm zu verwenden. Es gibt verschiedene Möglichkeiten, dies zu tun. Dieses Tutorial ist sehr nützlich, um die beste Option zu verstehen. Ich bevorzuge diese Lösung, die Sie einfach kopieren und einfügen können, anstatt den vorherigen Teil des Codes in der Farbleiste zu visualisieren .

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)

Geben Sie hier die Bildbeschreibung ein

PS

Ich würde vorschlagen, pcolormeshanstatt zu verwenden, pcolorweil es schneller ist (mehr Infos hier ).

GM
quelle