2013-02-08 4 views
46

Я пытаюсь сделать дискретную Colorbar для рассеивания в MatplotlibMatplotlib дискретная Colorbar

У меня есть х, у данных и для каждой точки значения тега целого числа, которое я хочу быть представлен уникальным цветом, например,

plt.scatter(x, y, c=tag) 

обычно метить будет целое число в пределах от 0-20, но точный диапазон может изменить

до сих пор я просто использовал настройки по умолчанию, например,

plt.colorbar() 

, который дает непрерывный диапазон цветов. В идеале я хотел бы иметь набор из n дискретных цветов (n = 20 в этом примере). Еще лучше было бы получить значение тега 0 для создания серого цвета и 1-20 быть красочным.

Я нашел несколько сценариев «поваренной книги», но они являются очень сложными, и я не могу думать, что они правильно решить, казалось бы, простую задачу

+1

делает [это] (http://matplotlib.org/examples/api/colorbar_only.html) или [это] (http://www.scipy.org/Cookbook/Matplotlib/ColormapTransformations) помощь? –

+0

спасибо за ссылки, но второй пример - это то, что я имею в виду о чрезвычайно сложных задачах для выполнения (казалось бы) тривиальной задачи. 1-я ссылка полезна – bph

ответ

58

Вы можете легко создать собственный дискретный цветной балл, используя BoundaryNorm в качестве нормализатора для вашего разброса. Причудливый бит (в моем методе) делает вывод 0 серым.

Для изображений я часто использую cmap.set_bad() и преобразую свои данные в массив с маской размером. Это было бы намного проще сделать 0 серым, но я не мог заставить это работать с разбросом или пользовательским cmap.

В качестве альтернативы вы можете сделать свой собственный cmap с нуля или прочитать существующий и переопределить только некоторые конкретные записи.

# setup the plot 
fig, ax = plt.subplots(1,1, figsize=(6,6)) 

# define the data 
x = np.random.rand(20) 
y = np.random.rand(20) 
tag = np.random.randint(0,20,20) 
tag[10:12] = 0 # make sure there are some 0 values to showup as grey 

# define the colormap 
cmap = plt.cm.jet 
# extract all colors from the .jet map 
cmaplist = [cmap(i) for i in range(cmap.N)] 
# force the first color entry to be grey 
cmaplist[0] = (.5,.5,.5,1.0) 
# create the new map 
cmap = cmap.from_list('Custom cmap', cmaplist, cmap.N) 

# define the bins and normalize 
bounds = np.linspace(0,20,21) 
norm = mpl.colors.BoundaryNorm(bounds, cmap.N) 

# make the scatter 
scat = ax.scatter(x,y,c=tag,s=np.random.randint(100,500,20),cmap=cmap, norm=norm) 

# create a second axes for the colorbar 
ax2 = fig.add_axes([0.95, 0.1, 0.03, 0.8]) 
cb = mpl.colorbar.ColorbarBase(ax2, cmap=cmap, norm=norm, spacing='proportional', ticks=bounds, boundaries=bounds, format='%1i') 

ax.set_title('Well defined discrete colors') 
ax2.set_ylabel('Very custom cbar [-]', size=12) 

enter image description here

Я лично считаю, что с 20 различных цветов его немного трудно читать определенное значение, но то до вас, конечно.

+3

отличный ответ - я думаю, что это потребовало бы меня * очень * долгое время, чтобы понять из онлайн-документов, большое спасибо – bph

+0

Я не уверен, разрешено ли это, но вы можете посмотреть на мой вопрос [здесь] (http : //stackoverflow.com/questions/32766062/how-to-determine-the-colours-when-using-matplotlib-pyplot-imshow)? – Esoemah

38

Вы могли бы следовать этому example:

#!/usr/bin/env python 
""" 
Use a pcolor or imshow with a custom colormap to make a contour plot. 

Since this example was initially written, a proper contour routine was 
added to matplotlib - see contour_demo.py and 
http://matplotlib.sf.net/matplotlib.pylab.html#-contour. 
""" 

from pylab import * 


delta = 0.01 
x = arange(-3.0, 3.0, delta) 
y = arange(-3.0, 3.0, delta) 
X,Y = meshgrid(x, y) 
Z1 = bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0) 
Z2 = bivariate_normal(X, Y, 1.5, 0.5, 1, 1) 
Z = Z2 - Z1 # difference of Gaussians 

cmap = cm.get_cmap('PiYG', 11) # 11 discrete colors 

im = imshow(Z, cmap=cmap, interpolation='bilinear', 
      vmax=abs(Z).max(), vmin=-abs(Z).max()) 
axis('off') 
colorbar() 

show() 

который производит следующее изображение:

poormans_contour

+6

cmap = cm.get_cmap ('jet', 20), затем разброс (x, y, c = tags, cmap = cmap), мне очень трудно найти полезную документацию для matplotlib – bph

0

Я думаю, что вы бы хотели посмотреть на colors.ListedColormap для создания вашей цветовой карты, или если вам просто нужна статическая цветовая палитра, я работал над an app, что может помочь.

+0

, которая выглядит круто, возможно, излишняя для моих нужд - не могли бы вы предложить способ пометки серого значения на существующую цветовую палитру? так что 0 значений выходят серым цветом, а остальные выходят в виде цветов? – bph

+0

@Hiett как создать массив color_list массива RGB на основе ваших значений y и передать их в ListedColormap? Вы можете пометить значение с помощью color_list [y == value_to_tag] = gray_color. – ChrisC

23

Чтобы установить значения, указанные выше или ниже диапазона цветовой карты, вы должны использовать методы цветовой схемы set_over и set_under. Если вы хотите отметить определенное значение, замаскируйте его (т. Е. Создайте маскированный массив) и используйте метод set_bad. (Обратите внимание на документацию для базового класса палитрой: http://matplotlib.org/api/colors_api.html#matplotlib.colors.Colormap)

Это звучит, как вы хотите что-то вроде этого:

import matplotlib.pyplot as plt 
import numpy as np 

# Generate some data 
x, y, z = np.random.random((3, 30)) 
z = z * 20 + 0.1 

# Set some values in z to 0... 
z[:5] = 0 

cmap = plt.get_cmap('jet', 20) 
cmap.set_under('gray') 

fig, ax = plt.subplots() 
cax = ax.scatter(x, y, c=z, s=100, cmap=cmap, vmin=0.1, vmax=z.max()) 
fig.colorbar(cax, extend='min') 

plt.show() 

enter image description here

+0

это действительно хорошо - я пытался использовать set_under, но не включил vmin, поэтому я не думаю, что он что-то делал – bph

19

Вышеуказанные ответы хороши, за исключением того, что они не» t иметь правильное размещение меток на цветной панели.Мне нравится, чтобы метки были посередине цвета, так что число -> цветное отображение более ясное. Вы можете решить эту проблему, изменив пределы вызова matshow:

import matplotlib.pyplot as plt 
import numpy as np 

def discrete_matshow(data): 
    #get discrete colormap 
    cmap = plt.get_cmap('RdBu', np.max(data)-np.min(data)+1) 
    # set limits .5 outside true range 
    mat = plt.matshow(data,cmap=cmap,vmin = np.min(data)-.5, vmax = np.max(data)+.5) 
    #tell the colorbar to tick at integers 
    cax = plt.colorbar(mat, ticks=np.arange(np.min(data),np.max(data)+1)) 

#generate data 
a=np.random.randint(1, 9, size=(10, 10)) 
discrete_matshow(a) 

example of discrete colorbar

+0

Я согласен, что размещение метки в середине соответствующего цвета очень полезно при просмотре дискретных данных. Второй метод правильный. Тем не менее, ваш первый метод, в общем, _wrong_: вы помечены тиками значениями, которые не соответствуют их размещению на цветной панели. 'set_ticklabels (...)' следует использовать только для управления форматированием меток (например, десятичным числом и т. д.). Если данные действительно дискретны, вы можете не заметить никаких проблем. Если в системе есть шум (например, 2 -> 1.9), эта несогласованная маркировка приведет к ошибочной и неправильной цветовой панели. –

+0

E. Я думаю, что вы правы в том, что изменение пределов - превосходное решение, поэтому я удалил другой, хотя ни один из них не будет хорошо «шуметь». Некоторые корректировки потребуются для обработки непрерывных данных. –

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