Тепловая карта Holoviews указывает цвет для каждой точки

#python #pandas #dataframe #bokeh #holoviews

#python #панды #фрейм данных #боке #holoviews

Вопрос:

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

В настоящее время я создаю два графика Holoviews с разными альфа-значениями и накладываю их следующим образом:

 data = pd.DataFrame([(i, 97 j,  i*j) for i in range(5) for j in range(5)], 
                columns=['x', 'y', 'val'])
data_filtered = data[(data.x < 3) amp; (data.y < 100)]

hm_opts = dict(kdims=['x', 'y'], vdims=['val'])
hm = hv.HeatMap(data, **hm_opts).opts(alpha=0.5)
hm_filtered = hv.HeatMap(data_filtered, **hm_opts).opts()
hm * hm_filtered
  

График

Однако это дает мне объект наложения Holoviews, где вместо этого я хотел бы иметь один объект тепловой карты.

Моя идея состояла в том, чтобы сопоставить каждую координату x / y с определенным значением цвета в шестнадцатеричной форме, в которой уже вычислена необходимая альфа. Поэтому мой фрейм данных будет выглядеть примерно так (пример):

     x    y  val    color
0   0   97    0  #00FF00
1   0   98    0  #00FF00
2   0   99    0  #00FF00
...
22  4   99    8  #FFD29F
23  4  100   12  #FFB89F
24  4  101   16  #D3AFF4
  

Есть ли способ указать Holoviews использовать эти цвета?
Когда я передаю список цветов параметру «cmap», он интерпретирует его как цветовые интервалы, передача имени столбца вызывает ошибку, поскольку он не может найти указанный cmap.

Когда я передаю список параметру «color», график вообще больше не отображается в записной книжке Jupyter.

Редактировать

Я нашел способ получить то, что я хочу, напрямую используя библиотеку Bokeh. Bokeh также является серверной частью, которую я использую с Holviews. Это код и результирующий график.

 source = ColumnDataSource(
    data=data
)
x_unique = data['x'].unique()
y_unique = data['y'].unique()
min_width = 110
min_height = 80
width = min_width   25 * len(x_unique)
height = min_height   25 * len(y_unique)
x_rect_width = 0.90
y_rect_width = 0.90
plot = figure(
    plot_width=width,
    plot_height=height,
    title='',
    x_range=FactorRange(*x_unique),
    y_range=FactorRange(*y_unique),
    x_axis_label='x',
    y_axis_label='y',
)
plot.rect('x', 'y', height=y_rect_width, width=x_rect_width, source=source, color='color')
plot.xgrid.grid_line_color = None
plot.ygrid.grid_line_color = None

show(plot)
  

График2

Bokeh позволяет передавать имя столбца цвета в параметр ‘color’ функции rect.
В любом случае, я бы все равно хотел иметь его в качестве контейнера Holoviews, чтобы я мог комбинировать его и создавать интерактивные приложения поверх него.

Решение

С помощью ответа @thomas-pedot я смог найти решение, похожее на то, что я искал:

 data = pd.DataFrame([(i, 97 j,  i*j) for i in range(5) for j in range(5)], 
                    columns=['x', 'y', 'val'])
data = data.assign(alpha=((data.x < 3) amp; (data.y < 100)).replace({True: 1.0, False: 3/8}))
red = '#FF0000'
yellow = '#FFFF00'
green = '#00FF00'
blue_violet = '#8A2BE2'
max_cout = data.loc[:, column].max()
levels = [0, 1, max_cout / 2, max_cout - 1, max_cout]
colors = [green, yellow, red, blue_violet]
hm_opts = dict(kdims=['x', 'y'], vdims=['val', 'alpha'])
hm = hv.HeatMap(data, **hm_opts).opts(
  alpha=hv.dim('alpha'), 
  color_levels=levels, 
  cmap=colors)
hm
  

Решение

Ответ №1:

 import pandas as pd
import holoviews as hv 
import matplotlib as mpl
hv.extension('matplotlib')

data = pd.DataFrame([(i, 97 j,  i*j) for i in range(5) for j in range(5)], 
                columns=['x', 'y', 'val'])
data_filtered = data[(data.x < 3) amp; (data.y < 100)]

cmap1 = mpl.colors.ListedColormap(['#00FF00', '#FFB89F', '#D3AFF4'])
hm_opts = dict(kdims=['x', 'y'], vdims=['val'])
hm = hv.HeatMap(data, **hm_opts).opts(alpha=0.5, cmap=cmap1)
  

Результаты:

Результаты

Я добавил строку cmap1 = mpl.colors.ListedColormap(['#00FF00', '#FFB89F', '#D3AFF4']) , которая позволяет вам указать, какие цвета вы хотите. Если вы обновите его до списка цветов (список в диапазоне всей вашей тепловой карты), тогда он будет именно таким, как вы хотите. Я думаю, вы можете работать с df["color"] в вашем случае (возможно, сначала напрямую преобразовать в список, но все будет в порядке)

Обратите внимание, что я также добавил cmap=cmap1 параметр в heatmap ‘ opt .

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

Комментарии:

1. Спасибо @Roim за этот ответ. Я столкнулся с аналогичной проблемой, но не смог адаптировать ваше решение для работы с bokeh вместо matplotlib. Я думал, что это будет довольно просто, например, с bokeh.models.LinearColorMapper() помощью или bokeh.models.CategoricalColorMapper() , но не смог заставить hvplot принять их в качестве допустимых цветовых карт.

2. Кажется, я не могу работать с этим ни на боке. Я думаю, есть большая вероятность, что это небольшая ошибка… Мне придется углубиться в это, чтобы дать хороший ответ

3. @Roim не могли бы вы объяснить, как вам удалось добавить значения / метки данных в тепловую карту? Спасибо

Ответ №2:

Непросто… Я пробую много разных преобразований в rgba, а затем обратно в HEX cmap, но безуспешно, но!

Сделайте это со стилем http://holoviews.org/user_guide/Style_Mapping.html

 data = pd.DataFrame([(i, 97 j,  i*j) for i in range(5) for j in range(5)], 
                columns=['x', 'y', 'val'])
data['a_new'] = 0.5
# Make a mask of you filter
mask = (data.x < 3) amp; (data.y < 100)

# Add it to a column
data1.loc[mask, 'a_new'] = 1.0 

#Add the new column to a new dimension
hm_opts_new = dict(kdims=['x', 'y'], vdims=['val','a_new'])

#Enjoy ? I hope... set the alpha option depends on your new column

hv.HeatMap(data1, **hm_opts_new).opts(opts.HeatMap(tools=['hover'], alpha=dim('a_new')))
  

Комментарии:

1. Это очень приятно. Я не знал, что вы можете передать имя измерения в альфа-аргумент. Итак, теперь мне нужно только настроить свои базовые цвета, чтобы они соответствовали тем, которые у меня были в моем пользовательском цветовом отображении. Таким образом, мне даже не нужно указывать цвета для каждой точки напрямую.

2. Я мог бы отредактировать свой вопрос, но пока не могу ответить, так как у меня недостаточно репутации.

3. Я отредактировал свой вопрос и пометил этот ответ как решение. Большое спасибо @thomas-pedot!

4. Спасибо, @iRave. Интересно, что это отлично сработало, когда я последовал вашему примеру и использовал hv.HeatMap(ds...) , где ds — это набор данных Xarray, но ds.hvplot(...kind='heatmap') выдал vdims option not found for image plot предупреждение.