Hello im trying to get the selected column of a bar chart with nested categorical groups, but i dont understand what the returned index of the tapstream means.
With this code here (mostly taken from http://holoviews.org/reference/elements/bokeh/Bars.html )
import numpy as np
from holoviews import opts
import panel as pn
import numpy as np
import holoviews as hv
import pandas as pd
hv.extension('bokeh')
samples = 100
pets = ['Cat', 'Dog', 'Hamster', 'Rabbit']
genders = ['Female', 'Male']
pets_sample = np.random.choice(pets, samples)
gender_sample = np.random.choice(genders, samples)
count = np.random.randint(1, 5, size=samples)
df = pd.DataFrame({'Pets': pets_sample, 'Gender': gender_sample, 'Count': count})
bars = hv.Bars(df, kdims=['Pets', 'Gender']).aggregate(function=np.sum).opts(opts.Bars(tools=["hover", "tap"]))
stream = hv.streams.Selection1D(source=bars)
bars.opts(width=500)
When i tap on a bar (ex.: dog,male), the stream.contents are:
{'index': [4]}
which does not respond to the bars.data dataframe
idx Pets Gender Count
0 Dog Female 18
1 Hamster Female 29
2 Dog Male 47
3 Cat Female 33
4 Rabbit Male 31
5 Cat Male 34
6 Rabbit Female 38
7 Hamster Male 9
For some bars, for example (hamster,female) the stream.contents show the correct index though.
Can someone help me explain whats happening here?
So apparently the index value comes from the underlying bokeh columndata source.
Im unsure of the best way to access it, so i used a hook and access it as a closure.
import numpy as np
from holoviews import opts
import panel as pn
import numpy as np
import holoviews as hv
import pandas as pd
pn.extension()
hv.extension('bokeh')
samples = 100
pets = ['Cat', 'Dog', 'Hamster', 'Rabbit']
genders = ['Female', 'Male']
pets_sample = np.random.choice(pets, samples)
gender_sample = np.random.choice(genders, samples)
count = np.random.randint(1, 5, size=samples)
df = pd.DataFrame({'Pets': pets_sample, 'Gender': gender_sample, 'Count': count})
closure_map = {}
def cds_swap_hook(plot, element):
renderer = plot.handles['glyph_renderer']
closure_map["data_source"] = renderer.data_source
bars = hv.Bars(df, kdims=['Pets', 'Gender']).aggregate(function=np.sum).opts(opts.Bars(tools=["hover", "tap"], hooks=[cds_swap_hook])).opts(width=500, axiswise=True)
stream = hv.streams.Selection1D(source=bars)
def tap_cb(index):
if not index:
return hv.Bars(df, kdims=['Pets', 'Gender']).select(Pets="Cat", Gender="Female")
selected_gender = closure_map["data_source"].data["Gender"][index][0]
selected_pet = closure_map["data_source"].data["Pets"][index][0]
return hv.Bars(df, kdims=['Pets', 'Gender']).select(Pets=selected_pet, Gender=selected_gender)
dependend_dmap = hv.DynamicMap(tap_cb, streams=[stream])
pn.Column(
bars,
dependend_dmap
)
This solves my problem of accessing the selected data, but it feels kinda hacky.
As a result i can show a drilled down plot of the selected data.
Posting this so maybe someone can get a use of it