How to have a select widget filter a datatable

I am a bokeh noob, and am trying to get a select widget to filter down a datable.

So far, I have managed to create the selection widget and original datatable. When I implement the callback, to create the filtered table, a filtered datatable does not appear.

I might be missing something obvious, and hope that someone can give me guidance.

Thanks

from bokeh.io import output_notebook, show
from bokeh.layouts import widgetbox, column, row
from bokeh.models.widgets import Select, DataTable, TableColumn
from bokeh.models.sources import ColumnDataSource, CDSView
from bokeh.models import CustomJS, Select
import pandas as pd

df = pd.DataFrame({'col1':["A","A","A","B","B","B"],
             'col2':["A1","A2","A3","B1","B2","B3"]})
category = Select(title = "Select Category:", options=sorted(list(set(df['col1']))), 
               value=sorted(list(set(df['col1'])))[0])

#Create data source
source=ColumnDataSource(data=dict(col1=df['col1'], col2=df['col2']))
filteredSource = ColumnDataSource(data=dict(col1=[],col2=[]))

#Create data table
columns = [TableColumn(field="col1",title="col1"),
           TableColumn(field="col2",title="col2",sortable=True)]
data_table=DataTable(source=filteredSource,columns=columns, width=400 )
data_table_unfiltered=DataTable(source=source,columns=columns, width=400 )

callback = CustomJS(args=dict(source=source,
                              filteredSource=filteredSource,
                              category=category),
                    code="""
    const data = source.data;
    const cat_value = category.value;
    const df2 = filteredSource.data;
    df2['col1'] = [];
    df2['col2'] = [];

    for (let i = 0; i < data['User'].length; i++) {
        if (data['col1'][i] === cat_value ) {
            df2['col1'].push(data['col1'][i])
            df2['col2'].push(data['col2'][i])
        }
    }

    filteredSource.change.emit()
""")

category.js_on_change('value', callback)
show(column(category, row(data_table,data_table_unfiltered)))

Running your code, in the JS console (ctrl-shift-i in the browser), I get an error saying “cannot read property ‘length’ from undefined”, which was a pretty dead giveaway.

You are looping through the length of data[‘User’], but there is no column called user in source. Changing it to data[‘col1’] and it runs fine for me.

1 Like