Hello,
I have successfully used holoviews.util.Dynamic to retain the ability to have a dynamic hover tool on coarsely aggregated data with datashader, as explained on the Interactivity page. That’s really great.
Building on this I am currently trying to display a tooltip that would show information based on categorical data, but I don’t know if it’s currently possible.
More precisely I’d like to show the category or categories of the points located in the hovered bin. Below is a snippet where I attempt to do so using the example provided in the datashader docs. Aggregates can only work on numerical data so I have an additional column which contains category numbers as floats. I use ds.by
to specify that I want the aggregate to work separately based on df['cat']
values. Then the reduction here is ds.min
but I could as well use ds.max
since the value is the same (ds.first
would be faster I guess but it yields an error saying it is only implemented for rasters).
import pandas as pd
import numpy as np
import datashader as ds
import holoviews as hv
import holoviews.operation.datashader as hd
from holoviews.streams import RangeXY
from collections import OrderedDict as odict
hd.shade.cmap=["lightblue", "darkblue"]
hv.extension("bokeh", "matplotlib")
num=100000
np.random.seed(1)
dists = {cat: pd.DataFrame(odict([('x',np.random.normal(x,s,num)),
('y',np.random.normal(y,s,num)),
('val',val),
('cat',cat),
('cat_number', cat_number)]))
for x, y, s, val, cat, cat_number in
[( 2, 2, 0.03, 10, "d1", 1),
( 2, -2, 0.10, 20, "d2", 2),
( -2, -2, 0.50, 30, "d3", 3),
( -2, 2, 1.00, 40, "d4", 4),
( 0, 0, 3.00, 50, "d5", 5)] }
df = pd.concat(dists,ignore_index=True)
df["cat"]=df["cat"].astype("category")
points = hv.Points(df.sample(10000))
pts = hd.datashade(points, width=400, height=400)
dynamic = hv.util.Dynamic(hd.aggregate(points, aggregator=ds.by('cat', ds.min('cat_number')),
width=24, height=24, streams=[RangeXY]), operation=hv.QuadMesh) \
.opts(tools=['hover'], alpha=0, hover_alpha=0.2)
(pts * dynamic).relabel("Dynamic square hover")
The error I get is the following : DataError: None of the available storage backends were able to support the supplied data format. And ds.min
by itself works, it’s the categorical part that doesn’t.
One solution would be to overlay as many aggregates as categories (like advised in this issue), each with its own hover tool, but in my experience the performance takes a hit when I superimpose several datashades. Plus the code would be more convoluted in my case.
I don’t know if this use case has been anticipated, or maybe I’m doing something wrong. Thanks in advance for the help.
As a side note, I have a custom tooltip already showing the local average of some value. I’d like to add the category field to this tooltip, so I intend to use ds.summary
to create several reductions but I can’t get it to work, even with a reduction that works by itself (e.g. ds.summary(min=ds.min(cat_number))
.
Software info:
- datashader 0.11.1 or 0.12.1
- holoviews 1.13.4 or 1.14.3
- bokeh 2.2.3 or 2.3.0
- context: within notebook or bokeh server (panel 0.10.3 or 0.11.2)