☰Read-only archive⌕
Looking for help with Bokeh?

This is a read-only archive. Ask questions and join the conversation on GitHub.

Visit Community Support on GitHub →
Archived discussions · Captured October 28, 2026

Updating multiple tabs in DataTable using 1 slider for all tabs

Community Support
1111
1111

See the code below.

I have a loop that creates 3 tabs on 1 DataTable and 1 RangeSlider.

I want all 3 tabs to update when I use the slider, but unfortunately only the last tab updates.

It probably has something to do with the iteration because it’s the last tab always, but I can’t wrap my head around how to make it work.

from bokeh.models.widgets import DataTable, DateFormatter, TableColumn, Panel, Tabs, RangeSlider
from bokeh.io import output_file, show
from bokeh.models import ColumnDataSource, Div
from bokeh.plotting import curdoc
from bokeh.plotting import figure
from bokeh.layouts import layout, widgetbox, row, column
from datetime import date
from random import randint

import pandas as pd

from os.path import dirname, join

df1 = pd.DataFrame(
        {'x': [date(2014, 3, i+1) for i in range(10)],
         'y': [randint(0, 100) for i in range(10)],
         'z': [randint(0, 50) for i in range(10)],
         'q': ['B' for i in range(10)]
        })
df2 = pd.DataFrame(
        {'x': [date(2014, 3, i+1) for i in range(10)],
         'y': [randint(0, 100) for i in range(10)],
         'z': [randint(0, 50) for i in range(10)],
         'q': ['A' for i in range(10)]
        })
df3 = pd.DataFrame(
        {'x': [date(2014, 3, i+1) for i in range(10)],
         'y': [randint(0, 100) for i in range(10)],
         'z': [randint(0, 50) for i in range(10)],
         'q': ['A' for i in range(10)]
        })

value_slider = RangeSlider(title="Value", range =(0,100), start=0, end=100, step=1)

tab_list = []
for df in [df1, df2, df3]:
    source = ColumnDataSource(data=dict(
            x=df['x'],
            y=df['y'],
            z=df['z']
        ))
    columns = [
        TableColumn(field="x", title="Date", formatter=DateFormatter()),
        TableColumn(field="y", title="Downloads"),
        TableColumn(field="z", title="Z"),
        ]

    data_table = DataTable(source=source, columns=columns, width=400, height=280)
    tab = Panel(child=data_table, title="table")
    tab_list.append(tab)

    def select():
        selected = df[
            (df['y'] >= value_slider.range[0]) &
            (df['y'] <= value_slider.range[1])
                ]
        return selected

    def update():
        df1 = select()
        source.data = dict(
            x = df1['x'],
            y = df1['y'],
            z = df1['z'],
            )

tabs = Tabs(tabs=tab_list)
value_slider.on_change('range' ,lambda attr, old, new: update())
selectors = widgetbox(value_slider,width=200)

all_plot = row(column(selectors), tabs)
sizing_mode = 'fixed'
l = layout([[all_plot]], sizing_mode=sizing_mode)

curdoc().add_root(l)

⌁   Link to post
Sebastien_Roche
Sebastien_Roche

Your functions definition should not be in the for loop. Even outside the select() callback is not necessary, and anyway it’s using the last value taken by ‘df’, which is df3, that’s why only your last table updates.

This works:
from bokeh.models.widgets import DataTable, DateFormatter, TableColumn, Panel, Tabs, RangeSlider
from bokeh.io import output_file, show
from bokeh.models import ColumnDataSource, Div
from bokeh.plotting import curdoc
from bokeh.plotting import figure
from bokeh.layouts import layout, widgetbox, row, column
from datetime import date
from random import randint

import pandas as pd

from os.path import dirname, join

df1 = pd.DataFrame(
{‘x’: [date(2014, 3, i+1) for i in range(10)],
‘y’: [randint(0, 100) for i in range(10)],
‘z’: [randint(0, 50) for i in range(10)],
‘q’: [‘B’ for i in range(10)]
})
df2 = pd.DataFrame(
{‘x’: [date(2014, 3, i+1) for i in range(10)],
‘y’: [randint(0, 100) for i in range(10)],
‘z’: [randint(0, 50) for i in range(10)],
‘q’: [‘A’ for i in range(10)]
})
df3 = pd.DataFrame(
{‘x’: [date(2014, 3, i+1) for i in range(10)],
‘y’: [randint(0, 100) for i in range(10)],
‘z’: [randint(0, 50) for i in range(10)],
‘q’: [‘A’ for i in range(10)]
})

value_slider = RangeSlider(title=“Value”, range =(0,100), start=0, end=100, step=1)

columns = [TableColumn(field=“x”, title=“Date”, formatter=DateFormatter()),
TableColumn(field=“y”, title=“Downloads”),
TableColumn(field=“z”, title=“Z”),
]

tab_list =
df_list = [df1, df2, df3]
source_list = [ColumnDataSource(data={‘x’:df[‘x’],‘y’:df[‘y’],‘z’:df[‘z’]}) for df in df_list]
tab_list = [Panel(child=DataTable(source=source, columns=columns, width=400, height=280), title=“table”) for source in source_list]

def update():
for i,source in enumerate(source_list):
new_df = df_list[i][(df_list[i][‘y’]>=value_slider.range[0]) & (df_list[i][‘y’]<=value_slider.range[1])]
source.data = { ‘x’:new_df[‘x’],‘y’:new_df[‘y’],‘z’:new_df[‘z’],}

tabs = Tabs(tabs=tab_list)
value_slider.on_change(‘range’ ,lambda attr, old, new: update())
selectors = widgetbox(value_slider,width=200)

all_plot = row(column(selectors), tabs)
sizing_mode = ‘fixed’
l = layout([[all_plot]], sizing_mode=sizing_mode)

curdoc().add_root(l)

``

⌁   Link to post

End of archived discussion · Replies are disabled