I'm trying to generate a Heatmap in Holoviews with custom color values for each point, in order to specify different alpha color values.
Currently I'm generating two Holoviews plots with different alpha values and overlay them like so:
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) & (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
This however, gives me a Holoviews Overlay object, where I'd like to have a single HeatMap object instead.
My idea was to map each x/y coordinate to a specific color value in hex form, which has the needed alpha already calculated into it. My DataFrame would therefore look something like this (example):
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
Is there a way to tell Holoviews to use these colors? When I pass the list of colors to the "cmap" parameter it interpretes it as color intervals, passing the name of the column raises an error as it cannot find the specified cmap.
When I pass the list to the "color" parameter, the plot is not displayed at all anymore in the Jupyter Notebook.
Edit
I found a way to get what I want using the Bokeh library directly. Bokeh is also the backend I'm using with Holviews. This is the code and the resulting plot.
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 allows to pass the color column name to the 'color' parameter of the rect function. Anyway, I'd still love to have it as a Holoviews container, so that I can combine it and build interactive apps on top of it.
Solution
With the help of the answer of @thomas-pedot I was able to find a solution which looks like what I was looking for:
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) & (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
Not easy... I try a lot of different converting to rgba then back to HEX cmap without success but !
Make it with style http://holoviews.org/user_guide/Style_Mapping.html