I’ve thoroughly documented the following file, and have added some questions for parts that I don’t understand. Have I made any mistakes?
In particular, does anyone know why @param.depends('_start_date.value', '_end_date.value', 'percent', watch=True)
only works for the parameter percent
and if there is anyway to make it work for widgets?
"""
Alluding to the React paradigm of "lifting state" this file demonstrates how to pass a widget into
a child class that will then respond to change in the parent widgets
"""
import panel as pn
import param
class Child(param.Parameterized):
"""The child class will only keep track of percentile
But should respond to changes in the parent classes start/end dates
"""
percent = param.Number()
def __init__(self, start_date_widget, end_date_widet):
"""Call super to initialize percent as a parameter and store start and end date values"""
super().__init__()
self._start_date = start_date_widget
self._end_date = end_date_widet
# @param.depends('_start_date.value', '_end_date.value', 'percent', watch=True)
# This is interesting and I don't really understand it...
# although below, when start_date and end_date change, the view updates, for this function,
# using the above depends decorator only causes an update for percent. Changes to _start_date
# and _end_date have no effect
# @pn.depends('_start_date.value', '_end_date.value', 'percent') has absolutely no effect
def side_effect(self):
"""Functions that are "side effects" as in they are not directly rendered by param must
include @param.depends(..., watch=True) in order to update when the parameters change
"""
print(f'Values changed: {self._start_date.value}, {self._end_date.value}, {self.percent}')
@param.depends('_start_date.value', '_end_date.value', 'percent')
def view(self):
"""
@param.depends(...) ONLY generates "a hint to Panel and other Param-based libraries
(e.g. HoloViews) that the method should be re-evaluated when a parameter changes". The
important thing to note here is that the function view must be nested in a panel object w/o
being called in order to update.
"""
return pn.Column(
# pn.Param(...) takes in a parameter and renders a widget.
# pn.Param(self.percent) doesn't work
# pn.Param(self.param.percent) DOES work.
pn.Param(self.param.percent),
# notice we use "self.percent", but "self._start_date.value".
# perent is a param, and start date is a widget. They are different types!
pn.panel(f'## {self.percent}, {self._start_date.value}, {self._end_date.value}'),
)
# Here we create our "super class" widgets
start_date = pn.widgets.DatePicker()
end_date = pn.widgets.DatePicker()
# widgets are passed into child class
child = Child(start_date, end_date)
# widgets are rendered. Note that child.view is not called, the function is passed indicating to
# panel that it should be re run every time the hinted parameters in @param.depends() are changed
pn.Row(start_date, end_date, child.view).servable()
# this doesn't work, because child.view is CALLED:
"""" pn.Row(start_date, end_date, child.view()).servable() """