Param#
Open this notebook in Jupyterlite | Download this notebook from GitHub (right-click to download).
import panel as pn
import param
pn.extension()
The panel.Param pane allows customizing the widgets, layout and style of the parameters of a param.Parameterized Class.
Parameters:#
For details on other options for customizing the component see the layout and styling how-to guides.
The basic parameters are:
object(param.Parameterized): Aparam.Parameterizedinstance or class, or its.paramattribute.parameters(List[str]): A list identifying the subset of parameters to include in the pane.widgets(dict): A dictionary mapping parameter names to the widget type to use, or to a dictionary of widget options including thetype.
The more advanced parameters which give you more control are:
default_layout(ListPanel, default=Column): The layout class to display the widgets in, e.g.pn.Column,pn.Rowor a custompn.GridBoxsubclass.display_threshold(float, default=0): Parameters with precedence below this value are not displayed.expand(bool, default=False): Whether parameterized subobjects are expanded or collapsed on instantiation.expand_button(bool): Whether to add buttons to expand and collapse sub-objects.expand_layout(ListPanel, default=Column): Layout to expand sub-objects into.hide_constant(bool, default=False): Whether to hide widgets of constant parameters.initializer(callable): Function called on initialization, usually to update the default parameter values of the underlying object.name(str): The title of the pane.show_labels(bool, default=True): Whether to show labels for each widget.show_name(bool, default=True): Whether to show the name of the Parameterized object.sort(bool or callable, default=False): Whether to sort the widgets alphabetically by label, or a function used to sort the parameters.
Model building#
Let’s build a model of a cycling Athlete and her PowerCurve.
The PowerCurve is a recording of her maximum power output in Watt per kg for fixed durations of time.
import datetime
import pandas as pd
import hvplot.pandas
DATE_BOUNDS = (datetime.date(1900, 1, 1), datetime.datetime.now().date())
class PowerCurve(param.Parameterized):
ten_sec = param.Number(default=1079)
ten_sec_date = param.Date(default=datetime.date(2018, 8, 21), bounds=DATE_BOUNDS)
one_min = param.Number(default=684)
one_min_date = param.Date(default=datetime.date(2017, 8, 31), bounds=DATE_BOUNDS)
ten_min = param.Number(default=419)
ten_min_date = param.Date(default=datetime.date(2017, 9, 22), bounds=DATE_BOUNDS)
twenty_min = param.Number(default=398)
twenty_min_date = param.Date(default=datetime.date(2017, 9, 22), bounds=DATE_BOUNDS)
one_hour = param.Number(default=319)
one_hour_date = param.Date(default=datetime.date(2017, 8, 6), bounds=DATE_BOUNDS)
@param.depends("ten_sec", "one_min", "ten_min", "twenty_min", "one_hour")
def plot(self):
data = {
"duration": [10 / 60, 1, 10, 20, 60],
"power": [self.ten_sec, self.one_min, self.ten_min, self.twenty_min, self.one_hour],
}
dataframe = pd.DataFrame(data)
line_plot = dataframe.hvplot.line(
x="duration", y="power", line_color="#007BFF", line_width=3, responsive=True,
)
scatter_plot = dataframe.hvplot.scatter(
x="duration", y="power", marker="circle", size=60, color="#007BFF", responsive=True
)
fig = line_plot * scatter_plot
gridstyle = {"grid_line_color": "black", "grid_line_width": 0.1}
fig = fig.opts(
height=400,
toolbar=None,
yticks=list(range(0, 1600, 200)),
ylim=(0, 1500),
gridstyle=gridstyle,
show_grid=True,
)
return fig
class Athlete(param.Parameterized):
name_ = param.String(default="P.A. Nelson")
birthday = param.Date(default=datetime.date(1976, 9, 17), bounds=DATE_BOUNDS)
weight = param.Number(default=82, bounds=(20,300))
power_curve = param.ClassSelector(class_=PowerCurve, default=PowerCurve())
athlete = Athlete()
The pn.Param pane can be used to view and edit the models.
Try clicking the ... button. This will expand the PowerCurve if running in an interactive notebook.
pn.Param(athlete)
The default Birthday and Weight widgets are not the most convenient to use, so let’s change them to a DatePicker and a LiteralInput:
pn.Param(athlete, widgets={"birthday": pn.widgets.DatePicker, "weight": pn.widgets.LiteralInput})
Let’s expand the power curve by default:
pn.Param(
athlete,
widgets={
"birthday": pn.widgets.DatePicker,
"weight": pn.widgets.LiteralInput
}, expand=True)
Now let’s display only the Name and Birthday, laid out in a Row:
pn.Param(
athlete,
widgets={"birthday": pn.widgets.DatePicker},
parameters=["name_", "birthday"],
show_name=False,
default_layout=pn.Row,
width=400
)
Let’s customize the view of the Athlete some more:
athlete_view = pn.Param(
athlete,
widgets={
"birthday": pn.widgets.DatePicker,
"weight": {"type": pn.widgets.LiteralInput, "width": 100}
},
parameters=["name_", "birthday", "weight"],
show_name=False,
default_layout=pn.Row,
width=600
)
athlete_view
Let’s take a look at the PowerCurve:
pn.Param(athlete.power_curve)
The PowerCurve layout is not that tidy. Let’s change the layout to two columns. Since default_layout expects a layout class, we create a GridBox subclass with ncols=2:
def new_class(cls, **kwargs):
"Creates a new class which overrides parameter defaults."
return type(type(cls).__name__, (cls,), kwargs)
power_curve_columns_view = pn.Param(
athlete.power_curve,
default_layout=new_class(pn.GridBox, ncols=2),
show_name=False,
widgets = {
"ten_sec_date": pn.widgets.DatePicker,
"one_min_date": pn.widgets.DatePicker,
"ten_min_date": pn.widgets.DatePicker,
"twenty_min_date": pn.widgets.DatePicker,
"one_hour_date": pn.widgets.DatePicker
}
)
power_curve_columns_view
Let’s put a plot of the PowerCurve in the mix:
power_curve_view = pn.Row(
power_curve_columns_view,
athlete.power_curve.plot,
sizing_mode='stretch_width'
)
power_curve_view
And finally, let’s put things together:
pn.Column(
pn.pane.Markdown("### Athlete"),
athlete_view,
pn.pane.Markdown("#### Power Curve"),
power_curve_view,
sizing_mode='stretch_width'
)
Sorting widgets#
By default the widgets are ordered by the parameter precedence and declaration order. Set sort=True to sort them alphabetically by label instead, or pass a function to define a custom order:
pn.Param(athlete, parameters=['name_', 'birthday', 'weight'], sort=True, show_name=False)
Disabling continuous updates for slider widgets#
When a function takes a long time to run and depends on a parameter, realtime feedback can be a burden instead of being helpful.
Therefore if a slider widget is used for a parameter and you have a function which takes long time to calculate, you can set throttled=True in the widget specification for that parameter. The function will then only run once the mouse button is released.
An example can be seen below where two parameters are connected to two sliders, one with and one without throttled enabled:
class A(param.Parameterized):
without_throttled_enabled = param.Range(
default=(100, 250),
bounds=(0, 250),
)
with_throttled_enabled = param.Range(
default=(100, 250),
bounds=(0, 250),
)
def __init__(self, **params):
super().__init__(**params)
widgets = {
"without_throttled_enabled": pn.widgets.IntRangeSlider,
"with_throttled_enabled": {
"type": pn.widgets.IntRangeSlider,
"throttled": True,
},
}
self.controls = pn.Param(self, widgets=widgets)
def calculation(self):
return self.without_throttled_enabled, self.with_throttled_enabled
a = A()
pn.Column(a.controls, a.calculation)
Open this notebook in Jupyterlite | Download this notebook from GitHub (right-click to download).