2013-09-03 4 views
8

Я использую Matplotlib 1.3.0 и у меня есть следующие:Matplotlib использование стандартной Colormap

import matplotlib.pyplot as plt 
cmap = plt.cm.jet 
plt.contourf([[.12, .2], [.8, 2]], levels=[0, .1, .3, .5, 1, 3], cmap=cmap, vmin=0, vmax=3) 
plt.colorbar() 

, который производит:

enter image description here

бит, что я не понимаю, где все остальные цвета пошли? Как я понимаю, указав vmin=0, vmax=3 то цвет бар должен использовать весь спектр cmap, как на этой картинке:

enter image description here

, который производится без предоставления аргументов vmin, vmax и levels. Итак ... что мне здесь не хватает?

РЕДАКТИРОВАТЬ 1

В ответ на tom10 & tcaswell. Я бы ожидал, что это будет так, как вы говорите, но ... к сожалению, это не так. Посмотрите на это:

plt.contourf([[.12, .2], [.8, 3.2]], levels=[0, .1, .3, .5, 1, 3], cmap=cmap, vmin=0, vmax=3) 
plt.colorbar() 

с:

enter image description here

Может прояснить этот немного: у меня есть данные и важные особенности этого являются около 0,1, но есть некоторые вокруг 3 скажем. Поэтому я даю ему levels=[0, 0.005, 0.075, 0.1, 0.125, 0.15, 0.2, 1, 2.5, 2.75, 3, 3.25] и vmin=0, vmax=3.25. Теперь я ожидаю увидеть весь диапазон цветов, но вместо этого все важные данные-точки от 0.005 до 0.125 окажутся в синей области (используя стандартную цветовую карту plt.cm.jet). То, что я говорю, я думаю, это ... если я дам levels=[0, 1, 2, 3], vmin=0, vmax=3 для некоторых данных, которые идут от 0 до 3, я ожидаю увидеть все цвета в данной цветовой карте, но если я дам levels=[0, 0.9, 0.1, 0.11, 1, 3], vmi=0, vmax=3, я бы ожидал того же, чтобы увидеть все цвета в данной цветовой карте, за исключением отображения на правильные интервалы, вместо этого я вижу кучу блюза, окрашивающего область 0-0.11, а некоторые зеленые/желтые окраски в другую часть региона. Надеюсь, что это ... немного ясно.

EDIT 2

То же самое происходит, даже если я не даю norm или vmin, vmax.

EDIT 3

Ссылаясь на комментарий tcaswell, в себя так, как это ... для меня по крайней мере, нелогичным. Я ожидал, что цвет будет несовместим с точками данных. Я ожидал бы, что весь диапазон цветов из цветовой карты будет использоваться все время (кроме случаев, когда vmin, vmax больше/меньше, чем levels мин, максимальные значения). Другими словами, глядя на этот код, который я сделал некоторое время назад (Python 3):

import matplotlib.colors as mc 
def addNorm(cmapData): 
    cmapData['norm'] = mc.BoundaryNorm(cmapData['bounds'], cmapData['cmap'].N) 
    return True 
def discretize(cmap, bounds): 
    resCmap = {} 
    resCmap['cmap'] = mc.ListedColormap(\ 
     [cmap(i/len(bounds[1:])) for i in range(len(bounds[1:]))] 
    ) 
    resCmap['bounds'] = bounds 
    addNorm(resCmap) 
    return resCmap 

затем использовать его как:

levels = [0, .1, .3, .5, 1, 3] 
cmapData = discretize(plt.cm.jet, bounds=levels) 
plt.contourf([[.12, .2], [.8, 3.2]], levels=levels, cmap=cmapData['cmap'], norm=cmapData['norm']) 
plt.colorbar() 

, который дает сюжет, где вы можете различать функции (0,1 -0,5), т.е.они больше не в синей области с помощью описанного выше метода с plt.cm.jet:

enter image description here

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

+0

Ваше обновление ведет себя _exactly_, как я ожидал. Желтый еще 2, ваша верхняя строка (которую вы не рисуете) красная, а над 3 контуром - белая, потому что она находится за пределами ваших уровней. – tacaswell

+0

ОК, я думаю, я понял, как используются эти стандартные шаблоны (и меня это не беспокоит), но ... тогда есть способ заставить цвета вести себя как _I ожидать? то есть. используя ** colormap ** с цветами от ** c0 ** до ** c8 **, допустим, для простоты, но я все еще имею в виду цветовые коды _default_): когда я устанавливаю 'levels = [0, 0.09, 0.1 , 0.11, 3]. Я ожидаю, что он будет использовать ** [c0 (для 0-0,09), c2 (0,09-0,1), c4 (0,09-0,1), c6 (0,1-0,11), c8 (0,11-0,3)] ** вместо использования ** [c0 (0-0,09), c1 (0,09-0,1), c2 (0,1-0,11), c6 (0,11-3)] **. Надеюсь, это имеет смысл ... – razvanc

+0

отлично, но это не то, что вы сделали. Цветовая карта ничего не знает о ваших уровнях, все, что она знает, - это то, как преобразовать скаляр -> цвет линейно между 'vmin' и' vmax'. Посмотрите на перечисленные цветовые карты. – tacaswell

ответ

3

Поиграв немного, кажется, что ответ на этот вопрос намного проще, чем я когда-либо думал. Сначала объясню какое-то объяснение. Читая документацию по нормализующим классам от matplotlib.colors, я понял ... ну, matplotlib.colors.BoundaryNorm следует использовать здесь! но что-то не так, как вы можете видеть в следующем примере:

import matplotlib.pyplot as plt 
import matplotlib.colors as mc 
levels = [0, .1, .3, .5, 1, 3] 
norm = mc.BoundaryNorm(levels, len(levels)-1) 
plt.contourf([[.12, .2], [.8, 2]], levels=levels, norm=norm) 
plt.colorbar() 
plt.show() 

, который дает это: enter image description here и это, очевидно, что-то мы не хотим! И я думал ... почему вы должны были бы дать конструктору BoundaryNorm количество цветов для использования? ... Не должно ли BoundaryNorm использовать всю полноту цветовой карты?А потом он ударил меня, только с небольшим изменением в коде выше:

# use here 256 instead of len(levels)-1 becuase 
# as it's mentioned in the documentation for the 
# colormaps, the default colormaps use 256 colors in their 
# definition: print(plt.cm.jet.N) for example 
norm = mc.BoundaryNorm(levels, 256) 

и мы получаем: enter image description here это именно то, что мы хотим!

Или мы можем сделать:

cmap = # user define cmap 
norm = mc.BoundaryNorm(levels, cmap.N) 
# which is I guess a little bit more programatically (is this a word?!) correct 
+0

Жаль, что это плохо документировано ... потребовалось много времени, чтобы понять эту простую вещь. – razvanc

+0

Смысл, похоже, вы понимаете, что используете прецедент и ограничение нормы, можете ли вы написать для этого документацию?Было бы полезно либо улучшить doc-строки, либо добавить пример в галерею. – tacaswell

+0

Да, я напишу некоторую документацию по этому вопросу, надеюсь, раньше, чем позже. – razvanc

2

Цвет заполненной области выбирается срединной точкой двух линий, которые она заполняет между (iirc). Желтый, который вы видите, - это картирование 2 под цветовой картой и ограничениями, которые вы устанавливаете.

Если вы хотите отобразить цвет по индексу области, сделать несколько обезьян заплат:

def _process_colors_by_index(self): 
    """ 
    Color argument processing for contouring. 

    The color is based in the index in the level set, not 
    the actual value of the level. 

    """ 
    self.monochrome = self.cmap.monochrome 
    if self.colors is not None: 
     # Generate integers for direct indexing. 
     i0, i1 = 0, len(self.levels) 
     if self.filled: 
      i1 -= 1 
     # Out of range indices for over and under: 
     if self.extend in ('both', 'min'): 
      i0 = -1 
     if self.extend in ('both', 'max'): 
      i1 += 1 
     self.cvalues = list(range(i0, i1)) 
     self.set_norm(colors.NoNorm()) 
    else: 
     self.cvalues = range(len(self.levels)) 
    self.set_array(range(len(self.levels))) 
    self.autoscale_None() 
    if self.extend in ('both', 'max', 'min'): 
     self.norm.clip = False 

    # self.tcolors are set by the "changed" method 


orig = matplotlib.contour.ContourSet._process_colors 
matplotlib.contour.ContourSet._process_colors = _process_colors_by_index 
cmap = plt.cm.jet 
figure() 
out = plt.contourf([[.12, .2], [.8, 2]], levels=[0, .1, .3, .5, 1, 3], cmap=cmap) 
plt.colorbar() 
# fix what we have done 
matplotlib.contour.ContourSet._process_colors = orig 

output

Вы, вероятно, может сделать лучше и удалить сдвиг на 1/2, а также.

Вы также можете достичь и изменить цвет существующих контуров. Похоже, вам нужно изменить значения out.cvalues, а затем вызвать out.changed() на объект.

Менее разрушительной версией было бы написать пользовательский norm по подклассу matplotlib.colors.Normalize, см. colors.py для шаблона.

+0

Теперь, когда я думаю о том, что вы сказали, это имеет смысл. Но все же ... это не то, как я ожидал бы, что цветная шкала будет вести себя (см. Мой комментарий выше) – razvanc

+0

Да, это круто: D ... Я даже не знал, что вы можете это сделать ... назначьте свой собственные функции _home grow_ для изменения основной функциональности. Да, я ожидал, что он будет основан на индексе уровней, а не на данных:) ... чтобы лучше визуализировать интересующие регионы (т. Е. Когда данные сильно нелинейны). Благодаря! – razvanc

+0

@razvanc также изучает 'LogNorm' или записывает пользовательские функции нормы. Это может быть менее разрушительным в долгосрочной перспективе. – tacaswell

0

Максимальное значение ваших данных: 2. В сюжете, о котором идет речь, вы задали vmax=3.

Более подробно, vmax устанавливает диапазон цветов, используемых при сопоставлении. Поскольку это намного больше, чем ваш диапазон данных, когда вы создаете данные, вы не видите полный диапазон цветов. Это еще больше смущает небольшое количество levels, которое вы выбрали, что не показывает вам все доступные цвета, поскольку в цветовой полосе отображается только один цвет для всего диапазона от 1 до 3, опять же, затеняющие цвета доступны за пределами 2 .

0

на самом деле я думаю, что лучшее решение еще находится в этом месте:

http://protracted-matter.blogspot.ie/2012/08/nonlinear-colormap-in-matplotlib.html

Он определяет этот маленький класс, который решает все проблемы:

class nlcmap(mc.LinearSegmentedColormap): 
    """A nonlinear colormap""" 

    name = 'nlcmap' 

    def __init__(self, cmap, levels): 
     self.cmap = cmap 
     # @MRR: Need to add N for backend 
     self.N = cmap.N 
     self.monochrome = self.cmap.monochrome 
     self.levels = np.asarray(levels, dtype='float64') 
     self._x = self.levels/self.levels.max() 
     self._y = np.linspace(0.0, 1.0, len(self.levels)) 

    #@MRR Need to add **kw for 'bytes' 
    def __call__(self, xi, alpha=1.0, **kw): 
     yi = np.interp(xi, self._x, self._y) 
     return self.cmap(yi, alpha) 

Сценарий был первоначально разработан парнем по имени Роберт Хетланд. Все подробности указаны в ссылке выше.

+0

Это разрушает модель нормализации/цветовой карты 'matplotlib'. Правильное место для нелинейного поведения находится в функциях 'Normalize'. – tacaswell

+0

Да, вы правы, например, с этим я заметил, что 'set_over', например, не работает. Но, тем не менее, у меня нет времени, чтобы заглянуть в детали класса нормализации (поскольку у него нет примеров того, как его расширить), и это проще для того, что мне нужно. – razvanc

+0

Я не принял этот ответ, так как я, наконец, нашел удовлетворительную альтернативу, используя '' BoundaryNorm'', который я задокументировал в принятом новом ответе. – razvanc

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