Skip to content

[Phase 5] Visualization Dashboard - Maps & Streamlit #6

@Sakeeb91

Description

@Sakeeb91

Summary

Create interactive visualizations for pattern exploration, including publication-quality maps, time series plots, and a Streamlit dashboard for real-time pattern analysis.

Parent Issue: #1
Depends On: Phase 4 (Extreme Event Analysis)

Objectives

  • Generate publication-quality EOF pattern maps with Cartopy
  • Create time series visualizations with phase shading
  • Build interactive Streamlit dashboard
  • Produce Jupyter notebook for exploration

System Context

src/visualization/
├── maps.py            # Cartopy-based pattern maps
├── timeseries.py      # Index time series plots
└── dashboard.py       # Streamlit interactive app

Files to Create/Modify

File Action Description
src/visualization/maps.py Create EOF pattern maps with coastlines
src/visualization/timeseries.py Create Time series with phase highlighting
src/visualization/dashboard.py Create Streamlit interactive dashboard
notebooks/exploration.ipynb Create Analysis notebook

Implementation Checklist

Pattern Maps

  • Configure Cartopy projections (PlateCarree, LambertConformal)
  • Add coastlines, country borders, gridlines
  • Use diverging colormap (RdBu_r) for anomaly patterns
  • Add colorbar with proper units
  • Save as PNG and PDF

Time Series Plots

  • Plot index time series with date axis
  • Shade positive/negative phases
  • Add running mean overlay
  • Compare multiple indices on same axes

Interactive Dashboard

  • Create Streamlit app structure
  • Add pattern selector dropdown
  • Display pattern map and time series side by side
  • Add date range selector
  • Show correlation heatmap

Notebook

  • Create exploration notebook
  • Include data loading examples
  • Show EOF analysis workflow
  • Document key findings

Code Snippets

EOF Pattern Map

# src/visualization/maps.py
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import cartopy.feature as cfeature
import numpy as np

def plot_eof_pattern(
    pattern: np.ndarray,
    lat: np.ndarray,
    lon: np.ndarray,
    title: str = "EOF Pattern",
    variance_explained: float = None,
    output_path: str = None
) -> plt.Figure:
    """Plot EOF spatial pattern with coastlines.

    Args:
        pattern: 2D array (lat, lon)
        lat: Latitude coordinates
        lon: Longitude coordinates
        title: Plot title
        variance_explained: Optional variance explained percentage
        output_path: Optional path to save figure

    Returns:
        matplotlib Figure object
    """
    fig, ax = plt.subplots(
        figsize=(12, 8),
        subplot_kw={"projection": ccrs.PlateCarree()}
    )

    # Set up map features
    ax.add_feature(cfeature.LAND, facecolor="lightgray")
    ax.add_feature(cfeature.COASTLINE, linewidth=0.5)
    ax.add_feature(cfeature.BORDERS, linewidth=0.3, linestyle=":")
    ax.gridlines(draw_labels=True, alpha=0.3)

    # Plot pattern
    vmax = np.abs(pattern).max()
    im = ax.contourf(
        lon, lat, pattern,
        levels=np.linspace(-vmax, vmax, 21),
        cmap="RdBu_r",
        transform=ccrs.PlateCarree(),
        extend="both"
    )

    # Colorbar
    cbar = plt.colorbar(im, ax=ax, orientation="horizontal", pad=0.05)
    cbar.set_label("Standardized Anomaly")

    # Title
    if variance_explained:
        title = f"{title} ({variance_explained:.1f}% variance)"
    ax.set_title(title, fontsize=14, fontweight="bold")

    if output_path:
        fig.savefig(output_path, dpi=150, bbox_inches="tight")

    return fig

Time Series with Phase Shading

# src/visualization/timeseries.py
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import pandas as pd
import numpy as np

def plot_index_timeseries(
    index: pd.Series,
    title: str = "Climate Index",
    threshold: float = 0.5,
    output_path: str = None
) -> plt.Figure:
    """Plot climate index time series with phase shading.

    Args:
        index: Time series with datetime index
        title: Plot title
        threshold: Threshold for phase classification
        output_path: Optional path to save figure

    Returns:
        matplotlib Figure object
    """
    fig, ax = plt.subplots(figsize=(14, 5))

    # Plot index
    ax.plot(index.index, index.values, "k-", linewidth=0.8, label="Monthly")

    # Add running mean
    rolling = index.rolling(12, center=True).mean()
    ax.plot(rolling.index, rolling.values, "b-", linewidth=2, label="12-month mean")

    # Shade positive phases
    ax.fill_between(
        index.index, index.values, threshold,
        where=index.values > threshold,
        alpha=0.3, color="red", label="Positive phase"
    )

    # Shade negative phases
    ax.fill_between(
        index.index, index.values, -threshold,
        where=index.values < -threshold,
        alpha=0.3, color="blue", label="Negative phase"
    )

    # Zero line
    ax.axhline(0, color="gray", linestyle="--", linewidth=0.5)

    # Formatting
    ax.set_xlabel("Date")
    ax.set_ylabel("Index Value")
    ax.set_title(title, fontsize=14, fontweight="bold")
    ax.legend(loc="upper right")
    ax.xaxis.set_major_locator(mdates.YearLocator(10))
    ax.xaxis.set_major_formatter(mdates.DateFormatter("%Y"))

    if output_path:
        fig.savefig(output_path, dpi=150, bbox_inches="tight")

    return fig

Streamlit Dashboard

# src/visualization/dashboard.py
import streamlit as st
import pandas as pd
import numpy as np

# Page config
st.set_page_config(
    page_title="Climate Pattern Explorer",
    layout="wide"
)

st.title("Climate Pattern Recognition Dashboard")

# Sidebar controls
st.sidebar.header("Settings")

pattern_type = st.sidebar.selectbox(
    "Select Teleconnection",
    ["NAO", "AO", "ONI", "PDO"]
)

date_range = st.sidebar.date_input(
    "Date Range",
    value=(pd.Timestamp("2000-01-01"), pd.Timestamp("2023-12-31"))
)

# Main content
col1, col2 = st.columns(2)

with col1:
    st.subheader(f"{pattern_type} Spatial Pattern")
    # Load and display pattern map
    # st.pyplot(fig)

with col2:
    st.subheader(f"{pattern_type} Time Series")
    # Load and display time series
    # st.line_chart(data)

# Correlation matrix
st.subheader("Index Correlations")
# st.dataframe(corr_matrix)

# Footer
st.markdown("---")
st.markdown("Data sources: ERA5, NOAA PSL")

Verification

# Generate pattern maps
python -c "
from src.visualization.maps import plot_eof_pattern
from src.features.eof import EOFAnalyzer
# ... generate and plot pattern
"

# Launch dashboard
streamlit run src/visualization/dashboard.py

# Run notebook
jupyter notebook notebooks/exploration.ipynb

Technical Challenges

Challenge Mitigation
Cartopy installation Use conda environment
Projection performance Cache transformed coordinates
Streamlit data size Load summaries, not raw data
Color scale selection Use diverging for anomalies

Definition of Done

  • EOF patterns render correctly with coastlines
  • Time series show phase shading correctly
  • Dashboard loads and responds within 2 seconds
  • All 4 major teleconnections visualizable
  • Notebook runs end-to-end without errors
  • Figures saved in figures/ directory

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions