Atur Rentang Colorbar di matplotlib

156

Saya memiliki kode berikut:

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

Jadi ini menghasilkan grafik dari nilai 'v' pada sumbu X vs Y, menggunakan colormap yang ditentukan. Sumbu X dan Y sempurna, tetapi colormap menyebar antara min dan maks v. Saya ingin memaksa colormap berkisar antara 0 dan 1.

Saya berpikir untuk menggunakan:

plt.axis(...)

Untuk mengatur rentang sumbu, tetapi ini hanya membutuhkan argumen untuk min dan maks X dan Y, bukan colormap.

Edit:

Untuk kejelasan, katakanlah saya memiliki satu grafik yang nilainya berkisar (0 ... 0,3), dan grafik lain yang nilainya (0,2 ... 0,8).

Dalam kedua grafik, saya ingin kisaran bilah warna menjadi (0 ... 1). Dalam kedua grafik, saya ingin rentang warna ini identik dengan menggunakan rentang penuh cdict di atas (jadi 0,25 pada kedua grafik akan memiliki warna yang sama). Pada grafik pertama, semua warna antara 0,3 dan 1,0 tidak akan ditampilkan dalam grafik, tetapi akan di tombol colourbar di samping. Di yang lain, semua warna antara 0 dan 0,2, dan antara 0,8 dan 1 tidak akan ditampilkan dalam grafik, tetapi akan di colourbar di samping.

Paul
sumber

Jawaban:

177

Menggunakan vmindan vmaxmemaksa rentang untuk warna. Ini sebuah contoh:

masukkan deskripsi gambar di sini

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
sumber
3
Mengapa jawaban ini lebih baik daripada yang menggunakan plt.clim yang diposting oleh @Amro?
Alex Lamson
90

Gunakan fungsi CLIM (setara dengan fungsi CAXIS di MATLAB):

plt.pcolor(X, Y, v, cmap=cm)
plt.clim(-4,4)  # identical to caxis([-4,4]) in MATLAB
plt.show()
Amro
sumber
2
Saya percaya clim () menskalakan sumbu warna, tetapi warna itu sendiri mengubah nilai. Titik pada fraksi tertentu di sepanjang skala akan menjadi warna yang sama apa pun skalanya, tetapi nilai yang diwakilinya akan berubah.
Paul
4
Iya. Ini adalah perilaku penanya yang diinginkan, jadi selesaikan masalahnya: bahwa skala warna identik di antara grafik.
Excalabur
16

Tidak yakin apakah ini solusi yang paling elegan (inilah yang saya gunakan), tetapi Anda bisa menskala data Anda ke kisaran antara 0 hingga 1 lalu memodifikasi bilah warna:

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)

Dengan dua batas berbeda Anda dapat mengontrol rentang dan legenda bilah warna. Dalam contoh ini hanya rentang antara -0,5 hingga 1,5 yang ditampilkan di bilah, sedangkan colormap mencakup -2 hingga 2 (jadi ini bisa menjadi rentang data Anda, yang Anda rekam sebelum penskalaan).

Jadi, alih-alih menskalakan colormap, Anda skala data Anda dan cocok dengan colorbar itu.

nikow
sumber
1
Saya pikir itu melakukan sesuatu yang agak berbeda ... maaf saya mungkin tidak cukup tepat dalam pertanyaan saya. Solusi Anda akan menskalakan warna sehingga apa yang digunakan untuk mewakili nilai 1.0 sekarang akan mewakili nilai maks dalam data saya. Colorbar akan menunjukkan 0..1 sesuai kebutuhan saya (dengan vmin = 0, vmax = 1), tetapi semua yang di atas nilai maks ini akan berwarna sama ...
Paul
1
... Saya telah memperbarui pertanyaan saya untuk menunjukkan apa yang saya cari lebih jelas. Maaf jika saya terlalu kabur.
Paul
10

Menggunakan lingkungan gambar dan .set_clim ()

Alternatif ini bisa lebih mudah dan aman jika Anda memiliki banyak plot:

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

masukkan deskripsi gambar di sini

Bilah warna tunggal

Alternatif terbaik adalah dengan menggunakan bilah warna tunggal untuk seluruh plot. Ada berbagai cara untuk melakukan itu, ini tutorial sangat berguna untuk memahami pilihan terbaik. Saya lebih suka solusi ini yang bisa Anda salin dan tempel alih-alih bagian visualisasi colorbar sebelumnya dari kode.

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)

masukkan deskripsi gambar di sini

PS

Saya sarankan menggunakan pcolormeshdaripada pcolorkarena lebih cepat ( info lebih lanjut di sini ).

GM
sumber