I’d like to have a bi-directional link from a scatter plot to a tabulator table. Everything works in this example, except when a Tabulator row is chosen, it is not reflected in the scatter plot.
_table_selected
captures the event but how can I update the plot to select the point in the plot? Is there a better way to link these objects?
import param
import panel as pn
import pandas as pd
import holoviews as hv
from holoviews.streams import PointDraw, Selection1D
hv.extension("bokeh")
pn.extension("tabulator")
class PlotLinker(param.Parameterized):
df = param.DataFrame(pd.DataFrame(data={"x": [0, 5, 10], "y": [0, 3, 10]}))
stream = param.ClassSelector(default=PointDraw(drag=True, add=False),
class_=(PointDraw),
precedence=-1)
selection = param.ClassSelector(default=Selection1D(),
class_=(Selection1D),
precedence=-1)
def table(self):
self.table_ = pn.widgets.Tabulator(self.df,
width=500,
layout="fit_columns")
self.table_.link(self.df,
callbacks={"value": self._callback_tabulator})
self.table_.param.watch(self._table_selected, 'selection')
return self.table_
def scatter(self):
points = hv.Scatter(self.df)
points.opts(tools=["hover"], active_tools=["point_draw"], size=10)
self.stream.source = points
self.selection.source = points
return points
@pn.depends("stream.data", watch=True)
def _update_dataframe(self):
"""Function to reflect the change in the PointDraw data to the original data"""
print('_update_dataframe')
stream_df = pd.DataFrame(self.stream.data)
if not stream_df.equals(self.df):
df = stream_df.reset_index()
if "index" in df.columns:
df = df.drop(["index"], axis=1)
self.df = df
def _callback_tabulator(self, target, event):
"""Simple callback to update the values when the table is updated"""
print('_callback_tabulator')
df = event.new
if "index" in df.columns:
df = df.drop(["index"], axis=1)
self.df = df
@param.depends('selection.index', watch=True)
def _point_selected(self):
''' link scatter plot selection to table row '''
print('_point_selected')
self.table_.selection = self.selection.index
# ??? doesn't update scatter & re-triggers seloection.index
def _table_selected(self, event):
''' link table row selection to scatter plot '''
print('_table_selected')
print(event)
# self.selection.update(index=event.new)
def view(self):
return pn.Row(self.scatter, self.table)
pl = PlotLinker()
pn.Row(pl.scatter, pl.table).servable()