Retrieve click data from Python Holoviews / Datashader

539 views Asked by At

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

1

There are 1 answers

0
dll On BEST ANSWER

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