33# ---- UI: sidebar controls ----
44mod_sensitivity_sidebar_ui <- function (id ) {
55 ns <- NS(id )
6- wellPanel(
7- h4(" Sensitivity analysis" ),
8-
9- # Message before primary analysis
10- conditionalPanel(
11- condition = sprintf(" !output['%s']" , ns(" ready" )),
12- helpText(" Run the primary analysis first to obtain γ; then you can run a sensitivity analysis." )
13- ),
14-
15- # Controls shown only after primary analysis is ready
16- conditionalPanel(
17- condition = sprintf(" output['%s']" , ns(" ready" )),
18- sliderInput(ns(" pc_range" ),
19- HTML(" Vary control true rate (\\ (\\ theta_c\\ ))" ),
6+ conditionalPanel(
7+ condition = sprintf(" output['%s'] === true" , ns(" ready" )),
8+ wellPanel(
9+ h4(" Sensitivity analysis" ),
10+ sliderInput(ns(" pc_range" ), HTML(" Vary control true rate (\\ (\\ theta_c\\ ))" ),
2011 min = 0 , max = 100 , value = c(70 , 95 ), step = 1 , post = " %" ),
21- numericInput(ns(" grid" ), " Number of grid points" , value = 11 , min = 3 , step = 1 ),
12+ numericInput(ns(" grid" ), " Number of grid points" , value = 10 , min = 3 , step = 1 , max = 15 ),
2213 checkboxGroupInput(ns(" metrics" ), " Compute:" ,
2314 choices = c(" Type-I at LFN" = " type1" ,
2415 " Power at assumed θt" = " power" ),
@@ -33,7 +24,7 @@ mod_sensitivity_main_ui <- function(id, plot_height = 300) {
3324 ns <- NS(id )
3425 tagList(
3526 conditionalPanel(
36- condition = sprintf(" output['%s']" , ns(" ready " )),
27+ condition = sprintf(" output['%s'] === true " , ns(" has_results " )),
3728 h4(" Sensitivity results" ),
3829 plotOutput(ns(" plot" ), height = plot_height ),
3930 tableOutput(ns(" table" ))
@@ -59,6 +50,7 @@ mod_sensitivity_server <- function(id,
5950 moduleServer(id , function (input , output , session ) {
6051
6152 `%||%` <- function (x , y ) if (is.null(x )) y else x
53+ .clamp <- function (x , a , b ) pmin(pmax(x , a ), b )
6254
6355 normalize_cols <- function (df ) {
6456 nm <- names(df )
@@ -69,20 +61,44 @@ mod_sensitivity_server <- function(id,
6961 df
7062 }
7163
72- # Gate UI until primary analysis exists
73- output $ ready <- reactive({ ! is.null(sim()) })
64+ # ready flag
65+ ready <- reactive({ isTRUE(! is.null(sim())) })
66+ output $ ready <- ready
7467 outputOptions(output , " ready" , suspendWhenHidden = FALSE )
7568
76- # Prefill θc range around current slider when ready
77- observeEvent(sim(), {
78- pc <- round((pc_current() %|| % 85 ))
79- lo <- max(0 , pc - 15 ); hi <- min(100 , pc + 15 )
80- updateSliderInput(session , " pc_range" , value = c(lo , hi ))
81- }, ignoreInit = TRUE )
82-
83- # Streaming results here
69+ # single definition (keep only this one)
8470 sens_stream <- reactiveVal(NULL )
8571
72+ # results-present flag
73+ output $ has_results <- reactive({
74+ df <- sens_stream()
75+ isTRUE(! is.null(df ) && nrow(df ) > 0 )
76+ })
77+ outputOptions(output , " has_results" , suspendWhenHidden = FALSE )
78+
79+ # prefill θc range once when ready becomes TRUE (or is already TRUE at init)
80+ .prefilled <- reactiveVal(FALSE )
81+ observeEvent(ready(), {
82+ req(ready(), ! .prefilled()) # ensure sim() exists and run only once
83+ .prefilled(TRUE )
84+
85+ s <- req(sim())
86+
87+ pc_assumed <- s $ t1 $ settings $ p_c %|| % s $ inputs $ p_c %|| % s $ pc_assumed %|| %
88+ (pc_current() / 100 ) %|| % 0.85
89+ pc_assumed <- suppressWarnings(as.numeric(pc_assumed ))
90+ if (! is.finite(pc_assumed )) pc_assumed <- 0.85
91+ pc_assumed <- .clamp(pc_assumed , 0 , 1 )
92+
93+ pc_pct <- round(100 * pc_assumed )
94+ if (pc_pct == 0 ) { lo <- 0 ; hi <- 10 } else { lo <- max(0 , pc_pct - 10 ); hi <- pc_pct }
95+
96+ # update after panel renders
97+ session $ onFlushed(function () {
98+ updateSliderInput(session , " pc_range" , value = c(lo , hi ))
99+ }, once = TRUE )
100+ }, ignoreInit = FALSE )
101+
86102 # Run sensitivity with progress and streaming updates
87103 observeEvent(input $ run , {
88104 s <- req(sim())
0 commit comments