-
-
Notifications
You must be signed in to change notification settings - Fork 532
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
cbd1491
commit d0a32d5
Showing
1 changed file
with
310 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,310 @@ | ||
{ | ||
"cells": [ | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"# Links parameters in panel" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"In the [param user guide](Param.ipynb), we have seen how parameterized classes are transformed to user interface at free cost. However in certain cases, we need more customisation over widgets automatically generated. Indeed widgets created with `widgets` modules exposed more attributes and allow more possibilities.\n", | ||
"\n", | ||
"In this notebook we will see how to links custom panels between them:\n", | ||
"\n", | ||
" - links between `Parameters` of `Parameterized` classes (most of panel inherit from `param.Parameterized`) with `link` method\n", | ||
" - links between `Parameters` and custom functions with `watch` method" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"import param\n", | ||
"import panel as pn\n", | ||
"pn.extension()" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"## Links between `params` of `Parameterized` classes" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"In this example we will link a markdown panel to a text input widget" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"mkdown_pane = pn.pane.Markdown('Markdown display')\n", | ||
"mkdown_pane" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"widget_text = pn.widgets.TextInput(value=mkdown_pane.object)\n", | ||
"widget_text" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"We verify both objects we want to link are `param.Parameterized` objects" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"print(isinstance(mkdown_pane, param.Parameterized), isinstance(widget_text, param.Parameterized))" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"Link of widget `value` attribute to the `object` attribute of the panel" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"widget_text.link(mkdown_pane, value = 'object')\n", | ||
"widget_text.value = 'New text' #above displays should reflect change" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"Accessing to available parameters using `params` method" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"widget_text.params()" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"## Link `params` with `watch` method " | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"Previously we have seen how to link one to one parameters between to Parameterized classes. However value between `parameters` must be the same. Sometimes parameters are linked but values differ. In this case we will add a `watcher`. A `watcher` is a function called when the attribute is changed." | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"Let's see how to link the disabled property of a `TextInput` widget to a `ToggleButton`" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"widget text creation" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"widget_text = pn.widgets.TextInput(value='text', disabled=True)\n", | ||
"widget_text" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"toggle button creation" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"widget_toggle = pn.widgets.Toggle(active=False, name='Click to enable text')\n", | ||
"widget_toggle" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"We could link toggle `active` parameter to the text widget `disabled` parameter with:\n", | ||
"```python\n", | ||
"widget_toggle.link(widget_text, active = 'disabled')\n", | ||
"```\n", | ||
"However we want the opposite behavior, when toggle is `active=True` text input is enabled (`disabled=False`)" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"To do it we use the `watch` method of the class `parameters` to connect the toggle button to the text input" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"watcher = widget_toggle.param.watch(lambda change: setattr(widget_text, 'disabled', not change.new), 'active' )" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"Now cliking on the toggle button enable or disable the text input" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"`param.watch` return a reference to the watcher which can be used to remove it." | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"widget_toggle.param.unwatch(watcher)" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"the two widgets are not linked anymore" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"## More advance usage" | ||
] | ||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"metadata": {}, | ||
"source": [ | ||
"Using the `Sine` example of the [param user guide](Param.ipynb), we will create sliders with a custom step value. Indeed the default step of sliders automatically generated is 0.1 and is not always adapted." | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"import numpy as np\n", | ||
"\n", | ||
"class Sine(param.Parameterized):\n", | ||
"\n", | ||
" phase = param.Number(default=0, bounds=(0, np.pi))\n", | ||
"\n", | ||
" frequency = param.Number(default=1, bounds=(0.1, 2))\n", | ||
" \n", | ||
" \n", | ||
" def widgets(self):\n", | ||
" phase_params = self.params()['phase']\n", | ||
" frequency_params = self.params()['frequency']\n", | ||
" phase_slider = pn.widgets.FloatSlider(value=phase_params.default,\n", | ||
" start=phase_params.bounds[0],\n", | ||
" end=phase_params.bounds[1], step=1e-2)\n", | ||
" frequency_slider = pn.widgets.FloatSlider(value=frequency_params.default,\n", | ||
" start=frequency_params.bounds[0],\n", | ||
" end=frequency_params.bounds[1], step=1e-2)\n", | ||
" phase_slider.link(self, value='phase')\n", | ||
" frequency_slider.link(self, value='frequency')\n", | ||
" return pn.widgets.WidgetBox(frequency_slider, phase_slider)\n", | ||
"\n", | ||
" @param.depends('phase', 'frequency')\n", | ||
" def view(self):\n", | ||
" y = np.sin(np.linspace(0, np.pi*3, 40)*self.frequency+self.phase)\n", | ||
" y = ((y-y.min())/y.ptp())*20\n", | ||
" array = np.array([list((' '*(int(round(d))-1) + '*').ljust(20)) for d in y])\n", | ||
" return pn.pane.Str('\\n'.join([''.join(r) for r in array.T]), height=325, width=500)\n", | ||
"\n", | ||
"sine = Sine(name='ASCII Sine Wave')\n", | ||
"pn.panel(pn.Row(sine.widgets(), sine.view))" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"execution_count": null, | ||
"metadata": {}, | ||
"outputs": [], | ||
"source": [] | ||
} | ||
], | ||
"metadata": { | ||
"kernelspec": { | ||
"display_name": "Python 3", | ||
"language": "python", | ||
"name": "python3" | ||
}, | ||
"language_info": { | ||
"codemirror_mode": { | ||
"name": "ipython", | ||
"version": 3 | ||
}, | ||
"file_extension": ".py", | ||
"mimetype": "text/x-python", | ||
"name": "python", | ||
"nbconvert_exporter": "python", | ||
"pygments_lexer": "ipython3", | ||
"version": "3.6.4" | ||
} | ||
}, | ||
"nbformat": 4, | ||
"nbformat_minor": 2 | ||
} |