Hi, I am new to bokeh applications with streamlit. I am trying to use customJS callback to update my plot if there is any change in the select widgets. I made up the following code and unfortunately plot is not updating after the change in select value.
here is the minimal working example code:
import pandas as pd
import streamlit as st
from copy import deepcopy
import numpy as np
from state import provide_state
import bokeh
from streamlit_bokeh_events import streamlit_bokeh_events
from bokeh.layouts import column, row
from bokeh.models import Slider, TextInput,Dropdown,Select,Button
from bokeh.plotting import figure
from bokeh.models import ColumnDataSource, CDSView, annotations, BooleanFilter, CustomJS, HoverTool
from colorcet import glasbey
def get_sizer(X, min_size, max_size):
X_std = (X - X.min(axis=0)) / (X.max(axis=0) - X.min(axis=0))
X_scaled = X_std * (max_size - min_size) + min_size
return X_scaled.fillna(min_size)
my_data = { 'group_1':['cat','dog','cat','dog','bull','bull','cat','rat'],
'group_2':['lion','tiger','deer','tiger','deer','deer','lion','lion'],
'group_3':['grass','bush','flower','leaf','grass','leaf','bush','grass'],
'length':[5,6,5,6,4,3,7,3],
'length_1':[25,36,45,36,54,43,76,37],
'width':[1,2,4,3,4,2,4,5],
'width_1':[11,12,14,13,14,12,14,15],
'size_1': [10,23,45,12,10,45,43,29]
}
st.set_page_config(
layout="wide",
page_title="Reference Search",
)
st.write('''# Animal category search''')
st.session_state.data = my_data.copy()
plot_data = pd.DataFrame(st.session_state.data )
coloring = Select(title="Select for coloring:", value="group_1", options=['group_1','group_2','group_3'])
color_label = coloring.value
sizing = Select(title="Select for sizing:", value="size_1", options=['length','length_1','width','width_1','size_1'])
sizing_label = sizing.value
palette = glasbey[:len(plot_data[color_label].unique())]
color_map = bokeh.models.CategoricalColorMapper(factors=plot_data[color_label].unique(),palette=palette)
plot_data['Size'] = get_sizer(plot_data[sizing_label], 10, 40)
plot_data['Half_Size'] = plot_data['Size']/1000
source = ColumnDataSource(plot_data.reset_index().rename(columns={'index':'Animal'}))
print(source.data)
p = figure( plot_width=800, plot_height=600,
title = 'animal categories',
tools='''pan,lasso_select,box_select,wheel_zoom,reset''',
active_scroll = 'wheel_zoom',active_inspect = None,
toolbar_location = 'above'
)
p.add_layout(annotations.Legend(), 'right')
p.legend.click_policy = 'hide'
p.scatter(x='length',y='width',
color={'field': color_label, 'transform': color_map},
legend=color_label, source=source)
callback = CustomJS(args=dict(source=source,plot=p,coloring=coloring,sizing=sizing), code="""
var data = source.data
var a =coloring.value;
var s = sizing.value;
var palette = glasbey[:len(data[a].unique())];
var color_map = bokeh.models.CategoricalColorMapper(factors=data[a].unique(),palette=palette)
plot.color={'field': color_cat_label, 'transform': color_map}
plot.legend=color_cat_label
plot.change.emit()
""")
coloring.js_on_change('value', callback)
sizing.js_on_change('value', callback)
streamlit_bokeh_events(
events="SelectEvent",
bokeh_plot=column(row(coloring,sizing,width=800),p),
key="foo2",
#refresh_on_update=True,
debounce_time=0,
)
It is able to produce a scatter plot with colourmap based on grouping initially, but not updating the plot once the grouping parameters for colourmap has changed through a select widget. initially let’s only concentrate on colouring widget, I am working on functionality to update my plot besed on select widgets colour group categories.
To be precise, I am not able to write proper CustomJS callback to update my plot.
when we only stick to coring widget change, there is no change in the source data x and y values. so, please do help me in writing proper CustomJS callback.