hi there,
I try to use a text input to filter a data table using python. Using the example below it works well if you don’t select anything. However, if you select a row, I have to also update the select indices. This works also well but I keep loosing focus on my text input box whenever the datatable change with a selection, which make the entier tool unusable.
Any idea ? If possible I would like to not write JS code.
Thanks !
from bokeh.io import curdoc
from bokeh.layouts import column
from bokeh.models import ColumnDataSource
from bokeh.models.widgets import TextInput, DataTable, TableColumn
import pandas as pd
class SelectableDataTable() :
def __init__(self, df, select_column) :
self.df = df
self.sdf = df
self.source = ColumnDataSource(df)
self.select_column = select_column
self.ti = TextInput()
self.ti.on_change("value_input", self.input_callback)
columns = [TableColumn(field=column, title=column) for column in df.columns]
self.dt = DataTable(source=self.source, columns=columns, selectable="checkbox")
self.source.selected.on_change("indices", self.source_selection_change)
self.save_selection = True
self.selected = set()
def input_callback(self, attr, old, new) :
self.sdf = df[df[self.select_column].str.contains(new)]
self.source.data = self.sdf
sdf_idxs = list(self.sdf.index)
select_idx = [idx for idx, sdf_idx in enumerate(sdf_idxs) if sdf_idx in self.selected]
self.save_selection = False
self.source.selected.indices = select_idx
self.save_selection = True
def source_selection_change(self, attr, old, new) :
if not self.save_selection : return
sdf_idxs = list(self.sdf.index)
selected = {sdf_idxs[index] for index in new}
unselected = set(sdf_idxs) - selected
self.selected = (self.selected | selected) - unselected
df = pd.DataFrame({'numbers': list(range(10)), 'colors': ["red", "blue"] * 5}, columns=['numbers', 'colors'])
sdt = SelectableDataTable(df, "colors")
layout = column(sdt.ti, sdt.dt)
curdoc().add_root(layout)
Edit : fix a small bug