Tabulator view sync with points view

Using the discussion here Bi-directional Link with Tabulator and Plot - #18 by rh1, I created a similar example with Tabulator and hv.Point to do selection sync between the Tabulator and Point view.

Also moving the conversation with @ahuang11 from Discord

However when I add header_filters to the Tabulator, I would like to sync the Point view with the Tabulator current view.

import panel as pn
import pandas as pd
import holoviews as hv
from holoviews import streams

pn.extension("tabulator")

df = pd.DataFrame(data={"x": [0, 5, 2], "y": [0, 3, 7], "label": ["a", "b", "c"]})

scatter = hv.Scatter(df, "x", "y").opts(
    xlim=(-10, 10), size=10, selected=[1], tools=["tap"]
)

tabulator = pn.widgets.Tabulator(df, selection=[], header_filters=True)


def update_scatter(selection):
    """link table row selection to scatter plot"""
    # print("row_selected", selection)
    return hv.Points(df, kdims=["x", "y"], vdims=["label"]).opts(
        xlim=(-10, 10),
        ylim=(-10, 10),
        size=10,
        selected=selection,
        tools=["tap", "box_select"],
    )


def point_selected(index):
    """link scatter plot selection to table row"""
    # print("point_selected", index)
    tabulator.selection = index


plot = hv.DynamicMap(pn.bind(update_scatter, tabulator.param.selection))

sel = streams.Selection1D(source=plot)

sel.param.watch_values(point_selected, "index")
# tabulator.param.watch_values(row_selected, 'selection')

pn.Row(tabulator, plot).servable()

1 Like

I believe you need to watch filters, so tabulator.param.filters and apply those same filters in the backend:
[{'field': 'Director', 'type': '=', 'value': 'Steven Spielberg'}]

When a filter is applied client-side the `filters` parameter is synced with Python. The definition of `filters` looks something like this:

Can take a deeper look next week!

Don’t know how I missed that! It works fine now, however the selection from the points view breaks if I update the plot with the tabulator.current_view.

import panel as pn
import pandas as pd
import holoviews as hv
from holoviews import streams

pn.extension("tabulator")

df = pd.DataFrame(data={"x": [0, 5, 2], "y": [0, 3, 7], "label": ["a", "b", "c"]})

scatter = hv.Points(df, kdims=["x", "y"], vdims=["label"]).opts(
    xlim=(-10, 10), size=10, selected=[1], tools=["tap"]
)

tabulator = pn.widgets.Tabulator(df, selection=[], header_filters=True)


def update_scatter(selection, filters):
    """link table row selection to scatter plot"""
    # print("row_selected", selection)
    dff = tabulator.current_view
    return hv.Points(dff, kdims=["x", "y"], vdims=["label"]).opts(
        xlim=(-10, 10),
        ylim=(-10, 10),
        size=10,
        selected=selection,
        tools=["tap", "box_select"],
    )


def point_selected(index):
    """link scatter plot selection to table row"""
    # print("point_selected", index)
    tabulator.selection = index


plot = hv.DynamicMap(
    pn.bind(update_scatter, tabulator.param.selection, tabulator.param.filters)
)

sel = streams.Selection1D(source=plot)

sel.param.watch_values(point_selected, "index")
# tabulator.param.watch_values(row_selected, 'selection')

pn.Row(tabulator, plot).servable()

Nice!

Can you clarify what you mean by that? I don’t quite follow.

When filtered the selection doesn’t work. I think it has to do with the index on the points is on current viewable points while the index on the tabulator view is based on the entire original dataframe.
It works but it would be great if it worked with link_selections or via javascript directly.
See failing selection reel below

@ahuang11 Another issue is that the selection event gets triggered again via hv.Points(…, selected=…) and tabulator.selection=… So one has to have logic to figure out if the call is originating from one of these. Is there a better solution?

Also would like to throttle the selection and filters. I went down the rabbit hole with value_throttled being mentioned but that doesn’t have an application here as there is no filters_throttled or selection_throttled available.

Both operations are firing off a series of events as a user types in values in the header_filters for the tabulator and for lasso selection for points view. Is there a generic way to throttle pn.bind updates?

I don’t think there’s a value throttled for filter so maybe you can submit an issue.

Alternatively, workarounds include ensuring there are matching values before filtering, or manually adding an async countdown that resets after new input.

Hi Andrew,
I opened this issue for it.