I’m trying to use tabulator header filtering to enable a user to apply bulk editing to a flag
column via button only on filtered rows. The problem I’m having is that after this operation, I am unable to “release” the filter and get all rows back without manually running _update_cds()
. tabulator.current_view
and
tabulator.filters
reflect the removal of headerfilter (all rows/ no filters), however what is displayed does not update without the manual _update_cds()
.
I’ve also attempted applying the bulk edit via _process_events({"data":{}})
which would call _process_data()
because the comment here sounds related, but it runs into the same issue.
The code (many thinks @Marc for Handling returns from button.on_click - #5 by Marc) is as follows:
import pandas as pd # v2.0.2
import panel as pn # v1.2.3
pn.extension("tabulator")
import param # v1.13.0
# # only for jupyterlab development
%load_ext blackcellmagic
from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"
class BulkEditTabulator(pn.viewable.Viewer):
# adapted from # https://discourse.holoviz.org/t/handling-returns-from-button-on-click/733/5
data = param.DataFrame()
flag_filtered = param.Action(label="Flag filtered rows")
unflag_filtered = param.Action(label="Unflag filtered rows")
update_cds = param.Action(
label="manual run _update_cds"
)
def __init__(self, **params):
params["data"] = pd.DataFrame({"flag":[0,0,0,0,0,0], "filter_column":["a","a", "b", "c", "c","c"]})
params["flag_filtered"] = self._flag_filtered
params["unflag_filtered"] = self._unflag_filtered
params["update_cds"] = self._update_cds
super().__init__(**params)
self._view = None
self._create_tabulator()
def _create_tabulator(self):
self.tabulator = pn.widgets.Tabulator(
self.data,
show_index=False,
header_filters=True,
)
return self.tabulator
def _flag_filtered(self, event=None):
"""set filtered rows 'flag' column to 1"""
value = 1
self.tabulator.patch(
{"flag": [(i, value) for i in self.tabulator.current_view.index]},
as_index=True,
)
def _unflag_filtered(self, event=None):
"""set filtered rows 'selection' column to None"""
value = 0
self.tabulator.patch(
{"flag": [(i, value) for i in self.tabulator.current_view.index]},
as_index=True,
)
def _update_cds(self, event=None):
"""manual update displayed table when header filter removal doesn't release filters"""
self.tabulator._update_cds()
def _get_view(self):
if not self._view:
flag_button = pn.widgets.Button.from_param(
self.param.flag_filtered, button_type="success"
)
unflag_button = pn.widgets.Button.from_param(
self.param.unflag_filtered, button_type="danger"
)
update_cds_button = pn.widgets.Button.from_param(
self.param.update_cds, button_type="warning"
)
self._view = pn.Column(
pn.Row(flag_button, unflag_button, update_cds_button), self.tabulator
)
return self._view
def __panel__(self):
return self._get_view()
app = BulkEditTabulator()
app.servable()