Building a Dashboard#
import pathlib
import numpy as np
import pandas as pd
import panel as pn
pn.extension('katex')
import hvplot.pandas # noqa
Non-interactive components#
In this exercise you will first construct a number of Panel components and then lay them out as a non-interactive Panel dashboard, using the usual earthquakes dataset.
%%time
df = pd.read_parquet(pathlib.Path('../../data/earthquakes-projected.parq'))
columns = ['mag', 'depth', 'latitude', 'longitude', 'place', 'type']
df = df[columns]
most_severe = df[df.mag >= 7]
CPU times: user 2.13 s, sys: 424 ms, total: 2.56 s
Wall time: 1.73 s
The logo#
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.
logo_url = pathlib.Path('../../assets/usgs_logo.png')
## Define a panel component containing the logo
logo = ...
## Display it
logo = pn.panel(logo_url, width=300)
logo
Richter scale equation#
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.
equation_string = '$M_L = log_{10}A - log_{10} A_0(\delta)$'
## Define a panel component containing the equation (Hint: Use the LaTeX pane)
equation = ...
## Display it
equation = pn.pane.LaTeX(equation_string)
equation
List the strongest earthquakes#
year = 2000
def strongest_earthquakes_fn(year):
year_df = df[(df.index.year == year) & (df.mag > 7)]
return year_df.sort_values('mag', ascending=False).iloc[:5][['place', 'mag']].reset_index()
## Create a panel component by calling the function with a particular year
strongest_earthquakes = ...
## Display it
strongest_earthquakes = pn.panel(strongest_earthquakes_fn(year))
strongest_earthquakes
Display an iframe of a Google Map#
Hint
An iframe is an HTML tag.
def gmap_fn(year):
yearly_df = df[(df.index.year == year)]
index = np.argmax(yearly_df.mag.fillna(0).values)
strongest = yearly_df.iloc[index]
lon, lat = strongest.longitude, strongest.latitude
return """
<iframe width="300" height="300" src="https://maps.google.com/maps?q={lat},{lon}&z=6&output=embed"
frameborder="0" scrolling="no" marginheight="0" marginwidth="0"></iframe>
""".format(lat=lat, lon=lon)
## Create a panel component by calling the function with a particular year and wrapping it in the appropriate pane
gmap = ...
## Display it
This example solution displays the map for the year
(by default is the year 2000):
gmap = pn.panel(gmap_fn(year))
gmap
A plot#
Here we create a plot from the year_df
dataframe with .hvplot
, create a Panel component, and assign it to the plot
variable. We can visualize the distribution of earthquake magnitudes over the year by plotting the time
variable on the x
-axis and the mag
variable on the y
-axis.
year_df = df[df.index.year == year]
## Create a plot and assign it to the plot variable
plot = ...
## Display it
This example solution uses concepts covered in the plotting section of the tutorial:
plot = year_df.hvplot.line(x='time', y='mag')
plot
Composing the static dashboard#
Now that we have defined all the different components, it is time to lay them out into the overall dashboard.
Arrange the following components into a dashboard using the Row
and Column
panels:
logo
equation
strongest_earthquakes
gmap
plot
Hint
Remember that you can nest panel Row
and Column
layouts and use HSpacer
and VSpacer
objects to adjust spacing as necessary.
# Static Dashboard combining all the elements above.
year = 2000
logo = pn.panel(logo_url, width=200)
equation = pn.pane.LaTeX(equation_string)
strongest_earthquakes = strongest_earthquakes_fn(year)
gmap = pn.pane.HTML(gmap_fn(year), height=300, width=300)
year_df = df[(df.index.year == year) & (df.mag > 7)]
plot = year_df.hvplot.line(x='time', y='mag')
title = pn.panel('# Strongest Earthquakes in the Year %d' % year, width=400)
header = pn.Row(title, pn.layout.HSpacer(), logo)
body_row1 = pn.Row(
pn.Column('### Richter scale definition', equation, '### Strongest Earthquake', gmap),
pn.Column('### Strongest Earthquakes', strongest_earthquakes),
)
pn.Column(header, pn.Column(body_row1,pn.Column('### Magnitude Plot', plot)))
A dashboard with interactive widgets#
Having learned about how to create interactive components, we can now integrate them into dashboards. Here is one of the interactive plots from the last exercise:
depth_slider = pn.widgets.FloatSlider(name='Minimum depth', start=0, end=700, value=350)
dfi = pn.rx(most_severe)
depth_filtered = dfi[dfi['depth'] < depth_slider]
depth_filtered_plot = depth_filtered.hvplot(y='mag', kind='scatter', color='red', marker='x')
#depth_filtered_plot
Have a look at this object to remind you what it represents.
Adding a title and description#
Using the following markdown description of this plot, create a dashboard that integrates it together with an appropriate title, USGS logo and the interactive plot itself.
plot_description_markdown = """
This plot filters earthquakes according to the minimum depth slider and displays the magnitude of the filtered earthquakes over time. Note that only earthquakes with a magnitude `>7` are shown.
"""
title = pn.panel('# Earthquake magnitude as function of depth')
header = pn.Row(title, pn.layout.HSpacer(), logo)
pn.Column(header, pn.panel(plot_description_markdown), depth_filtered_plot)
A dashboard filtering over year#
Now let us make a dashboard driven by a year slider. Create a integer slider that ranges from year 2000 to 2018 called year_slider
.
Hint
You can use a pn.widgets.IntSlider
to select the year.
year_slider = ...
# Display the slider
year_slider = pn.widgets.IntSlider(name='Year', start=2000, end=2018, value=2000)
year_slider
Now let’s look at how the strongest_earthquakes_fn
displays a DataFrame
for the most severe earthquakes in a given year:
year = 2000
most_severe_2000 = most_severe[most_severe.index.year == year]
most_severe_2000.sort_values('mag', ascending=False).iloc[:5].reset_index()[['time', 'place', 'mag']]
time | place | mag | |
---|---|---|---|
0 | 2000-11-16 04:54:56.740000+00:00 | New Ireland region, Papua New Guinea | 8.0 |
1 | 2000-06-04 16:28:26.170000+00:00 | southern Sumatra, Indonesia | 7.9 |
2 | 2000-06-18 14:44:13.310000+00:00 | South Indian Ocean | 7.9 |
3 | 2000-11-16 07:42:16.930000+00:00 | New Ireland region, Papua New Guinea | 7.8 |
4 | 2000-11-17 21:01:56.490000+00:00 | New Britain region, Papua New Guinea | 7.8 |
Using this as an example, create an equivalent table driven by year_slider
, by declaring a filtered interactive DataFrame
called year_rdf
. The handle on the result should be called year_table
.
# Display the table above but with a selectable year using year_slider
year_slider = pn.widgets.IntSlider(name='Year', start=2000, end=2018, value=2000)
rdf = pn.rx(most_severe)
year_rdf = rdf[rdf.index.year == year_slider]
year_table = year_rdf.sort_values('mag', ascending=False).iloc[:5].reset_index()[['time', 'place', 'mag']]
year_table
Now create a scatter plot from year_rdf
with red cross (x
) markers of size 50
called year_scatter
.
Hint
Use a hvplot
call with kind='scatter'
. You also need to set the color
and size
keywords and set size=50
.
# Create an interactive scatter called year_scatter
year_slider = pn.widgets.IntSlider(name='Year', start=2000, end=2018, value=2000)
rdf = pn.rx(most_severe)
year_rdf = rdf[rdf.index.year == year_slider]
year_scatter = year_rdf.mag.hvplot(kind='scatter', color='red', marker='x', size=50)
year_scatter
Putting these components together#
Now using the terminal methods on our interactive dataframe together with a panel Markdown title and the Row
and Column
layout, we can now put year_slider
, year_table
and year_scatter
together into a dashboard.
Hint
Remember that you can use ReactiveExpr
with show_widgets=False
or pass the expression to another Panel component to display it without the widget. A single year_slider
can then be displayed by a pn.Column
.
# Build a dashboard using year_slider, year_table and year_scatter
year_rdf = rdf[rdf.index.year == year_slider]
year_table = year_rdf.sort_values('mag', ascending=False).reset_index().iloc[:5][['time', 'place', 'mag']]
year_scatter = year_rdf.mag.hvplot(kind='scatter', color='red', marker='x', size=50)
pn.Column('# Earthquake magnitudes by year ',
year_slider,
pn.Row(pn.panel(year_table, show_widgets=False),
pn.panel(year_scatter, show_widgets=False))).servable()