Explore nitrate profiles

In [ ]:
print('Starting app')
In [ ]:
import panel as pn
pn.extension()
import holoviews as hv
from holoviews import opts
from holoviews.operation.datashader import datashade
import datashader.reductions as dsr
hv.extension('bokeh')
import geoviews as gv
import cartopy.crs as ccrs
import pandas as pd
import numpy as np
import matplotlib as mpl
import cmocean

from utils.mpl import cmap_to_list

from imports import theme
hv.renderer('bokeh').theme = theme
In [ ]:
dims = dict(
    nitrate=hv.Dimension('nitrate', label='NO₃', unit='µM'),
    depth=hv.Dimension('depth', label='Depth', unit='m', range=(0,300)),
    lon=hv.Dimension('lon', label='Longitude', unit='°E'),
    lat=hv.Dimension('lat', label='Latitude', unit='°N'),
)
In [ ]:
df = pd.read_csv('../data/no3-compilation/database.csv', parse_dates=['date'])
df_single = pd.read_csv('../data/no3-compilation/database-per-stn.csv', parse_dates=['date'])

Map to select points

In [ ]:
loc = gv.feature.land * gv.feature.coastline * gv.Points(df_single, ['lon', 'lat'], [])
loc = loc.relabel('Select a region')
selection = hv.streams.Selection1D(source=loc, index=list(range(len(df_single)))) # set default arg

Datashaded nitrate profiles

In [ ]:
cmap = cmocean.cm.phase
colors = cmap_to_list(cmap, 12)
# mock points for legend. see http://holoviews.org/user_guide/Large_Data.html, # Multidimensional plots
legend_points = hv.Overlay(
    [hv.Scatter([-100, 0], label=str(k+1)).opts(color=v, marker='square', legend_position='right') 
     for k, v in list(enumerate(colors))])
# mock data to append to streamed dataframe to ensure that all months are represented with same color scaling as in mock legend
months = pd.DataFrame(dict(month=np.arange(12)))

def get_ntr(index):
    stations = df_single.iloc[index].station
    return df.loc[df.station.isin(stations)]

ntr_toshade = hv.DynamicMap(
    lambda index: hv.Scatter(
        pd.concat([get_ntr(index), months], sort='False'), 
        'depth', ['nitrate', 'month']
    ), 
    streams=[selection]
)

ntr_shaded = (
    datashade(
        ntr_toshade, 
        aggregator=dsr.count_cat('month'), color_key=cmap,
        dynamic=True, normalization='eq_hist',
        x_sampling=5, y_sampling=0.25
    ) 
    * legend_points
).relabel('All selected profiles').redim(**dims)

Monthly averaged nitrate profiles

In [ ]:
ntr_avg = hv.DynamicMap(
    lambda index: hv.Scatter(
        get_ntr(index).groupby(['month', 'depth']).mean(), 
        'depth', ['nitrate', 'month']
    ).groupby('month').overlay(), 
    streams=[selection]
).relabel('Monthly average').redim(**dims)

Define options

In [ ]:
options = [
    opts.Points(
        active_tools=['lasso_select'], tools=['lasso_select', 'box_select'], 
        projection=ccrs.NorthPolarStereo(),
        frame_height=400, aspect=1,
    ),
    opts.Scatter(
        invert_axes=True, invert_yaxis=True, 
        color=hv.Cycle([mpl.colors.to_hex(c) for c in colors]),
        width=500, frame_height=400,
    ),
    opts.RGB(
        invert_axes=True, invert_yaxis=True,
        ylim=(0, None),
        width=500, frame_height=400,
    ),
    opts.NdOverlay(legend_position='right', ),
    opts.Layout(merge_tools=False),
]

Build app

In [ ]:
l = (loc + ntr_shaded + ntr_avg).opts(*options)

app = pn.Row(
    loc,
    ntr_avg, 
    ntr_shaded
)

print('Rendering now!')
app.servable()