Took me a while to assemble one, given that my actual code is a big bulk, but here it is.
Supposed to be executed as a Bokeh server.
To produce the bug, change the value of the range slider twice.
from bokeh.plotting import figure, curdoc
from bokeh.models import ColumnDataSource, Label, RangeSlider
from bokeh.layouts import column
from random import *
def loading_pic(width: int = 500, height: int = 500) -> figure:
plot = figure(x_range=(0,width), y_range=(0,height), width=width, height=height, tools='')
pos_x = width/2
pos_y = height/2
label_size = min(height/4, width/4)
label_size_str = str(label_size)+'px'
loading_label = Label(x=pos_x, y=pos_y, text='Loading', text_font_size = label_size_str,
text_align='center', text_baseline='middle')
plot.add_layout(loading_label)
plot.xaxis.visible = False
plot.yaxis.visible = False
plot.xgrid.grid_line_color = None
plot.ygrid.grid_line_color = None
return plot
def random_coords(maximum: float = 500, amount: int = 1000) -> ColumnDataSource:
data = ColumnDataSource()
data.data['x'] = [random()*maximum for i in range(amount)]
data.data['y'] = [random()*maximum for i in range(amount)]
return data
class MyPlot:
def __init__(self, data: ColumnDataSource):
self.plot = figure(x_range=(0,500), y_range=(0,500), width=500, height=500)
self.plot.circle(source=data, x='x', y='y')
class MyFrame:
def __init__(self):
self.layout = column()
self.loading = loading_pic()
self.layout.children.append(self.loading)
def display_loading(self) -> None:
self.layout.children[0] = self.loading
def plot(self, data) -> None:
self.my_plot = MyPlot(data)
self.layout.children[0] = self.my_plot.plot
def plot_delayed(self, attr, old, new) -> None:
self.display_loading()
data = random_coords()
curdoc().add_next_tick_callback(lambda: self.plot(data))
my_frame = MyFrame()
range_slider = RangeSlider(start = 0, end = 10, value = (0,10), step = 1, title = 'Range')
range_slider.on_change('value_throttled', my_frame.plot_delayed)
layout = column(my_frame.layout, range_slider)
curdoc().add_root(layout)