\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import panel as pn\n",
"from load_data import *\n",
"\n",
"pn.extension()\n",
"df = load_data()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"df.head()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In the previous section we learned the very basics of working with Panel.\n",
"Specifically we looked at the different types of components, how to update them\n",
"and how to serve a Panel application or dashboard. However to start building\n",
"actual apps with Panel we need to be able to add interactivity by linking\n",
"different components together. In this section we will learn how to link widgets\n",
"to outputs to start building some simple interactive applications.\n",
"\n",
"In this section we will once again make use of the wave heights dataset we\n",
"loaded previously and compute some statistics:\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Widgets and reactive components\n",
"\n",
"`pn.interact` constructs widgets automatically that can then be reconfigured,\n",
"but if you want more control, you'll want to instantiate widgets explicitly. A\n",
"widget is an input control that allows a user to change a `value` using some\n",
"graphical UI. A simple example is a `RangeSlider`:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"wvht_filter = pn.widgets.RangeSlider(\n",
" name=\"Wave Heights\", start=0, end=df[\"wvht\"].max()\n",
")\n",
"\n",
"wvht_filter"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Here the widget `value` is a [Parameter](https://param.pyviz.org) that is set to\n",
"a tuple of the selected upper and lower bound. Parameters are an extended type\n",
"of Python attribute that declare their type, range, etc. so that other code can\n",
"interact with them in a consistent way. When we change the range using the\n",
"widget the `value` parameter updates, and vice versa if you change the value\n",
"parameter manually:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"wvht_filter.value"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Callbacks\n",
"\n",
"The `depends` API is still a very high level way of declaring interactive\n",
"components. Panel also supports the more low-level approach of writing callbacks\n",
"in response to changes in some parameter, e.g. the `value` of a widget. All\n",
"parameters can be watched using the `.param.watch` API, which will call the\n",
"provided callback with an event object containing the old and new value of the\n",
"widget.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now that it is loaded we will create a slider which we will eventually use to\n",
"select the row of the dataframe that we want to display:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"row_slider = pn.widgets.IntSlider(value=0, start=0, end=len(df) - 1)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Next we create a Pane to display the current row of the dataframe with times\n",
"formatted nicely:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"row_pane = pn.panel(df.loc[row_slider.value])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now that we have defined both the widget and the object we want to update we can\n",
"declare a callback to link the two. As we learned in the previous section\n",
"assigning a new value to the `object` of a pane will update the display. In the\n",
"callback we select the row of the dataframe and then assign it to the\n",
"`pane.object`.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def df_callback(event):\n",
" row_pane.object = df.loc[event.new]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Lastly we actually have to register this callback. To do so we provide the\n",
"callback and the parameter we want to trigger the event on the slider's\n",
"`.param.watch` method:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"row_slider.param.watch(df_callback, \"value\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now that everything is connected up we can put both the widget and the pane in a\n",
"panel and display them:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"pn.Column(row_slider, row_pane, width=400)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"As you can see, this process is slightly more laborious than `pn.interact` or\n",
"even the `pn.depends` approach, but doing it in this way should help you see how\n",
"everything fits together and can be useful to more precisely control callbacks\n",
"that update particular parameters or the contents of a larger layout.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Moving onwards\n",
"\n",
"Now that we have learned to link parameters between displayed objects and build\n",
"interactive components, we can start building actual apps and dashboards. Before\n",
"we move on to plotting and visualization let us quickly use what we have learned\n",
"by adding interactivity to\n",
"[the dashboard we built in the previous exercise](./exercises/Building_a_Dashboard.ipynb).\n"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python [conda env:root] *",
"language": "python",
"name": "conda-root-py"
},
"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.9.6"
}
},
"nbformat": 4,
"nbformat_minor": 4
}