Visualization#

TEEHR integrates with HoloViews/hvPlot and GeoViews for interactive visualization of timeseries and spatial data. This section demonstrates common visualization patterns for TEEHR evaluation results.

Note

This section is under development. Additional examples and interactive visualizations will be added in future releases.

Prerequisites#

TEEHR includes visualization dependencies (installed with the main package):

  • HoloViews/hvPlot: Interactive plotting for timeseries data

  • GeoViews: Geographic visualization with Bokeh backend

  • matplotlib: Static plotting support

import holoviews as hv
import hvplot.pandas
import geoviews as gv
from bokeh.io import output_notebook

# Enable notebook output
hv.extension('bokeh')
output_notebook()

Basic Timeseries Plot#

Plot observed vs. simulated timeseries for a single location:

import teehr
import hvplot.pandas

ev = teehr.LocalReadWriteEvaluation(dir_path="/path/to/evaluation")

# Get joined timeseries for a specific location
df = ev.joined_timeseries_view().filter(
    "primary_location_id = 'usgs-01184000'"
).to_pandas()

# Plot primary (observed) vs secondary (simulated)
plot = df.hvplot.line(
    x='value_time',
    y=['primary_value', 'secondary_value'],
    title='Streamflow: Observed vs. Simulated',
    xlabel='Time',
    ylabel='Streamflow (cfs)',
    legend='top',
    width=800,
    height=400
)

plot

Forecast Timeseries#

Plot ensemble forecast with spread:

# Filter for forecast data with multiple members
df = ev.secondary_timeseries.filter(
    "configuration_name = 'nwm30_medium_range'",
    "primary_location_id = 'usgs-01184000'"
).to_pandas()

# Plot ensemble members
plot = df.hvplot.line(
    x='value_time',
    y='value',
    by='reference_time',
    title='Ensemble Forecast',
    xlabel='Time',
    ylabel='Streamflow (cfs)',
    width=800,
    height=400
)

plot

Basic Map#

Display locations with attributes:

import geoviews as gv
import geoviews.tile_sources as gts

gv.extension('bokeh')

ev = teehr.LocalReadWriteEvaluation(dir_path="/path/to/evaluation")

# Get locations as GeoDataFrame
gdf = ev.locations.to_geopandas()

# Create point layer
points = gv.Points(gdf).opts(
    size=8,
    color='blue',
    tools=['hover'],
)

# Add basemap tiles
tiles = gts.OSM

# Combine layers
map_plot = tiles * points
map_plot.opts(width=700, height=500, title='Evaluation Locations')

Metrics on a Map#

Visualize performance metrics spatially:

import geoviews as gv
from bokeh.palettes import RdYlGn11

ev = teehr.LocalReadWriteEvaluation(dir_path="/path/to/evaluation")

# Calculate metrics with geometry
from teehr.metrics import DeterministicMetrics

metrics_gdf = ev.joined_timeseries_view().aggregate(
    metrics=[DeterministicMetrics.KlingGuptaEfficiency()],
    group_by=["primary_location_id"],
).to_geopandas()

# Create colored points based on KGE
points = gv.Points(
    metrics_gdf,
    kdims=['geometry'],
    vdims=['kling_gupta_efficiency', 'primary_location_id']
).opts(
    size=10,
    color='kling_gupta_efficiency',
    cmap='RdYlGn',
    clim=(0, 1),
    colorbar=True,
    tools=['hover'],
)

# Add basemap
tiles = gv.tile_sources.OSM

map_plot = tiles * points
map_plot.opts(
    width=700,
    height=500,
    title='Kling-Gupta Efficiency by Location'
)

Hydrograph Comparison#

Compare observed and simulated hydrographs with metrics overlay:

import holoviews as hv
import hvplot.pandas

ev = teehr.LocalReadWriteEvaluation(dir_path="/path/to/evaluation")

# Get timeseries
df = ev.joined_timeseries_view().filter(
    "primary_location_id = 'usgs-01184000'",
    "configuration_name = 'nwm30_retrospective'"
).to_pandas()

# Calculate metrics
from teehr.metrics import DeterministicMetrics

metrics = ev.joined_timeseries_view().filter(
    "primary_location_id = 'usgs-01184000'",
    "configuration_name = 'nwm30_retrospective'"
).aggregate(
    metrics=[
        DeterministicMetrics.KlingGuptaEfficiency(),
        DeterministicMetrics.NashSutcliffeEfficiency(),
    ],
    group_by=["primary_location_id"]
).to_pandas()

kge = metrics['kling_gupta_efficiency'].values[0]
nse = metrics['nash_sutcliffe_efficiency'].values[0]

# Create hydrograph plot
obs_line = df.hvplot.line(
    x='value_time', y='primary_value',
    label='Observed', color='blue', line_width=1.5
)
sim_line = df.hvplot.line(
    x='value_time', y='secondary_value',
    label='Simulated', color='red', line_width=1.5, alpha=0.7
)

# Add metrics as text annotation
title = f'Hydrograph Comparison | KGE: {kge:.3f}, NSE: {nse:.3f}'

plot = (obs_line * sim_line).opts(
    title=title,
    xlabel='Time',
    ylabel='Streamflow (cfs)',
    legend_position='top_right',
    width=900,
    height=400
)

plot

Additional Resources#

For more visualization examples, see:

Example notebooks demonstrating TEEHR visualizations are available in the Example Notebooks section.