Получение отдельных цветов из цветовой карты в 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)

10 ответов

Решение

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

(Спасибо Joe Kington tacaswell и tacaswell за предложения о том, как улучшить ответ.)

Чтобы получить целочисленное значение 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

Однажды я столкнулся с подобной ситуацией, когда мне нужно «n» нет. цветов из палитры, чтобы я мог назначить каждый цвет своим данным. Я скомпилировал код для этого в пакете под названием « mycolorpy ». Вы можете установить его, используя:

      pip install mycolorpy

Затем вы можете сделать:

      from mycolorpy import colorlist as mcp
import numpy as np

Пример: создать список из 5 шестигранных строк из лагеря "зима".

      color1=mcp.gen_color(cmap="winter",n=5)
print(color1)

Выход:

      ['#0000ff', '#0040df', '#0080bf', '#00c09f', '#00ff80']

Другой пример создания списка из 16 цветов из лагеря bwr:

      color2=mcp.gen_color(cmap="bwr",n=16)
print(color2)

Выход:

      ['#0000ff', '#2222ff', '#4444ff', '#6666ff', '#8888ff', '#aaaaff', '#ccccff', '#eeeeff', '#ffeeee', '#ffcccc', '#ffaaaa', '#ff8888', '#ff6666', '#ff4444', '#ff2222', '#ff0000']

Существует на блокнотPython с примерами использования, чтобы лучше это наглядно представить.

Допустим, вы хотите сгенерировать список цветов из cmap, нормализованный по заданным данным. Вы можете сделать это, используя:

      a=random.randint(1000, size=(200))
a=np.array(a)
color1=mcp.gen_color_normalized(cmap="seismic",data_arr=a)
plt.scatter(a,a,c=color1)

Выход:

Вы также можете изменить цвет, используя:

      color1=mcp.gen_color_normalized(cmap="seismic",data_arr=a,reverse=True)
plt.scatter(a,a,c=color1)

Выход:

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

Сначала я пробовал просто генерировать цвета случайным образом, повторно заполняя ГСЧ перед каждым графиком. Это работало нормально (закомментировано в коде ниже), но могло генерировать почти неразличимые цвета. Мне нужны были очень контрастные цвета, в идеале взятые из палитры, содержащей все цвета.

У меня могло быть до 31 серии данных на одном графике, поэтому я разделил цветовую карту на такое количество шагов. Затем я прошел по ступеням в таком порядке, который гарантировал, что очень скоро не вернусь в окрестности определенного цвета.

Мои данные находятся в очень нерегулярном временном ряду, поэтому я хотел видеть точки и линии, причем точка имеет «противоположный» цвет линии.

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

Вот мой код. Возможно, не красиво, но функционально.

      from matplotlib import cm
cmap = cm.get_cmap('gist_rainbow')  #('hsv') #('nipy_spectral')

max_colors = 31   # Constant, max mumber of series in any plot.  Ideally prime.
color_number = 0  # Variable, incremented for each series.

def restart_colors():
    global color_number
    color_number = 0
    #np.random.seed(1)

def next_color():
    global color_number
    color_number += 1
    #color = tuple(np.random.uniform(0.0, 0.5, 3))
    color = cmap( ((5 * color_number) % max_colors) / max_colors )
    return color

def plot_args():  # Invoked for each plot in a series as: '**(plot_args())'
    mkr = next_color()
    clr = (1 - mkr[0], 1 - mkr[1], 1 - mkr[2], mkr[3])  # Give line inverse of marker color
    return {
        "marker": "o",
        "color": clr,
        "mfc": mkr,
        "mec": mkr,
        "markersize": 0.5,
        "linewidth": 1,
    }

Мой контекст - это JupyterLab и Pandas, поэтому вот пример кода графика:

      restart_colors()  # Repeatable color sequence for every plot

fig, axs = plt.subplots(figsize=(15, 8))
plt.title("%s + T-meter"%name)

# Plot reference temperatures:
axs.set_ylabel("°C", rotation=0)
for s in ["T1", "T2", "T3", "T4"]:
    df_tmeter.plot(ax=axs, x="Timestamp", y=s, label="T-meter:%s" % s, **(plot_args()))

# Other series gets their own axis labels
ax2 = axs.twinx()
ax2.set_ylabel(units)

for c in df_uptime_sensors:
    df_uptime[df_uptime["UUID"] == c].plot(
        ax=ax2, x="Timestamp", y=units, label="%s - %s" % (units, c), **(plot_args())
    )

fig.tight_layout()
plt.show()

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

Цветовые карты имеют собственный метод нормализации, поэтому, если у вас уже есть график, вы можете получить доступ к цвету по определенному значению.

      import matplotlib.pyplot as plt
import numpy as np

cmap = plt.cm.viridis

cm = plt.pcolormesh(np.random.randn(10, 10), cmap=cmap)

print(cmap(cm.norm(2.2)))

Чтобы использовать решения от 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]))

Я нашел довольно короткий способ вернуть списокNшестнадцатеричные цвета с matplotlib:

      import matplotlib

# Choose colormap
cmap = plt.cm.get_cmap('terrain', N)
colors = [matplotlib.colors.to_hex(cmap(i)) for i in range(N)]

Надеюсь, поможет!

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

      import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap

# Choose a colormap from Matplotlib
colormap = plt.cm.viridis

# Set number of colors
num_colors = 5

# Create a ListedColormap with discrete colors
discrete_cmap = ListedColormap(colormap(np.linspace(0, 1, num_colors)))

# Output RGB values
for i, rgb in enumerate(discrete_cmap.colors):
    print(f"Color {i + 1}: RGB = {rgb}")

# Plot a colorbar to visualize
plt.imshow([[i] for i in range(num_colors)], cmap=discrete_cmap, aspect='auto')
plt.colorbar(ticks=range(num_colors))
plt.show()

Для полноты, это варианты cmap, с которыми я столкнулся до сих пор:

Accent, Accent_r, Blues, Blues_r, BrBG, BrBG_r, BuGn, BuGn_r, BuPu, BuPu_r, CMRmap, CMRmap_r, Dark2, Dark2_r, GnBu, GnBu_r, Greens, Greens_r, Grays, Greys_Rd, ORRD, ORGAN, ORD, ORD PRGn_r, Парный, Парный_r, Pastel1, Pastel1_r, Pastel2, Pastel2_r, PiYG, PiYG_r, PuBu, PuBuGn, PuBuGn_r, PuBu_r, PuOr, PuOr_r, PuRd, RdGu_r, Purples, Purples_r, RdGu_r, RdBu_r, RdBu_r, RdBu_r RdYlBu, RdYlBu_r, RdYlGn, RdYlGn_r, Reds, Reds_r, Set1, Set1_r, Set2, Set2_r, Set3, Set3_r, Spectral, Spectral_r, Wistia, Wistia_r, YlGn, YlGnBurOr, YlGnBur_r, YlGnBur_r, YlGnBur_r, YlGnBur_r, YlGnBur_r, YlGnBur, YlGnBur afmhot_r, autumn, autumn_r, binary, binary_r, bone, bone_r, brg, brg_r, bwr, bwr_r, cividis, cividis_r, cool, cool_r, coolwarm, coolwarm_r, Copper, Copper_r, cubehelix, cubehelix_r, flag, flag_earth_r, gist_r, gist_rgist_gray, gist_gray_r, gist_heat, gist_heat_r, gist_ncar, gist_ncar_r, gist_rainbow, gist_rainbow_r, gist_stern, gist_stern_r, gist_yarg, gist_yarg_r, gnuplot_rnnuplot2, grey_rnuplot2, gnuplot_rnuplot2, gnuplot_rnuplot2 jet_r, magma, magma_r, nipy_spectral, nipy_spectral_r, ocean, ocean_r, pink, pink_r, Plasma, Plasma_r, Prism, Prism_r, rainbow, rainbow_r, seismic, seismic_r, spring, spring_r, summer, summer_r, tab10, tab10_r, tab20 tab20b, tab20b_r, tab20c, tab20c_r, terrain, terrain_r, сумерки, twilight_r, twilight_shifted, twilight_shifted_r, viridis, viridis_r, winter, winter_rgray_r, hot, hot_r, hsv, hsv_r, inferno, inferno_r, jet, jet_r, magma, magma_r, nipy_spectral, nipy_spectral_r, ocean, ocean_r, розовый, pink_r, плазма, плазменный_r, призма, prism_r, rainbow_rism, seism, seism весна, spring_r, лето, лето_r, tab10, tab10_r, tab20, tab20_r, tab20b, tab20b_r, tab20c, tab20c_r, terrain, terrain_r, сумерки, twilight_r, twilight_shifted, twilight_shifted_r, viridis, viridis_r, зима, зима gray_r, hot, hot_r, hsv, hsv_r, inferno, inferno_r, jet, jet_r, magma, magma_r, nipy_spectral, nipy_spectral_r, ocean, ocean_r, розовый, pink_r, плазма, плазменный_r, призма, prism_r, rainbow_rism, seism, seism весна, spring_r, лето, лето_r, tab10, tab10_r, tab20, tab20_r, tab20b, tab20b_r, tab20c, tab20c_r, terrain, terrain_r, сумерки, twilight_r, twilight_shifted, twilight_shifted_r, viridis, viridis_r, зима, зима viridis, viridis_r, winter, winter_rviridis, viridis_r, winter, winter_r

Для быстрого и грязного вы можете использовать карту напрямую. Или вы можете просто делать то, что говорит @amaliammr.

      data_size = 23   # range 0..23
colors = plt.cm.turbo
color_normal = colours.N/data_size

for i in range(data_size):
    col = colours.colors[int(i*color_normal)]


Другие вопросы по тегам