#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)
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
предупреждение.