Explore ERDDAP timeseries data using Jupyter Widgets

In [1]:
from erddapy import ERDDAP


server = 'http://www.neracoos.org/erddap'
e = ERDDAP(server=server)

e.protocol = 'tabledap'
In [2]:
import pendulum


initial_standard_name = 'significant_height_of_wind_and_swell_waves'

zoom = 6
center = [42.5, -68]
nchar = 3 # number of characters for short dataset name
cdm_data_type = 'TimeSeries'

max_time = pendulum.utcnow()
min_time = pendulum.utcnow().subtract(weeks=2) 
In [3]:
import pandas as pd


url = '{}/categorize/standard_name/index.csv'.format(server)
df = pd.read_csv(url, skiprows=[1, 2])
variables = df['Category'].values
In [4]:
import ipywidgets

dpdown = ipywidgets.Dropdown(options=variables, value=initial_standard_name)
In [5]:
def point(dataset, lon, lat, nchar):
    geojsonFeature = {
        "type": "Feature",
        "properties": {
            "datasetID": dataset,
            "short_dataset_name": dataset[:nchar]
        },
        "geometry": {
            "type": "Point",
            "coordinates": [lon, lat]
        }
    };
    geojsonFeature['properties']['style'] = {'color': 'Grey'}
    return geojsonFeature
In [6]:
def adv_search(e, standard_name, cdm_data_type, min_time, max_time):
    try:
        search_url = e.get_search_url(
            response='csv',
            cdm_data_type=cdm_data_type.lower(),
            items_per_page=100000,
            standard_name=standard_name,
            min_time=min_time,
            max_time=max_time
        )
        df = pd.read_csv(search_url)
    except:
        df = []
        if len(var)>14:
            v = '{}...'.format(standard_name[:15])
        else:
            v = standard_name
        figure.title = 'No {} found in this time range. Pick another variable.'.format(v)
        figure.marks[0].y = 0.0 * figure.marks[0].y
    return df
In [7]:
def alllonlat(e, cdm_data_type, min_time, max_time):
    url='{}/tabledap/allDatasets.csv?datasetID%2CminLongitude%2CminLatitude&cdm_data_type=%22{}%22&minTime%3C={}&maxTime%3E={}'.format(e.server,cdm_data_type,max_time,min_time)
    df = pd.read_csv(url, skiprows=[1])
    return df
In [8]:
def stdname2geojson(e, standard_name, min_time, max_time, nchar):
    dfa = adv_search(e, standard_name, cdm_data_type, min_time, max_time)
    if isinstance(dfa, pd.DataFrame):
        datasets = dfa['Dataset ID'].values
        dfll = alllonlat(e, cdm_data_type, min_time, max_time)
        dfr = dfll[dfll['datasetID'].isin(dfa['Dataset ID'])]
        geojson = {'features':[point(row[1],row[2],row[3],nchar) for row in dfr.itertuples()]}
    else:
        geojson = {'features':[]}
        datasets = []
    return geojson, datasets
In [9]:
def click_handler(event=None, id=None, properties=None):
    datasetID = properties['datasetID']
    kwargs = {'time>=': min_time, 'time<=': max_time}
    df, var = get_data(datasetID, dpdown.value, kwargs)
    figure.marks[0].x = df.index
    figure.marks[0].y = df[var]
    figure.title = '{} - {}'.format(properties['short_dataset_name'], var)
In [10]:
import ipyleaflet


def update_dpdown(change):
    standard_name = change['new']
    data, datasets = stdname2geojson(e, standard_name, min_time, max_time, nchar)
    feature_layer = ipyleaflet.GeoJSON(data=data)
    feature_layer.on_click(click_handler)
    m.layers = [m.layers[0], feature_layer]
In [11]:
dpdown.observe(update_dpdown, names=['value'])
In [12]:
def get_data(dataset, standard_name, kwargs):
    var = e.get_var_by_attr(
        dataset_id=dataset,
        standard_name=lambda v: str(v).lower() == standard_name)[0]
    e.dataset_id = dataset
    e.variables = ['time', var]
    e.constraints = kwargs
    df = e.to_pandas(index_col='time', parse_dates=True, skiprows=[1])
    return df, var
In [13]:
m = ipyleaflet.Map(
    center=center,
    zoom=zoom,
)

data, datasets = stdname2geojson(e, initial_standard_name, min_time, max_time, nchar)
feature_layer = ipyleaflet.GeoJSON(data=data)
feature_layer.on_click(click_handler)
m.layers = [m.layers[0], feature_layer]
In [14]:
import bqplot


dt_x = bqplot.DateScale()
sc_y = bqplot.LinearScale()

initial_dataset = datasets[0]
kwargs = {'time>=': min_time, 'time<=': max_time}
df, var = get_data(initial_dataset, initial_standard_name, kwargs)
time_series = bqplot.Lines(x=df.index, y=df[var], scales={'x': dt_x, 'y': sc_y})
ax_x = bqplot.Axis(scale=dt_x, label='Time')
ax_y = bqplot.Axis(scale=sc_y, orientation='vertical')
figure = bqplot.Figure(marks=[time_series], axes=[ax_x, ax_y])
figure.title = '{} - {}'.format(initial_dataset[:nchar], var)
figure.layout.height = '300px'
figure.layout.width = '800px'
In [15]:
ipywidgets.VBox([dpdown, m, figure])