Hi, I recently learned how to use bokeh and I am having trouble making my python callbacks work with the bokeh server.
Here is my code (I’m building a candlestick chart with weather data):
from bokeh.client import push_session
from bokeh.plotting import figure, curdoc
from bokeh.models import ColumnDataSource, DatetimeTickFormatter, CDSView, BooleanFilter,HoverTool
from bokeh.models import Select
from bokeh.layouts import column, widgetbox
from make_datasets import hourly_all_winters
# Convert dataset to a column data source
source = ColumnDataSource(data={
'date': hourly_all_winters['date'],
'max': hourly_all_winters['max'],
'min': hourly_all_winters['min'],
'first': hourly_all_winters['first'],
'last': hourly_all_winters['last'],
'average': hourly_all_winters['mean'],
'winter': hourly_all_winters['winter'],
})
# Create first plot and select only the box_zoom and reset tools
y_range = (-30, 30)
p = figure(y_range=y_range, x_axis_type="datetime", plot_width=950, plot_height=200,
title=f"Daily temperature variations - winter {source.data['winter'][0]}",
x_axis_label='Months', y_axis_label='Temperature in °C',
tools="box_zoom,reset")
p.xaxis.formatter = DatetimeTickFormatter(months=['%B'])
# Create the range line glyph
p.segment('date', 'max', 'date', 'min', source=source, color="black")
# Create the ascending bars glyph - we need to create a view of our data with a boolean mask to only plot the data
# we want
booleans_inc = [True if last > first else False for last, first in zip(source.data['last'], source.data['first'])]
view_inc = CDSView(source=source, filters=[BooleanFilter(booleans_inc)])
booleans_dec = [True if last < first else False for last, first in zip(source.data['last'], source.data['first'])]
view_dec = CDSView(source=source, filters=[BooleanFilter(booleans_dec)])
w = 365 * 60 * 2000
p.vbar('date', w, 'first', 'last', source=source, view=view_inc, fill_color="#2c8cd1", line_color="#2c8cd1")
p.vbar('date', w, 'first', 'last', source=source, view=view_dec, fill_color="#F2583E", line_color="#F2583E")
# Create a hover tool so that we can see min, max, first and last values for each record
# over the plot
hover = HoverTool(tooltips=[("First", "@first{first.1f}"),
("Last", "@last{last.1f}"),
("Min", "@min{min.1f}"),
("Max", "@max{max.1f}"), ], mode='vline')
p.add_tools(hover)
# Make a slider object
slider = Select(options=['', '2013-2014', '2014-2015', '2015-2016', '2016-2017', '2017-2018', '2018-2019'],
value='', title='Winter')
def update_plot(attr, old, new):
if new == '':
source.data = ColumnDataSource(data={'date': hourly_all_winters['date'],
'max': hourly_all_winters['max'],
'min': hourly_all_winters['min'],
'first': hourly_all_winters['first'],
'last': hourly_all_winters['last'],
'average': hourly_all_winters['mean'],
'winter': hourly_all_winters['winter'],}).data
else:
new_source = ColumnDataSource(data={'date': hourly_all_winters[hourly_all_winters.winter == winter]['date'],
'max': hourly_all_winters[hourly_all_winters.winter == new]['max'],
'min': hourly_all_winters[hourly_all_winters.winter == new]['min'],
'first': hourly_all_winters[hourly_all_winters.winter == new]['first'],
'last': hourly_all_winters[hourly_all_winters.winter == new]['last'],
'average': hourly_all_winters[hourly_all_winters.winter == new]['mean'],
'winter': hourly_all_winters[hourly_all_winters.winter == new]['winter'],
})
source.data = new_source.data
# Attach the callback to the 'value' property of slider
slider.on_change('value', update_plot)
# put the button and plot in a layout and add to the document
curdoc().add_root(column(widgetbox(slider), p))
show(curdoc())
I tried both starting with my “2013-2014” data and the full dataset but every time I run my code I get the first visualization working, but selecting other data with the dropdown only returns a blank plot. Any thoughts on what I may have missed? I also tried using push_session() to see if it’d help with no luck.