Skip to contents

This document details the high-level software architecture and interactive reactivity design patterns of the ewing Shiny application dashboard. It explains how independent component modules communicate state and route simulation data dynamically.


1. Modular Communication Structure

The dashboard layout and server linkages are defined in R/ewingApp.R. Rather than a monolithic codebase, the interface is split into dedicated Shiny modules using moduleServer().

Below is the state communication and data flow diagram:

graph TD
    %% Node definitions
    IP[initParApp: Parameters Selector]
    SS[simApp: Simulation Engine]
    DP[distPlotApp: Age Distributions]
    SP[substrateApp: Spatial Grid Map]
    EP[envPlotApp: Multi-Run Envelopes]
    DL[downloadApp: File Downloader]

    %% Communications
    IP -->|upload paths & species parameters| SS
    SS -->|sim_data$simres reactive| IP
    SS -->|sim_data$simres reactive| DP
    SS -->|sim_data$simres reactive| SP
    SS -->|sim_data$simres reactive & nsim| EP
    
    SS -->|sim_data| DL
    DP -->|distplot plot reactive| DL
    SP -->|sppplot plot reactive| DL
    EP -->|envplot plot reactive| DL

    style IP fill:#D5F5E3,stroke:#27AE60,stroke-width:2px;
    style SS fill:#FCF3CF,stroke:#F1C40F,stroke-width:2px;
    style DP fill:#E8F8F5,stroke:#17A589,stroke-width:2px;
    style SP fill:#E8F8F5,stroke:#17A589,stroke-width:2px;
    style EP fill:#E8F8F5,stroke:#17A589,stroke-width:2px;
    style DL fill:#EBDEF0,stroke:#8E44AD,stroke-width:2px;

Server Coordination (ewingServer)

The coordinating server loop in ewingServer() maps these interactions explicitly:

ewingServer <- function(id) {
  shiny::moduleServer(id, function(input, output, session) {
    ns <- session$ns
    
    # 1. Initialize Parameters Table & Species Models
    init_par <- initParServer("init_par", simres = shiny::reactive({ tryCatch(sim_data$simres(), error=function(e) NULL) }))
    
    # 2. Main Run Simulation 
    sim_data <- simServer("sim", init_par)
    
    # 3. Dynamic Visualizations (Evaluating on active state)
    dist_plot <- distPlotServer("dist_plot", sim_data$simres)
    spp_plot <- substrateServer("substrate", sim_data$simres)
    env_plot <- envPlotServer("env_plot", sim_data$simres, sim_data$nsim)
    
    # 4. Bind the File Extractor
    downloadServer("download", sim_data = sim_data, distplot = dist_plot, sppplot = spp_plot, envplot = env_plot)
    ...
  })
}

2. UI Layout & Dynamic Tabs

The user interface uses bslib::page_sidebar() to build a split-frame responsive layout: - Global Sidebar: Contains panels from initParInput(), simInput(), distPlotInput(), envPlotInput(), and downloadInput(). - Dynamic Main Panel: The active tabs change dynamically based on the value of nsim chosen by the user.

# Dynamic tab builder in R/ewingApp.R
output$dynamic_tabs <- shiny::renderUI({
  sims <- shiny::req(sim_data$nsim())
  if (sims == 1) {
    bslib::navset_tab(
      bslib::nav_panel("Dist Plots", distPlotOutput(ns("dist_plot"))),
      bslib::nav_panel("Substrate Plots", bslib::card(substrateOutput(ns("substrate")))),
      bslib::nav_panel("Input Data", initParOutput(ns("init_par")))
    )
  } else {
    bslib::navset_tab(
      bslib::nav_panel("Envelope Plots", bslib::card(envPlotOutput(ns("env_plot")))),
      bslib::nav_panel("Input Data", initParOutput(ns("init_par")))
    )
  }
})

3. Data Flow and Module API Bindings

Module Exposed Reactive Outputs Subscribed Inputs
Parameters (initPar) - host: Initial host count
- parasite: Initial parasite count
- datafile: Selected Excel filepath
- simres: Active simulation result for DT visualization
Simulation (sim) - simres: The ewing or ewing_discrete run output
- nsim: Selected number of simulation runs
- init_par: Config state list
Age Distributions (distPlot) - distplot: The active ggplot age overlay object - simres: Main single-run results
Spatial Substrate (substrate) - sppplot: The active ggplot individual positions grid - simres: Main single-run results
Envelope Bounds (envPlot) - envplot: The active ggplot confidence boundary - simres: Multi-run discrete data
Downloads (download) - (None, output is written directly to disk via user click triggers) - sim_data: Contains run metrics
- distplot, sppplot, envplot reactives

For deep dives into each section, see: - Simulation Panels - Visualization Panels - Utilities & Download Controls


4. Peer Application Wrappers & Shared Sub-Modules

IsleRoyaleApp.R and sysetholApp.R are built as peer application wrappers sharing identical underlying Shiny sub-modules: - step_controls (step_size_slider / parse_step_size / axisUnitInput / ageClassControlInput): Centralized logarithmic step click slider, dynamic axis units selector (Steps vs. Days for Isle Royale; Steps vs. Time for general apps), and Age Classes display options sub-modules in R/step_controls.R. - distPlotApp (distPlotOutput / distPlotServer): Renders age-class population dynamics over simulation steps or days. - inputApp (inputAppInput / inputAppOutput / inputAppServer / discover_dataset_tables): Dynamically discovers and displays input configuration data tables from any simulation site directory or Excel workbook. - substrateApp (substrateInput / substrateOutput / substrateServer): Renders substrate grid overlays and organism positions across tridiagonal plant networks or real-world GIS spatial meshes. - Tab-Aware Sidebar Decluttering: Both applications utilize conditionalPanel logic bound to the active tab ID (input.tabset). Display options (e.g., spatial map feature toggles, age-class normalization options, envelope confidence controls) are contextually shown strictly when their target tab is active, keeping the sidebar uncluttered.