1

I have a data table with 40+ columns. I can choose which columns to show in the data table by changing the TableColumn attribute visible to True or False. Here's a small example

filtered_table_data=df[["Date","Li","Be"]]

filtered_table_source= ColumnDataSource(data=filtered_table_data)

filtered_table_cols=[]

filtered_table_cols.append(TableColumn(field='Date', title='Date', width=2000, visible=True))
filtered_table_cols.append(TableColumn(field='Li', title='Li', width=750, visible=False))
filtered_table_cols.append(TableColumn(field='Be', title='Be', width=750,visible=True))
 
filtered_table=DataTable(source=filtered_table_source, columns=filtered_table_cols)

What I would like to do is use the multi choice widget to be able to choose which columns to show in the data table. For example if only Date and Li is selected then those Table Columns would be set to visible and Be would be set to visible=False. I do not know how to write the callback for that or if I need a customjs callback or just an update function

code so far:

# def update():
#     cols=["Date"]+multi_choice.value
#     current=df[cols]


filtered_table_data=df[["Date","Li","Be"]]

filtered_table_source= ColumnDataSource(data=filtered_table_data)

filtered_table_cols=[]

filtered_table_cols.append(TableColumn(field='Date', title='Date', width=2000))
filtered_table_cols.append(TableColumn(field='Li', title='Li', width=750,))
filtered_table_cols.append(TableColumn(field='Be', title='Be', width=750))
 
filtered_table=DataTable(source=filtered_table_source, columns=filtered_table_cols)

multi_choice = MultiChoice(value=["Li", "Be"], options=df.columns[2:-1].tolist(), title='Select elements:')

#multi_choice.on_change("value",lambda attr, old, new: update()) 

l2=layout([multi_choice, filtered_table])

show(l2)
Gingerhaze
  • 664
  • 2
  • 5
  • 13

1 Answers1

1

You do need a CustomJS callback. The code below should fit your needs. I used the CheckboxButtonGroup instead of MultiChoice, feel free to adapt it (you can try it in a Jupyter Notebook).

import pandas as pd
from bokeh.models import ColumnDataSource, DataTable, TableColumn, CustomJS, CheckboxButtonGroup
from bokeh.io import show, output_notebook
from bokeh.layouts import column
output_notebook()

def create_table(doc):
    
    # create dataframe
    df = pd.DataFrame({
        'Date': ['2023-01-01', '2023-01-01', '2023-01-01'],
        'Li': [1, 2, 3],
        'Be': [100, 200, 300]
    })
    df_dict = df.to_dict("list")
    cols = list(df_dict.keys())

    # create column datasource
    source = ColumnDataSource(data=df)

    # create figure
    columns = []
    for col in cols:
        columns.append(TableColumn(field=col, title=col))
    figure = DataTable(source=source, columns=columns)

    # create widget
    checkbox_button_group = CheckboxButtonGroup(labels=cols, active=list(range(len(df))))
    checkbox_button_group.js_on_click(CustomJS(code="""
        console.log('checkbox_button_group: active=' + this.active, this.toString())
    """))
    
    # update columns to display
    def update_cols(df, display_columns=None):
        if display_columns is None:
            display_columns = []
        figure.columns = [col for col in columns if col.title in display_columns]

    def update(attr, old, new):
        cols_to_display = [checkbox_button_group.labels[i] for i in checkbox_button_group.active]
        update_cols(df=df, display_columns=cols_to_display)

    checkbox_button_group.on_change('active', update)
        
    doc.add_root(column(checkbox_button_group, figure))

show(create_table)
Juliette B
  • 186
  • 1
  • 5