Please, any idea how to update the slider min and max values, index_min and index_max, with users Select widget? For example, when u1 is selected, the min and max values of the slider should be 2586 and 2836.
import pandas as pd
from bokeh.layouts import column, layout
from bokeh.models import ColumnDataSource, Select, Slider
from bokeh.io import curdoc
from bokeh.plotting import figure
df = pd.DataFrame({'Time': [2586, 2836, 2986, 3269, 3702],
'X': [120, 210, 80, 98, 40],
'Y': [230, 40, 33, 122, 10],
'User': ['u1', 'u1', 'u2', 'u2', 'u2'],
'img': ['tree1.png', 'tree2.jpg', 'tree3.jpg', 'tree4.jpg','tree5.jpg']})
source = ColumnDataSource(data=dict(time=[], x=[], y=[], user=[], img=[]))
options = sorted(set(df['User']))
user_options = ['Please select ...'] + options
users = Select(title="User:", value=user_options[0], options=user_options)
index_min = df['Time'].min()
index_max = df['Time'].max()
index = Slider(start=index_min, end=index_max, value=index_max , step=1, title="Time Index")
def select_user():
user_val = users.value
selected = df[(df.Time <= index.value)]
if (user_val != ""):
selected = selected[selected.User.str.contains(user_val)==True]
return selected
def update():
dfnew = select_user()
source.data = dict(time=dfnew['Time'], x=dfnew['X'], y=dfnew['Y'], user=dfnew['User'], img=dfnew['img'])
controls = [users, index]
for control in controls:
control.on_change('value', lambda attr, old, new: update())
p = figure(plot_width = 600, plot_height = 600)
p.circle(x="x", y="y", source=source, legend='user')
update() # initial load of the data
l = layout(column(users, index, p))
curdoc().add_root(l)
Here's how I would do it.
import pandas as pd
from bokeh.io import curdoc
from bokeh.layouts import column
from bokeh.models import ColumnDataSource, Select, Slider
df = pd.DataFrame({'Time': [2586, 2836, 2986, 3269, 3702, 1, 2],
'X': [120, 210, 80, 98, 40, 0, 1],
'Y': [230, 40, 33, 122, 10, 1, 2],
'User': ['u1', 'u1', 'u2', 'u2', 'u2', 'u3', 'u4'],
'img': ['tree1.png', 'tree2.jpg', 'tree3.jpg', 'tree4.jpg', 'tree5.jpg', 'x', 'x']})
source = ColumnDataSource(data=dict(time=[], x=[], y=[], user=[], img=[]))
user_options = [('', 'Please select ...')] + [(o, o) for o in sorted(set(df['User']))]
users = Select(title="User:", value=user_options[0][0], options=user_options)
index = Slider(start=0, end=1, value=0, step=1, title="Time Index")
def filter_by_user(user):
if user:
return df[df['User'] == user]
return df
def on_user_change(attr, old, new):
selected = filter_by_user(new)
start = selected['Time'].min()
end = selected['Time'].max()
index.update(start=start,
end=end + 1 if start == end else end,
value=start,
disabled=start == end)
users.on_change('value', on_user_change)
def on_index_change(attr, old, new):
selected = filter_by_user(users.value)
dfnew = selected[selected['Time'] <= new]
# Note: if you rename your df columns to all lower-case, then you can just use `ColumnDataSource.from_df()`.
source.data = dict(time=dfnew['Time'], x=dfnew['X'], y=dfnew['Y'], user=dfnew['User'], img=dfnew['img'])
index.on_change('value', on_index_change)
# Just to populate the initial data.
on_user_change(None, None, '')
curdoc().add_root(column(users, index))