2010-07-19 4 views
138

Я хотел бы знать, как просто изменить порядок цветов заданной цветовой карты, чтобы использовать ее с plot_surface.Инвертировать colormap в matplotlib

+0

Название должно быть «Revert» not «Invert». Есть разница! –

ответ

268

Стандартные цветовые карты также имеют обратные версии. Они имеют одинаковые имена с _r, прикрепленными к концу. (Documentation here.)

+0

Это не работает с «amfhot»: «ValueError: Colormap amfhot_r не распознается». Я полагаю, что «hot_r» будет достаточно. – shockburner

+0

Аналогично, «ValueError: Colormap red_r не распознается». –

12

В matplotlib цветная карта не является списком, но содержит список ее цветов как colormap.colors. А модуль matplotlib.colors предоставляет функцию ListedColormap() для создания цветовой карты из списка. Таким образом, вы можете обратить любой цвет карты, делая

colormap_r = ListedColormap(colormap.colors[::-1]) 
+7

+1. Однако это не приведет к обратному изменению любой цветовой карты. Только 'ListedColormap' (т. Е. Дискретный, а не интерполированный) имеет атрибут' colors'. Реверсирование 'LinearSegmentedColormaps' немного сложнее. (Вам нужно отменить каждый элемент в dict '_segmentdata'.) –

+3

Что касается обратного' LinearSegmentedColormaps', я просто сделал это для некоторых colourmaps. [Вот записная книжка IPython об этом.] (Http://nbviewer.ipython.org/github/kwinkunks/notebooks/blob/master/Matteo_colourmaps.ipynb) – kwinkunks

+0

@kwinkunks Я думаю, что функция в вашем ноутбуке неверна, см. Ответ ниже – Mattijn

6

в качестве LinearSegmentedColormaps основан на словаре красного, зеленого и синего цветов, необходимо обратить каждый элемент:

import matplotlib.pyplot as plt 
import matplotlib as mpl 
def reverse_colourmap(cmap, name = 'my_cmap_r'): 
    """ 
    In: 
    cmap, name 
    Out: 
    my_cmap_r 

    Explanation: 
    t[0] goes from 0 to 1 
    row i: x y0 y1 -> t[0] t[1] t[2] 
       /
       /
    row i+1: x y0 y1 -> t[n] t[1] t[2] 

    so the inverse should do the same: 
    row i+1: x y1 y0 -> 1-t[0] t[2] t[1] 
       /
       /
    row i: x y1 y0 -> 1-t[n] t[2] t[1] 
    """   
    reverse = [] 
    k = [] 

    for key in cmap._segmentdata:  
     k.append(key) 
     channel = cmap._segmentdata[key] 
     data = [] 

     for t in channel:      
      data.append((1-t[0],t[2],t[1]))    
     reverse.append(sorted(data))  

    LinearL = dict(zip(k,reverse)) 
    my_cmap_r = mpl.colors.LinearSegmentedColormap(name, LinearL) 
    return my_cmap_r 

Смотри, что он работает:

my_cmap   
<matplotlib.colors.LinearSegmentedColormap at 0xd5a0518> 

my_cmap_r = reverse_colourmap(my_cmap) 

fig = plt.figure(figsize=(8, 2)) 
ax1 = fig.add_axes([0.05, 0.80, 0.9, 0.15]) 
ax2 = fig.add_axes([0.05, 0.475, 0.9, 0.15]) 
norm = mpl.colors.Normalize(vmin=0, vmax=1) 
cb1 = mpl.colorbar.ColorbarBase(ax1, cmap = my_cmap, norm=norm,orientation='horizontal') 
cb2 = mpl.colorbar.ColorbarBase(ax2, cmap = my_cmap_r, norm=norm, orientation='horizontal') 

enter image description here

ED IT


Я не получаю замечание user3445587. Он отлично работает на радужной палитре:

cmap = mpl.cm.jet 
cmap_r = reverse_colourmap(cmap) 

fig = plt.figure(figsize=(8, 2)) 
ax1 = fig.add_axes([0.05, 0.80, 0.9, 0.15]) 
ax2 = fig.add_axes([0.05, 0.475, 0.9, 0.15]) 
norm = mpl.colors.Normalize(vmin=0, vmax=1) 
cb1 = mpl.colorbar.ColorbarBase(ax1, cmap = cmap, norm=norm,orientation='horizontal') 
cb2 = mpl.colorbar.ColorbarBase(ax2, cmap = cmap_r, norm=norm, orientation='horizontal') 

enter image description here

Но это особенно хорошо работает для пользовательских объявлены цветовых карт, так как это не по умолчанию _r для пользовательских объявлены цветовых карт. Следуя примеру взяты из http://matplotlib.org/examples/pylab_examples/custom_cmap.html:

cdict1 = {'red': ((0.0, 0.0, 0.0), 
        (0.5, 0.0, 0.1), 
        (1.0, 1.0, 1.0)), 

     'green': ((0.0, 0.0, 0.0), 
        (1.0, 0.0, 0.0)), 

     'blue': ((0.0, 0.0, 1.0), 
        (0.5, 0.1, 0.0), 
        (1.0, 0.0, 0.0)) 
     } 

blue_red1 = mpl.colors.LinearSegmentedColormap('BlueRed1', cdict1) 
blue_red1_r = reverse_colourmap(blue_red1) 

fig = plt.figure(figsize=(8, 2)) 
ax1 = fig.add_axes([0.05, 0.80, 0.9, 0.15]) 
ax2 = fig.add_axes([0.05, 0.475, 0.9, 0.15]) 

norm = mpl.colors.Normalize(vmin=0, vmax=1) 
cb1 = mpl.colorbar.ColorbarBase(ax1, cmap = blue_red1, norm=norm,orientation='horizontal') 
cb2 = mpl.colorbar.ColorbarBase(ax2, cmap = blue_red1_r, norm=norm, orientation='horizontal') 

enter image description here

+0

Этот пример не является полным в том смысле, что данные сегмента не должны быть в списках, поэтому он не обязательно обратим (например, стандартная цветовая схема радуги). Я думаю, что в принципе все LinearSegmentedColormaps должны в принципе быть обратимыми с помощью лямбда-функции, как в радужной цветовой палитре? – overseas

+0

@ user3445587 Я добавляю еще несколько примеров, но я думаю, что это нормально работает на стандартной цветовой палитре радуги. – Mattijn

+0

Поскольку это было слишком долго, я добавил новый ответ, который должен работать для всех типов LinearSegmentData. Проблема в том, что для радуги _segmentdata реализована по-разному. Таким образом, ваш код - по крайней мере, на моей машине - не работает с цветовой областью радуги. – overseas

1

Есть два типа LinearSegmentedColormaps. В некоторых, _segmentdata дается в явном виде, например, для струи:

>>> cm.jet._segmentdata 
{'blue': ((0.0, 0.5, 0.5), (0.11, 1, 1), (0.34, 1, 1), (0.65, 0, 0), (1, 0, 0)), 'red': ((0.0, 0, 0), (0.35, 0, 0), (0.66, 1, 1), (0.89, 1, 1), (1, 0.5, 0.5)), 'green': ((0.0, 0, 0), (0.125, 0, 0), (0.375, 1, 1), (0.64, 1, 1), (0.91, 0, 0), (1, 0, 0))} 

Для радуги, _segmentdata задается следующим образом:

>>> cm.rainbow._segmentdata 
{'blue': <function <lambda> at 0x7fac32ac2b70>, 'red': <function <lambda> at 0x7fac32ac7840>, 'green': <function <lambda> at 0x7fac32ac2d08>} 

Мы можем найти функции в источнике Matplotlib, где они приведены в

_rainbow_data = { 
     'red': gfunc[33], # 33: lambda x: np.abs(2 * x - 0.5), 
     'green': gfunc[13], # 13: lambda x: np.sin(x * np.pi), 
     'blue': gfunc[10], # 10: lambda x: np.cos(x * np.pi/2) 
} 

Все, что вы хотите это уже сделано в Matplotlib, просто называют cm.revcmap, который переворачивает оба типа segmentdata, так

cm.revcmap(cm.rainbow._segmentdata) 

должен выполнить эту работу - вы можете просто создать новую LinearSegmentData из этого.В revcmap, реверсирование функции на основе SegmentData делается с

def _reverser(f): 
    def freversed(x): 
     return f(1 - x) 
    return freversed 

в то время как другие списки поменялись местами, как обычно

valnew = [(1.0 - x, y1, y0) for x, y0, y1 in reversed(val)] 

Так на самом деле все, что вы хотите, это

def reverse_colourmap(cmap, name = 'my_cmap_r'): 
    return mpl.colors.LinearSegmentedColormap(name, cm.revcmap(cmap._segmentdata)) 
2

Решение довольно простое. Предположим, вы хотите использовать схему осенних цветов. Стандартная версия:

cmap = matplotlib.cm.autumn 

Чтобы изменить спектр палитры цвета, используйте get_cmap() функцию и добавить «_R» в название палитры, как это:

cmap_reversed = matplotlib.cm.get_cmap('autumn_r') 
1

Там нет встроенного способа (пока) реверсирований произвольных цветовых карт, но одно простое решение фактически не изменяет Colorbar но создать объект инвертирующего Normalize:

from matplotlib.colors import Normalize 

class InvertedNormalize(Normalize): 
    def __call__(self, *args, **kwargs): 
     return 1 - super(InvertedNormalize, self).__call__(*args, **kwargs) 

Вы можете использовать это с plot_surface и другие функции построения графика Matplotlib, например,

inverted_norm = InvertedNormalize(vmin=10, vmax=100) 
ax.plot_surface(..., cmap=<your colormap>, norm=inverted_norm) 

Это будет работать с любой цветовой палитрой Matplotlib.

+0

Теперь есть! https://matplotlib.org/api/_as_gen/matplotlib.colors.ListedColormap.html#matplotlib.colors.ListedColormap.reversed –

0

По Matplotlib 2.0, есть reversed() метод ListedColormap и LinearSegmentedColorMap объектов, так что вы можете просто сделать

cmap_reversed = cmap.reverse()

См here для документации.

Смежные вопросы