'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)

Here's the demonstration of my plot and the two widgets not working together properly



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source