The Boston Light Swim

Sea Surface Temperature time-series maps

Load configuration


In [1]:
import os
from ioos_tools.ioos import parse_config, load_ncs

config = parse_config('config.yaml')

save_dir = os.path.join(os.path.abspath(config['run_name']))

Load skill_score


In [2]:
import json

fname = os.path.join(config['run_name'], 'skill_score.json')
with open(fname, 'r') as f:
    skill_score = json.loads(f.read())

In [3]:
import pandas as pd

mean_bias = pd.DataFrame.from_dict(skill_score['mean_bias'])
mean_bias = mean_bias.applymap('{:.2f}'.format).replace('nan', '--')

skill_score = pd.DataFrame.from_dict(skill_score['rmse'])
skill_score = skill_score.applymap('{:.2f}'.format).replace('nan', '--')

In [4]:
from ioos_tools.ioos import make_map

bbox = config['region']['bbox']
units = config['units']
run_name = config['run_name']

kw = dict(zoom_start=11, line=True, states=False,
          secoora_stations=False, layers=False)
mapa = make_map(bbox, **kw)

Clusters


In [5]:
from ioos_tools.ioos import stations_keys

all_obs = stations_keys(config)

In [6]:
from glob import glob
from operator import itemgetter

import iris
import folium
from folium.plugins import MarkerCluster

iris.FUTURE.netcdf_promote = True

big_list = []
for fname in glob(os.path.join(save_dir, '*.nc')):
    if 'OBS_DATA' in fname:
        continue
    cube = iris.load_cube(fname)
    model = fname.split('-')[-1].split('.')[0]
    lons = cube.coord(axis='X').points
    lats = cube.coord(axis='Y').points
    stations = cube.coord('station_code').points
    models = [model]*lons.size
    lista = zip(models, lons.tolist(), lats.tolist(), stations.tolist())
    big_list.extend(lista)

big_list.sort(key=itemgetter(3))
df = pd.DataFrame(big_list, columns=['name', 'lon', 'lat', 'station'])
df.set_index('station', drop=True, inplace=True)
groups = df.groupby(df.index)


locations, popups = [], []
for station, info in groups:
    sta_name = all_obs[station]
    for lat, lon, name in zip(info.lat, info.lon, info.name):
        locations.append([lat, lon])
        name = os.path.split(name)[-1]
        popups.append('[{}]: {}'.format(name, sta_name))

MarkerCluster(locations=locations, popups=popups).add_to(mapa)


Out[6]:
<folium.plugins.marker_cluster.MarkerCluster at 0x7ff012dc9b38>

Model and observations plots


In [7]:
import warnings

# Suppresing warnings for a "pretty output."
# Remove this line to debug any possible issues.
warnings.simplefilter('ignore')

In [8]:
# Legend dictionary. If any new model is found we will use its filename as legend.
# Here we only provide some nice names for the models we expect to find.

titles = {
    'coawst_4_use_best': 'COAWST_4',
    'global': 'HYCOM',
    'NECOFS_GOM3_FORECAST': 'NECOFS_GOM3',
    'NECOFS_FVCOM_OCEAN_MASSBAY_FORECAST': 'NECOFS_MassBay',
    'OBS_DATA': 'Observations'
}

In [9]:
from bokeh.resources import CDN
from bokeh.plotting import figure
from bokeh.embed import file_html
from bokeh.models import HoverTool
from itertools import cycle
from bokeh.palettes import Category20

from folium import IFrame

# Plot defaults.
colors = Category20[20]
colorcycler = cycle(colors)
tools = 'pan,box_zoom,reset'
width, height = 750, 250


def make_plot(df, station):
    p = figure(
        toolbar_location='above',
        x_axis_type='datetime',
        width=width,
        height=height,
        tools=tools,
        title=str(station)
    )
    for column, series in df.iteritems():
        series.dropna(inplace=True)
        if not series.empty:
            if 'OBS_DATA' not in column:
                bias = mean_bias[str(station)][column]
                skill = skill_score[str(station)][column]
                line_color = next(colorcycler)
                kw = dict(alpha=0.65, line_color=line_color)
            else:
                skill = bias = 'NA'
                kw = dict(alpha=1, color='crimson')
            line = p.line(
                x=series.index,
                y=series.values,
                legend='%s' % titles.get(column, column),
                line_width=5,
                line_cap='round',
                line_join='round',
                **kw,
            )
            p.add_tools(HoverTool(tooltips=[('Name', '%s' % column),
                                            ('Bias', bias),
                                            ('Skill', skill)],
                                  renderers=[line]))
    return p


def make_marker(p, station):
    lons = stations_keys(config, key='lon')
    lats = stations_keys(config, key='lat')

    lon, lat = lons[station], lats[station]
    html = file_html(p, CDN, station)
    iframe = IFrame(html, width=width+40, height=height+80)

    popup = folium.Popup(iframe, max_width=2650)
    icon = folium.Icon(color='green', icon='stats')
    marker = folium.Marker(location=[lat, lon],
                           popup=popup,
                           icon=icon)
    return marker

In [10]:
dfs = load_ncs(config)

for station in dfs:
    sta_name = all_obs[station]
    df = dfs[station]
    if df.empty:
        continue
    p = make_plot(df, station)
    maker = make_marker(p, station)
    maker.add_to(mapa)

mapa


Out[10]: