'Retrieve click data from Python Holoviews / Datashader

I'm coming from Python-Dash trying to achieve an interactive graphing functionality by creating a second graph using the click data of the first one. Similar to what can be found here

I'm stuck in retrieving and correctly using the click data to potentially create a second graph.

Here is what I've tried:

import numpy as np
import pandas as pd
import holoviews as hv
from holoviews.operation.datashader import datashade, dynspread
from holoviews import streams
import panel as pn 
import datashader as ds
hv.extension("bokeh")
packages=[np,pd, hv, pn, ds]
for i in packages: print(i.__name__, i.__version__)

#dummy data
N=1200
np.random.seed(123)
df = pd.DataFrame({
    'date': np.arange(0,N,1),
    'product' : [np.random.choice(['A', 'B']) for i in range(N)],
    'quantity' : np.random.randint(1,10,N),
    'price' : np.random.randint(50,100,N),
})
df.head(2)

def clicked_point(x, y):
    return pn.pane.Str('Click at %0.2f, %0.2f' % (x, y), width=200)

kdims = ['date', 'quantity']
vdims = ['product', 'quantity']
points  = hv.Points(df, kdims, vdims)

shaded = datashade(points)
spreaded = dynspread(shaded)
plot = spreaded.opts(tools=['hover','tap'])

stream = hv.streams.Tap(source=spreaded, x=np.nan, y=np.nan)
layout = pn.Row(plot, pn.bind(clicked_point, x=stream.param.x, y=stream.param.y))
layout

enter image description here

The problem is that it's unclear to me how to use the click data printed on right of the graph and/or the data available in the tooltip to, for example, go back to the original dataframe and filter it based on these values. It would be nice to be able to do something like:

df2=df.loc[(df['date']==clicked_date) & (df['quantity']==clicked_quantity) ]

I'd appreciate any suggestion on this regard.

Best,

dll



Solution 1:[1]

Basically, this requires to create a function to filter the data based on the click data create a streams object in holoviews to capture the events data and then put them together in the table. Notice there could be multiple ways of approximating the x-y coordinates to actual points in the data. In this case, for instance, I just rounded up x and y coordinates:

def click_table(x,y):    
   if x  is None or y is None:
       df2=[]
   else:
       df2=table[round(x,0) , round(y,0)]
return df2 

stream = hv.streams.Tap(source=spreaded, x=np.nan, y=np.nan)
layout = pn.Row(plot, 
            pn.bind(clicked_point, x=stream.param.x, y=stream.param.y),
            pn.bind(click_table, x=stream.param.x, y=stream.param.y)
           )
layout

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Andronicus