metaltoaster
metaltoaster

Reputation: 378

DataTable in Bokeh dashboard; reactive filtering with a slider widget

I am trying to use a slider widget in Bokeh to reactively filter a DataTable and I think I am missing something in my code. The table is not updating as I move the slider. Here is my code:-

from operator import index
from bokeh.models.widgets.markups import Div
import numpy as np
from numpy.lib import source
import pandas as pd
from bokeh.io import curdoc,show
from bokeh.layouts import column, row, gridplot,widgetbox
from bokeh.models import ColumnDataSource, CustomJS,Select, Slider, BoxSelectTool, LassoSelectTool, Tabs, Panel, LinearColorMapper, ColorBar, BasicTicker, PrintfTickFormatter, MultiSelect, DataTable, TableColumn
from bokeh.plotting import figure, curdoc
from bokeh.palettes import viridis, gray, cividis, Category20, Category20c
from bokeh.transform import factor_cmap,cumsum
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import classification_report, confusion_matrix, mean_squared_error, r2_score, recall_score, f1_score
from sklearn.preprocessing import StandardScaler, PolynomialFeatures
from sklearn.cluster import KMeans
from sklearn.svm import SVC
from sklearn.decomposition import PCA
from math import pi
from bokeh.transform import cumsum

np.random.seed(42)


print("step 1")
#define the categorical variable
category_a = ['A','B','C']
category_b = ['X','Y','Z']
print("step 2")
df_random = pd.DataFrame({
   'id': np.arange(0, 100),
   'date': pd.date_range(start='1/1/2021', periods=100, freq='D'),
   'month':np.random.randint(1, 12, 100),
   'sensor_1': np.random.uniform(0, 1,100),
   'sensor_2': np.random.uniform(10, 150, 100),
   'sensor_3': np.random.randint(0, 90, 100),
   'sensor_4': np.random.randint(0, 450, 100),
   'sensor_5': np.random.randint(0, 352, 100),
   'categorya': np.random.choice(category_a, 100, p=[0.2, 0.4, 0.4]),
   'categoryb': np.random.choice(category_b, 100, p=[0.6, 0.2, 0.2]),
})


source = ColumnDataSource(data=df_random)


columns = [
    TableColumn(field='id', title='ID'),
    TableColumn(field='date', title='Date'),
    TableColumn(field='month', title='Month'),
    TableColumn(field='sensor_1', title='Sensor 1'),
    TableColumn(field='sensor_2', title='Sensor 2'),
    TableColumn(field='sensor_3', title='Sensor 3'),
    TableColumn(field='sensor_4', title='Sensor 4'),
    TableColumn(field='sensor_5', title='Sensor 5'),
    TableColumn(field='categorya', title='Category A'),
    TableColumn(field='categoryb', title='Category B'),
]




data_table = DataTable(source=source, columns=columns, width=1100, height=280)

slider = Slider(start = 1, end = 100, value = 10, step = 1, title = "i", width = 300)

callback_code = """ i = slider.value;
                    new_data = groupeddf[sensor_2>=slider.value]
                    data_table.source.data = new_data """



callback = CustomJS(args = dict(slider = slider, table = data_table), code = callback_code)
slider.js_on_change('value', callback)


layouttable=widgetbox(slider, data_table)

curdoc().title = "table"
curdoc().add_root(layouttable)

Ideally, I would like to be able to add in more slider widgets to help me filter the data table to a granular level. But for now I would like to be able to get it working at a simple level. Can anyone point out what I am doing wrong?

Upvotes: 0

Views: 685

Answers (1)

first widgetbox not supported anymore. you should use row, column etc.

first : slider.on_change('value', update)

create a function that update

def update(attr, old, new):
    upd_slider = df_random[df_random['sensor_2'] > slider.value]
    updated_data ={
        'id': upd_slider['id'],
        'date': upd_slider['date'],
        'month': upd_slider['month'],
        'sensor_1': upd_slider['sensor_1'],
        'sensor_2': upd_slider['sensor_2'],
        'sensor_3': upd_slider['sensor_3'],
        'sensor_4': upd_slider['sensor_4'],
        'sensor_5': upd_slider['sensor_5'],
        'categorya': upd_slider['categorya'],
        'categoryb': upd_slider['categoryb'],
    }
    source.data = updated_data

we cannot change only sensor_2 like source.data['sensor_2] because it change only one value and lens of source would be different.

full code

from operator import index
from bokeh.models.widgets.markups import Div
import numpy as np
from numpy.lib import source
import pandas as pd
from bokeh.io import curdoc,show
from bokeh.layouts import column, row, gridplot,Column
from bokeh.models import ColumnDataSource, CustomJS,Select, Slider, BoxSelectTool, LassoSelectTool, Tabs, Panel, LinearColorMapper, ColorBar, BasicTicker, PrintfTickFormatter, MultiSelect, DataTable, TableColumn
from bokeh.plotting import figure, curdoc
from bokeh.palettes import viridis, gray, cividis, Category20, Category20c
from bokeh.transform import factor_cmap,cumsum
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import classification_report, confusion_matrix, mean_squared_error, r2_score, recall_score, f1_score
from sklearn.preprocessing import StandardScaler, PolynomialFeatures
from sklearn.cluster import KMeans
from sklearn.svm import SVC
from sklearn.decomposition import PCA
from math import pi
from bokeh.transform import cumsum

np.random.seed(42)


print("step 1")
#define the categorical variable
category_a = ['A','B','C']
category_b = ['X','Y','Z']
print("step 2")
df_random = pd.DataFrame({
   'id': np.arange(0, 100),
   'date': pd.date_range(start='1/1/2021', periods=100, freq='D'),
   'month':np.random.randint(1, 12, 100),
   'sensor_1': np.random.uniform(0, 1,100),
   'sensor_2': np.random.uniform(10, 150, 100),
   'sensor_3': np.random.randint(0, 90, 100),
   'sensor_4': np.random.randint(0, 450, 100),
   'sensor_5': np.random.randint(0, 352, 100),
   'categorya': np.random.choice(category_a, 100, p=[0.2, 0.4, 0.4]),
   'categoryb': np.random.choice(category_b, 100, p=[0.6, 0.2, 0.2]),
})


source = ColumnDataSource(data=df_random)


columns = [
    TableColumn(field='id', title='ID'),
    TableColumn(field='date', title='Date'),
    TableColumn(field='month', title='Month'),
    TableColumn(field='sensor_1', title='Sensor 1'),
    TableColumn(field='sensor_2', title='Sensor 2'),
    TableColumn(field='sensor_3', title='Sensor 3'),
    TableColumn(field='sensor_4', title='Sensor 4'),
    TableColumn(field='sensor_5', title='Sensor 5'),
    TableColumn(field='categorya', title='Category A'),
    TableColumn(field='categoryb', title='Category B'),
]
def update(attr, old, new):
    upd_slider = df_random[df_random['sensor_2'] > slider.value]
    updated_data ={
        'id': upd_slider['id'],
        'date': upd_slider['date'],
        'month': upd_slider['month'],
        'sensor_1': upd_slider['sensor_1'],
        'sensor_2': upd_slider['sensor_2'],
        'sensor_3': upd_slider['sensor_3'],
        'sensor_4': upd_slider['sensor_4'],
        'sensor_5': upd_slider['sensor_5'],
        'categorya': upd_slider['categorya'],
        'categoryb': upd_slider['categoryb'],
    }
    source.data = updated_data


data_table = DataTable(source=source, columns=columns, width=1100, height=280)

slider = Slider(start = 1, end = 100, value = 10, step = 1, title = "i", width = 300)
slider.on_change('value', update)





layouttable=Column(slider, data_table)

curdoc().title = "table"
curdoc().add_root(layouttable)

Upvotes: 1

Related Questions