Подтвердить что ты не робот

Получение отдельных цветов с цветовой карты в matplotlib

Если у вас есть Colormap из

cmap = matplotlib.cm.get_cmap('Spectral')

как вы можете получить определенный цвет из него между 0 и 1, где 0.0 является первым цветом на карте, а 1.0 является последним цветом на карте?

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

>>> do_some_magic(cmap, 0.5) # Return an RGBA tuplet
(0.1, 0.2, 0.3, 1.0)
4b9b3361

Ответ 1

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

import matplotlib

cmap = matplotlib.cm.get_cmap('Spectral')

rgba = cmap(0.5)
print(rgba) # (0.99807766255210428, 0.99923106502084169, 0.74602077638401709, 1.0)

Для значений вне диапазона [0.0, 1.0] он вернет нижний и дополнительный цвета (соответственно). По умолчанию это минимальный и максимальный цвет в диапазоне (так 0.0 и 1.0). Это значение по умолчанию можно изменить с помощью cmap.set_under() и cmap_set_over().

Для "специальных" чисел, таких как np.nan и np.inf, по умолчанию используется значение 0.0, это можно изменить с помощью cmap.set_bad() аналогично тому, как указано выше.

Наконец, вам может потребоваться нормализовать ваши данные так, чтобы они соответствовали диапазону [0.0, 1.0]. Это можно сделать, используя matplotlib.colors.Normalize просто так, как показано в небольшом примере ниже, где аргументы vmin и vmax описывают, какие числа должны быть отображаются соответственно 0,0 и 1,0.

import matplotlib

norm = matplotlib.colors.Normalize(vmin=10.0, vmax=20.0)

print(norm(15.0)) # 0.5

Логарифмический нормализатор (matplotlib.colors.LogNorm) также доступен для диапазонов данных с большим диапазоном значений.

(Спасибо как Джо Кингтону и tcaswell за предложения по улучшению ответа. )

Ответ 2

Чтобы получить целочисленное значение rgba вместо значения с плавающей запятой, мы можем сделать

rgba = cmap(0.5,bytes=True)

Таким образом, чтобы упростить код на основе ответа от Ffisegydd, код будет выглядеть следующим образом:

#import colormap
from matplotlib import cm

#normalize item number values to colormap
norm = matplotlib.colors.Normalize(vmin=0, vmax=1000)

#colormap possible values = viridis, jet, spectral
rgba_color = cm.jet(norm(400),bytes=True) 

#400 is one of value between 0 and 1000

Ответ 3

Чтобы использовать решения из Ffisegydd и amaliammr, вот пример, где мы создаем CSV-представление для пользовательской карты цветов:

#! /usr/bin/env python3
import matplotlib
import numpy as np 

vmin = 0.1
vmax = 1000

norm = matplotlib.colors.Normalize(np.log10(vmin), np.log10(vmax))
lognum = norm(np.log10([.5, 2., 10, 40, 150,1000]))

cdict = {
    'red':
    (
        (0., 0, 0),
        (lognum[0], 0, 0),
        (lognum[1], 0, 0),
        (lognum[2], 1, 1),
        (lognum[3], 0.8, 0.8),
        (lognum[4], .7, .7),
    (lognum[5], .7, .7)
    ),
    'green':
    (
        (0., .6, .6),
        (lognum[0], 0.8, 0.8),
        (lognum[1], 1, 1),
        (lognum[2], 1, 1),
        (lognum[3], 0, 0),
        (lognum[4], 0, 0),
    (lognum[5], 0, 0)
    ),
    'blue':
    (
        (0., 0, 0),
        (lognum[0], 0, 0),
        (lognum[1], 0, 0),
        (lognum[2], 0, 0),
        (lognum[3], 0, 0),
        (lognum[4], 0, 0),
    (lognum[5], 1, 1)
    )
}


mycmap = matplotlib.colors.LinearSegmentedColormap('my_colormap', cdict, 256)   
norm = matplotlib.colors.LogNorm(vmin, vmax)
colors = {}
count = 0
step_size = 0.001
for value in np.arange(vmin, vmax+step_size, step_size):
    count += 1
    print("%d/%d %f%%" % (count, vmax*(1./step_size), 100.*count/(vmax*(1./step_size))))
    rgba = mycmap(norm(value), bytes=True)
    color = (rgba[0], rgba[1], rgba[2])
    if color not in colors.values():
        colors[value] = color

print ("value, red, green, blue")
for value in sorted(colors.keys()):
    rgb = colors[value]
    print("%s, %s, %s, %s" % (value, rgb[0], rgb[1], rgb[2]))