"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"import panel as pn\n",
"import holoviews as hv\n",
"from holoviews import opts # noqa\n",
"\n",
"pn.extension('katex')\n",
"hv.extension('bokeh')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Exercise 1\n",
"\n",
"In this exercise you will construct a number of Panel components and then lay them out as a non-interactive Panel dashboard."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### The data\n",
"\n",
"Throughout this tutorial we will be working with one core dataset, a collection of earthquakes recorded between 2000-2018 provided by the US Geological Survey (USGS). The data is provided as a Parquet file as part of the tutorial and we will load it using Dask and persist it. We will return to this later; for now we will focus on building a dashboard and you don't know any of the details about the dataset or the Dask or Pandas API."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import dask.dataframe as dd\n",
"\n",
"df = dd.read_parquet('../../data/earthquakes.parq')\n",
"\n",
"df = df[~df.mag.isna()].persist()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### The logo\n",
"\n",
"The first component of the dashboard is an image of the US Geological Survey logo. Start by declaring a pane containing the logo and assign it to the ``logo`` variable. Also set a width to ensure the logo doesn't appear too big."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"logo_url = '../../assets/usgs_logo.png'\n",
"\n",
"## Define a panel component containing the logo\n",
"logo = ...\n",
"\n",
"## Display it\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Solution \n",
"\n",
"```python\n",
"logo = pn.panel(logo_url, width=300) \n",
"```\n",
"\n",
""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Richter scale equation\n",
"\n",
"Next we will create a component to display the equation for the Richter scale definition. Declare the appropriate pane and assign it to the ``equation`` variable."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"equation_string = '$M_L = log_{10}A - log_{10} A_0(\\delta)$'\n",
"\n",
"## Define a panel component containing the equation (Hint: Use the LaTeX pane)\n",
"equation = ...\n",
"\n",
"## Display it\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Solution \n",
"\n",
"```python\n",
"logo = pn.pane.LaTeX(equation_string) \n",
"```\n",
"\n",
""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### List the strongest earthquakes"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"year = 2000\n",
"\n",
"def strongest_earthquakes_fn(year):\n",
" year_df = df[(df.time.dt.year == year) & (df.mag > 7)].compute()\n",
" return year_df.sort_values('mag', ascending=False).iloc[:5][['time', 'place', 'mag']].reset_index(drop=True)\n",
"\n",
"## Create a panel component by calling the function with a particular year\n",
"strongest_earthquakes = ...\n",
"\n",
"## Display it\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Solution \n",
"\n",
"```python\n",
"strongest_earthquakes = pn.panel(strongest_earthquakes_fn(year)) \n",
"```\n",
"\n",
""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Display an iframe of a Google Map"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Hint \n",
"\n",
"An iframe is an HTML tag.\n",
"\n",
""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def gmap_fn(year):\n",
" yearly_df = df[(df.time.dt.year == year)].compute()\n",
" index = np.argmax(yearly_df.mag.values)\n",
" strongest = yearly_df.iloc[index]\n",
" lon, lat = strongest.longitude, strongest.latitude\n",
" return \"\"\"\n",
" \n",
" \"\"\".format(lat=lat, lon=lon)\n",
"\n",
"## Create a panel component by calling the function with a particular year and wrapping it in the appropriate pane\n",
"gmap = ...\n",
"\n",
"## Display it\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### A plot [challenge]\n",
"\n",
"If you are up to it, create a custom plot from the ``year_df`` dataframe defined below, create a Panel component, and assign it to the ``plot`` variable.\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Info \n",
"\n",
"If you are using matplotlib pyplot you can get the figure with ``plot = plt.gcf()`` and the close it with ``plot.close()``\n",
"\n",
""
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"year_df = df[df.time.dt.year == year].compute()\n",
"\n",
"## Create a plot and assign it to the plot variable\n",
"plot = ...\n",
"\n",
"## Display it\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Solution \n",
"\n",
"This example solution uses concepts covered in the plotting section of the tutorial:\n",
"\n",
"```python\n",
"plot = hv.Violin(year_df, 'type', 'mag').opts(ylim=(0, None), xrotation=90)\n",
"```\n",
"\n",
""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Composing the dashboard\n",
"\n",
"Now that we have defined all the different components, it is time to lay them out into the overall dashboard.\n",
"\n",
"Arrange the following components into a dashboard using the ``Row`` and ``Column`` panels:\n",
"\n",
"* ``logo``\n",
"* ``equation``\n",
"* ``strongest_earthquakes``\n",
"* ``gmap``\n",
"* ``plot`` (optional)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Solution \n",
"\n",
"```python\n",
"year = 2000\n",
"\n",
"logo = pn.panel(logo_url, width=200)\n",
"equation = pn.pane.LaTeX(equation_string)\n",
"strongest_earthquakes = strongest_earthquakes_fn(year)\n",
"gmap = pn.pane.HTML(gmap_fn(year), height=300, width=300)\n",
"plot = hv.Violin(year_df, 'type', ('mag', 'Magnitude')).opts(ylim=(0, None))\n",
"\n",
"title = pn.panel('# Strongest Earthquakes in the Year %d' % year, width=400)\n",
"header = pn.Row(title, pn.layout.HSpacer(), logo)\n",
"\n",
"body = pn.Row(\n",
" pn.Column('### Strongest Earthquakes', strongest_earthquakes),\n",
" pn.Column('### Description', gmap),\n",
" pn.Column('### Magnitude Plot', plot)\n",
")\n",
"\n",
"pn.Column(header, body)\n",
"```\n",
" \n",
""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Exercise 2\n",
"\n",
"Having learned about how to create interactive components we can now make the formerly static dashboard interactive by adding a widget to control the year."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### The widget\n",
"\n",
"Declare an ``IntSlider`` widget with a start value of 2000, end value of 2018, and current value of 2000."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Solution \n",
"\n",
"```python\n",
"year_slider = pn.widgets.IntSlider(name='Year', start=2000, end=2018, value=2000)\n",
"year_slider\n",
"```\n",
"\n",
""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"#### The title\n",
"\n",
"Write a function with dependencies which returns a title for the given year, e.g. \"Strongest Earthquakes in the Year 2000\":"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Solution \n",
"\n",
"```python\n",
"@pn.depends(year_slider.param.value)\n",
"def title_fn(year):\n",
" return '## Strongest Earthquakes in the Year {year}'.format(year=year)\n",
"```\n",
"\n",
""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### The table and map\n",
"\n",
"Add dependencies to the functions below so the output updates whenever the slider value changes:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"\n",
"def strongest_earthquakes_fn(year): # noqa: redefined on purpose\n",
" year_df = df[df.time.dt.year == year].compute()\n",
" return year_df.sort_values('mag', ascending=False).iloc[:5][['time', 'place', 'mag']].reset_index(drop=True)\n",
"\n",
"\n",
"def gmap_fn(year): # noqa: redefined on purpose\n",
" yearly_df = df[(df.time.dt.year == year)].compute()\n",
" index = np.argmax(yearly_df.mag.values)\n",
" strongest = yearly_df.iloc[index]\n",
" lon, lat = strongest.longitude, strongest.latitude\n",
" return pn.pane.HTML(\"\"\"\n",
" \n",
" \"\"\".format(lat=lat, lon=lon), height=300, width=300)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### The Plot [challenge]\n",
"\n",
"In case you defined a plot above make the plot dynamic by wrapping it in a function which depends on the year."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Solution \n",
"\n",
"```python\n",
"@pn.depends(year_slider.param.value)\n",
"def plot_fn(year)\n",
" year_df = df[df.time.dt.year == year].compute()\n",
" return hv.Violin(year_df, 'type', ('mag', 'Magnitude')).opts(xrotation=90)\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Composing the dashboard\n",
"\n",
"Now that we have created new dynamic components let us lay them out once again to create a fully interactive dashboard. Ensure that you include the widget so you can actually control the year."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Solution \n",
"\n",
"```python\n",
"year_slider = pn.widgets.IntSlider(name='Year', start=2000, end=2018, value=2000)\n",
"\n",
"@pn.depends(year_slider.param.value)\n",
"def title_fn(year):\n",
" return '## Strongest Earthquakes in the Year {year}'.format(year=year)\n",
" \n",
"@pn.depends(year_slider.param.value)\n",
"def strongest_earthquakes_fn(year):\n",
" year_df = df[df.time.dt.year == year].compute()\n",
" return year_df.sort_values('mag', ascending=False).iloc[:5][['time', 'place', 'mag']].reset_index(drop=True)\n",
"\n",
"@pn.depends(year_slider.param.value)\n",
"def gmap_fn(year):\n",
" yearly_df = df[(df.time.dt.year == year)].compute()\n",
" index = np.argmax(yearly_df.mag.values)\n",
" strongest = yearly_df.iloc[index]\n",
" lon, lat = strongest.longitude, strongest.latitude\n",
" return pn.pane.HTML(\"\"\"\n",
" \n",
" \"\"\".format(lat=lat, lon=lon), height=300, width=300)\n",
"\n",
"@pn.depends(year_slider.param.value)\n",
"def plot_fn(year):\n",
" year_df = df[df.time.dt.year == year].compute()\n",
" return hv.Violin(year_df, 'type', ('mag', 'Magnitude'))\n",
" \n",
"logo = pn.panel(logo_url, width=200)\n",
"equation = pn.pane.LaTeX(equation_string)\n",
"\n",
"header = pn.Row(title_fn, pn.layout.HSpacer(), logo)\n",
"\n",
"body = pn.Row(\n",
" \n",
" pn.Column('### Strongest Earthquakes', strongest_earthquakes_fn),\n",
" pn.Column('### Map', gmap_fn),\n",
" pn.Column('### Magnitude Plot', plot_fn)\n",
")\n",
"\n",
"pn.Column(header, year_slider, body)\n",
"```\n",
"\n",
""
]
}
],
"metadata": {
"language_info": {
"name": "python",
"pygments_lexer": "ipython3"
}
},
"nbformat": 4,
"nbformat_minor": 4
}