Matplotlib дискретный цветной бар

Я пытаюсь сделать дискретную панель цвета для диаграммы рассеяния в matplotlib

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

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

Обычно тег будет целым числом от 0 до 20, но точный диапазон может меняться

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

plt.colorbar()

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

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

Ответ 1

Вы можете легко создать собственный дискретный цветной балл, используя 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 разными цветами его немного трудно читать конкретное значение, но это, конечно же, для вас.

Ответ 2

Вы можете следовать этому 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

Ответ 3

Чтобы установить значения выше или ниже диапазона цветовой палитры, вы захотите использовать методы set_over и set_under в цветовой палитре. Если вы хотите отметить определенное значение, замаскируйте его (т.е. Создайте маскированный массив) и используйте метод set_bad. (Посмотрите документацию для базового класса colormap: 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

Ответ 4

Вышеуказанные ответы хороши, за исключением того, что у них нет правильного размещения меток на цветной панели. Мне нравится, чтобы метки были посередине цвета, так что число → цветное отображение более ясное. Вы можете решить эту проблему, изменив пределы вызова 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

Ответ 5

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