Periodically Run Callbacks#
This guide addresses how to set up per-session callbacks that run periodically.
Periodic callbacks allow periodically updating your application with new data. Below we will create a simple Bokeh plot and display it with Panel:
import numpy as np
import panel as pn
from bokeh.models import ColumnDataSource
from bokeh.plotting import figure
pn.extension()
source = ColumnDataSource({"x": np.arange(10), "y": np.arange(10)})
p = figure()
p.line(x="x", y="y", source=source)
bokeh_pane = pn.pane.Bokeh(p)
bokeh_pane.servable()
Now we will define a callback that updates the data on the ColumnDataSource
and use the pn.state.add_periodic_callback
method to schedule updates every 200 ms. We will also set a timeout of 5 seconds after which the callback will automatically stop.
Warning
The dynamic callbacks may not function properly in the online documentation. Please use them in a notebook or script.
def update():
data = np.random.randint(0, 2 ** 31, 10)
source.data.update({"y": data})
bokeh_pane.param.trigger('object') # Only needed in notebook
cb = pn.state.add_periodic_callback(update, 200, timeout=5000)
In a notebook or bokeh server context we should now see the plot update periodically. The other nice thing about this is that pn.state.add_periodic_callback
returns PeriodicCallback
we can call .stop()
and .start()
on if we want to stop or pause the periodic execution. Additionally we can also dynamically adjust the period by setting the timeout
parameter to speed up or slow down the callback.
Other nice features on a periodic callback are the ability to check the number of executions using the cb.counter
property and the ability to toggle the callback on and off simply by setting the running
parameter. This makes it possible to link a widget to the running state:
toggle = pn.widgets.Toggle(name='Toggle callback', value=True)
toggle.link(cb, bidirectional=True, value='running')
toggle
Note that when starting a server dynamically with pn.serve
you cannot start a periodic callback before the application is actually being served. Therefore you should create the application and start the callback in a wrapping function:
from functools import partial
import numpy as np
import panel as pn
from bokeh.models import ColumnDataSource
from bokeh.plotting import figure
def update(source):
data = np.random.randint(0, 2 ** 31, 10)
source.data.update({"y": data})
def panel_app():
source = ColumnDataSource({"x": np.arange(10), "y": np.arange(10)})
p = figure()
p.line(x="x", y="y", source=source)
cb = pn.state.add_periodic_callback(partial(update, source), 200, timeout=5000)
toggle = pn.widgets.Toggle(name='Toggle callback', value=True)
toggle.link(cb, bidirectional=True, value='running')
return pn.Column(pn.pane.Bokeh(p), toggle)
pn.serve(panel_app)