Glaciers#

import numpy as np
import pandas as pd
import holoviews as hv
import panel as pn

from colorcet import bmy

pn.extension('tabulator', template='fast')
import hvplot.pandas

Create intro#

instruction = pn.pane.Markdown("""
This dashboard visualizes all global glaciers and allows exploring the relationships
between their locations and variables such as their elevation, temperature and annual
precipitation.<br><br>Box- or lasso-select on each plot to subselect and hit the 
"Clear selection" button to reset. See the notebook source code for how to build apps
like this!""", width=600)

panel_logo = pn.pane.PNG(
    'https://panel.holoviz.org/_static/logo_stacked.png',
    link_url='https://panel.holoviz.org', height=95, align='center'
)

oggm_logo = pn.pane.PNG(
    'https://raw.githubusercontent.com/OGGM/oggm/master/docs/_static/logos/oggm_s_alpha.png',
    link_url='https://oggm.org/', height=100, align='center'
)

intro = pn.Row(
    oggm_logo,
    instruction,
    pn.layout.HSpacer(),
    panel_logo,
    sizing_mode='stretch_width'
)

intro

Load and cache data#

from holoviews.element.tiles import lon_lat_to_easting_northing

@pn.cache
def load_data():
    df = pd.read_parquet('https://datasets.holoviz.org/oggm_glaciers/v1/oggm_glaciers.parq')
    df['latdeg'] = df.cenlat
    df['x'], df['y'] = lon_lat_to_easting_northing(df.cenlon, df.cenlat)
    return df

df = load_data()

df.tail()
rgi_id cenlon cenlat area_km2 glacier_type terminus_type mean_elev max_elev min_elev avg_temp_at_mean_elev avg_prcp latdeg x y
213745 RGI60-18.03533 170.354 -43.4215 0.189 Glacier Land-terminating 1704.858276 2102.0 1231.0 2.992555 6277.991881 -43.4215 1.896372e+07 -5.376350e+06
213746 RGI60-18.03534 170.349 -43.4550 0.040 Glacier Land-terminating 2105.564209 2261.0 1906.0 0.502311 6274.274146 -43.4550 1.896316e+07 -5.381486e+06
213747 RGI60-18.03535 170.351 -43.4400 0.184 Glacier Land-terminating 1999.645874 2270.0 1693.0 1.187901 6274.274146 -43.4400 1.896339e+07 -5.379186e+06
213748 RGI60-18.03536 170.364 -43.4106 0.111 Glacier Land-terminating 1812.489014 1943.0 1597.0 2.392771 6154.064456 -43.4106 1.896483e+07 -5.374680e+06
213749 RGI60-18.03537 170.323 -43.3829 0.085 Glacier Land-terminating 1887.771484 1991.0 1785.0 1.351039 6890.991816 -43.3829 1.896027e+07 -5.370436e+06

Set up linked selections#

ls = hv.link_selections.instance()

def clear_selections(event):
    ls.selection_expr = None

clear_button = pn.widgets.Button(name='Clear selection', align='center')

clear_button.param.watch(clear_selections, 'clicks');

total_area = df.area_km2.sum()

def count(data):
    selected_area  = np.sum(data['area_km2'])
    selected_percentage = selected_area / total_area * 100
    return f'## Glaciers selected: {len(data)} | Area: {selected_area:.0f} km² ({selected_percentage:.1f}%)</font>'

pn.Row(
    pn.pane.Markdown(pn.bind(count, ls.selection_param(df)), align='center', width=600),
    clear_button
).servable(area='header', title='OGGM Glaciers')

Create plots#

geo = df.hvplot.points(
    'x', 'y', rasterize=True, tools=['hover'], tiles='ESRI', cmap=bmy, logz=True, colorbar=True,
    xaxis=None, yaxis=False, ylim=(-7452837.583633271, 6349198.00989753), min_height=400, responsive=True
).opts('Tiles', alpha=0.8)

scatter = df.hvplot.scatter(
    'avg_prcp', 'mean_elev', rasterize=True, fontscale=1.2, grid=True,
    xlabel='Avg. Precipitation', ylabel='Elevation', responsive=True, min_height=400
)

temp = df.hvplot.hist(
    'avg_temp_at_mean_elev', fontscale=1.2, responsive=True, min_height=350, fill_color='#85c1e9'
)

precipitation = df.hvplot.hist(
    'avg_prcp', fontscale=1.2, responsive=True, min_height=350, fill_color='#f1948a'
)

plots = pn.pane.HoloViews(ls(geo + scatter + temp + precipitation).cols(2).opts(sizing_mode='stretch_both'))
plots

Dashboard content#

pn.Column(intro, plots, sizing_mode='stretch_both').servable();