Установить диапазон цветовой шкалы в matplotlib

156

У меня есть следующий код:

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

Таким образом, получается график значений 'v' на осях X против Y, используя указанную цветовую карту. Оси X и Y идеальны, но цветовая карта распространяется между минимальным и максимальным значениями v. Я бы хотел, чтобы цветовая карта находилась в диапазоне от 0 до 1.

Я думал об использовании:

plt.axis(...)

Чтобы установить диапазоны осей, но для этого нужны аргументы только для минимального и максимального значений X и Y, а не для цветовой карты.

Редактировать:

Для ясности, скажем, у меня есть один график, значения которого находятся в диапазоне (0 ... 0,3), и другой график, значения которого (0,2 ... 0,8).

На обоих графиках я хочу, чтобы диапазон цветовой шкалы был (0 ... 1). На обоих графиках я хочу, чтобы этот диапазон цветов был идентичным с использованием полного диапазона Cdict выше (поэтому 0,25 на обоих графиках будет одного цвета). На первом графике все цвета от 0,3 до 1,0 не будут отображаться на графике, но будут отображаться на клавише с цветовой шкалой сбоку. В другом случае все цвета от 0 до 0,2, а также от 0,8 до 1 не будут отображаться на графике, но будут отображаться на цветовой шкале сбоку.

Павел
источник

Ответы:

177

Использование vminи vmaxфорсирование диапазона цветов. Вот пример:

введите описание изображения здесь

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
источник
3
Почему этот ответ лучше, чем тот, который использует plt.clim, опубликованный @Amro?
Алекс Лэмсон
90

Используйте функцию CLIM (эквивалентную функции CAXIS в MATLAB):

plt.pcolor(X, Y, v, cmap=cm)
plt.clim(-4,4)  # identical to caxis([-4,4]) in MATLAB
plt.show()
Amro
источник
2
Я считаю, что clim () масштабирует цветовые оси, но сами цвета меняют значения. Точка в определенной доле вдоль шкалы будет иметь тот же цвет, что и шкала, но значение, которое она представляет, изменится.
Пол
4
Да. Это желаемое поведение спрашивающего, поэтому решает проблему: чтобы цветовая шкала была одинаковой между графиками.
Экскалабур
16

Не уверен, что это самое элегантное решение (это то, что я использовал), но вы можете масштабировать ваши данные в диапазоне от 0 до 1, а затем изменить цветовую шкалу:

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)

С двумя различными ограничениями вы можете контролировать диапазон и легенду цветовой панели. В этом примере на панели отображается только диапазон от -0,5 до 1,5, а цветовая карта охватывает значения от -2 до 2 (так что это может быть диапазон данных, который вы записываете до масштабирования).

Поэтому вместо масштабирования карты цветов вы масштабируете свои данные и подстраиваете их под цветовую панель.

nikow
источник
1
Я думаю, что это делает что-то немного другое ... извините, я, вероятно, не был достаточно точен в своем вопросе. Ваше решение будет масштабировать цвета так, чтобы то, что раньше представляло значение 1.0, теперь представляло максимальное значение в моих данных. Цветная полоса покажет 0..1, как мне нужно (с vmin = 0, vmax = 1), но все, что выше этого максимального значения, будет одного цвета ...
Пол
1
... Я обновил свой вопрос, чтобы более четко показать, что я хочу. Извините, если я был слишком расплывчатым.
Пол
10

Использование среды рисунка и .set_clim ()

Может быть проще и безопаснее эта альтернатива, если у вас есть несколько участков:

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

введите описание изображения здесь

Единый цветовой бар

Лучшая альтернатива - использовать одну цветную полосу для всего графика. Есть разные способы сделать это, это руководство очень полезно для понимания лучшего варианта. Я предпочитаю это решение, которое вы можете просто скопировать и вставить вместо предыдущей части кода для визуализации цветовой панели .

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)

введите описание изображения здесь

PS

Я бы предложил использовать pcolormeshвместо, pcolorпотому что это быстрее (больше информации здесь ).

GM
источник