Create Low-Level Python Links Using .watch
#
This guide addresses how to use the low-level .watch
API to trigger callbacks on parameters.
Prerequisites
The How to > Create High-Level Python Links with ‘.link’ guide demonstrates a high-level API to link to parameters, which is adequate in most cases.
If we need more control than what .link
provides, we can fall back to the underlying .watch
method. The main differences are that .watch
:
does not assume you are linking two objects (providing more control over what you are watching)
allows batched callbacks when multiple parameters change at once
allows you to specify that an event should be triggered every time the parameter is set (instead of the default of only when the parameter value actually changes)
To demonstrate .watch
, let us set up three different models:
Markdown
pane to display the possible optionsMarkdown
pane to display the selected optionsToggleGroup
widget that allows us to toggle between a number of options
import panel as pn
pn.extension()
selections = pn.pane.Markdown(object='')
selected = pn.pane.Markdown(object='')
toggle = pn.widgets.ToggleGroup(options=['A', 'B'])
Defining a callback#
Next we define a callback that can handle multiple parameter changes at once and uses the Event
’s name
to figure out how to process the event. In this case it updates either the selections
or the selected
pane depending on whether ToggleGroup options
or value
changed:
def callback(*events):
print(events)
for event in events:
if event.name == 'options':
selections.object = 'Possible options: %s' % ', '.join(event.new)
elif event.name == 'value':
selected.object = 'Selected: %s' % ','.join(event.new)
Event objects#
Before going any further let us discover what these Event
objects are. An Event
is used to signal the change in a parameter value. Event objects provide a number of useful attributes that provides additional information about the event:
name
: The name of the parameter that has changednew
: The new value of the parameterold
: The old value of the parameter before the event was triggeredtype
: The type of event (‘triggered’, ‘changed’, or ‘set’)what
: Describes what about the parameter changed (usually the value but other parameter attributes can also change)obj
: The Parameterized instance that holds the parametercls
: The Parameterized class that holds the parameter
Registering a watcher#
Now that we know how to define a callback and make use of Event
attributes, it is time to register the callback. The obj.param.watch
method lets us supply the callback along with the parameters we want to watch. Additionally we can declare whether the events should only be triggered when the parameter value changes, or every time the parameter is set:
watcher = toggle.param.watch(callback, ['options', 'value'], onlychanged=False)
Now let us display the widget alongside the Markdown
panes that reflect the current state of the widget:
pn.Row(pn.Column(toggle, width=200, height=50), selections, pn.Spacer(width=50, height=50), selected)
To initialize the selections
and selected
we can explicitly trigger
options and value events:
toggle.param.trigger('options', 'value')
(Event(what='value', name='options', obj=CheckButtonGroup(options=['A', 'B']), cls=CheckButtonGroup(options=['A', 'B']), old=['A', 'B'], new=['A', 'B'], type='triggered'), Event(what='value', name='value', obj=CheckButtonGroup(options=['A', 'B']), cls=CheckButtonGroup(options=['A', 'B']), old=[], new=[], type='triggered'))
We can also override the initial parameters using the update
method:
options = ['A','B','C','D']
toggle.param.update(options=dict(zip(options,options)), value=['D'])
(Event(what='value', name='options', obj=CheckButtonGroup(options={'A': 'A', 'B': 'B', ...}, value=['D']), cls=CheckButtonGroup(options={'A': 'A', 'B': 'B', ...}, value=['D']), old=['A', 'B'], new={'A': 'A', 'B': 'B', 'C': 'C', 'D': 'D'}, type='set'), Event(what='value', name='value', obj=CheckButtonGroup(options={'A': 'A', 'B': 'B', ...}, value=['D']), cls=CheckButtonGroup(options={'A': 'A', 'B': 'B', ...}, value=['D']), old=[], new=['D'], type='set'))
Using update
allows us to batch two separate changes (the options and the value) together, which you can see from the print
output resulted into a single invocation of the callback. You could instead have set them separately using the usual parameter-setting syntax toggle.value=['D']; toggle.options=dict(zip(options,options))
, but batching them can be much more efficient for a non-trivial callback like a database query or a complex plot that needs updating.
Now that the widgets are visible, you can toggle the option values and see the selected pane update in response via the callback (if Python is running).
Unlinking#
If for whatever reason we want to stop watching parameter changes we can unsubscribe by passing our watcher
(returned in the watch
call above) to the unwatch
method:
toggle.param.unwatch(watcher)