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:
Markdownpane to display the possible optionsMarkdownpane to display the selected optionsToggleGroupwidget 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)