'Bokeh plot with multiple widgets
I am building an interactive Bokeh plot with two widgets: DateRangeSlider and Select, both are meant to update the contents displayed in the plot.
I have a dataframe of user activity per day. I want to use the Select widget to choose the user-id to be visualised, and DateRangeSlider to select the time period for the visualisation. Both work fine on their own, but I'm having difficulties getting everything to work together.
Specifically, if I select a customer id, I have no way of communicating that a specific customer was selected to the DateRangeSlider. Then my DateRangeSlider continues to display the distribution for all customers. Similarly, once I adjust the dates on the DateRangeSlider, my Select widget does not have that knowledge and will display activity of the selected customer for the entire date range.
I thought I'd need to pass variables from JS callbacks back to my Python code, but it doesn't seem possible. I have external restrictions that don't allow me to use Bokeh server either. I will appreciate any pointers in the right direction to help with this.
Here is the code for the DateRangeSlider:
source = ColumnDataSource(data={'x': groupedByDay.index, 'y': groupedByDay, 'dates': dates})
source2 = ColumnDataSource(data={'x': groupedByDay.index, 'y': groupedByDay, 'dates': dates})
date_range_slider = DateRangeSlider(value=(date(2021, 1, 1), date(2021, 3, 25)),
start=date(2021, 1, 1),
end=date(2021, 3, 25),
step=24*60*60*1000)
callback = CustomJS(args=dict(source=source,
ref_source=source2),
code="""
const date_from = cb_obj.value[0];
const date_to = cb_obj.value[1];
const data = source.data;
const ref = ref_source.data;
const from_pos = ref["x"].indexOf(date_from);
const to_pos = ref["x"].indexOf(date_to) + 1;
// re-create the source data from reference
data["y"] = ref["y"].slice(from_pos, to_pos);
data["x"] = ref["x"].slice(from_pos, to_pos);
data["dates"] = ref["dates"].slice(from_pos, to_pos);
source.change.emit();
""")
date_range_slider.js_on_change('value', callback)
This is the code for Select widget:
uploadsDict = {}
for firmName in firmsNameSelection:
if firmName == "Show all":
uploadsDict[firmName] = groupedByDay
continue
firm_df = df[df['firm'] == firmName]
firm_grouped = firm_df.groupby(['publish-date'])['publish-date'].count()
firm_grouped = firm_grouped.reindex(dates, fill_value=0)
uploadsDict[firmName] = firm_grouped
select = Select(title="Select customer:", value="Show all", options=list(firmsNameSelection))
firmSelectCallback = CustomJS(args=dict(source=source,
uploadsDict=uploadsDict,
currentSelection=currentSelection),
code="""
source.data.y = uploadsDict[this.value];
source.change.emit();
""")
select.js_on_change('value', firmSelectCallback)
Here's the code for the plot itslef:
plot = figure(title="Number of Documents Uploaded",
x_axis_type="datetime",
x_axis_label='',
y_axis_label='User activity')
barplot = plot.vbar(x='x', top='y', source=source, width=init_barwidth)
mylayout = layout(
[
[date_range_slider],
[select],
[plot]
]
)
show(mylayout)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|

