My code is below.
The expected behavior is such:
run_analysis
is clicked by the user.observeEvent
block for input$run_analysis
, which updates the reactive value run_analysis_clicked
to TRUE
.observe
block to be executed, which updates the selected tab in the mainPanelTabs
tabset.But that's not what's happening. For some reason, the observe
block is NOT being triggered after the run_analysis_clicked
value is changed.
I've tried to pair this down to a minimally reproducible sample.
library(shiny)
#### USER INTERFACE ####
ui <- fluidPage(
titlePanel("Bootstrap Sample Size Simulator"),
sidebarLayout(
sidebarPanel(
# Define the primary inputs needed to setup the sample size simulation
fileInput("file_upload", "Upload a CSV file with sample data to use for sample size optimization:", accept = ".csv"),
uiOutput("slider_output"),
uiOutput("action_output")
),
mainPanel(
tabsetPanel(
id = "mainPanelTabs", # Add an ID for easier reference
tabPanel("instructions", "Instructions content goes here."),
tabPanel("data", "Data content goes here."),
tabPanel("results", "Results content goes goes here.")
)
)
)
)
#### SERVER ####
server <- function(input, output, session) {
# Define reactive values that populate when the file is uploaded
upload <- reactiveValues(
isUploaded = FALSE, # flag signifying the file has been uploaded
data = NULL, # empty placeholder for the data
sample_max = NULL # initialize as empty
)
# Define reactive value that identifies when the run_analysis button has been clicked
run_analysis_clicked <- reactive({
FALSE # Flag is initially set to FALSE
})
# Define reactive value that updates the selected tab
selectedTab <- reactiveVal("instructions")
# Define function for creating the slider UI element for sample size limits selection
slider_ui <- function() {
if (upload$isUploaded) {
sliderInput("sample_range",
label = "Range of Sample Sizes to simulate from the uploaded data:",
min = 2,
max = upload$sample_max,
step = 1,
value = c(2, upload$sample_max)
)
} else {
NULL
}
}
# Define function for creating the run analysis button
action_ui <- function() {
if (upload$isUploaded) {
actionButton("run_analysis",
label = "Run the analysis"
)
} else {
NULL
}
}
# Update reactive values when file is uploaded
observeEvent(input$file_upload, {
upload$isUploaded <- TRUE # update flag after file is uploaded
upload$data <- read.csv(input$file_upload$datapath) # read the uploaded CSV file
upload$sample_max <- nrow(upload$data) # update sample_max after file has been
print(paste("upload$sample_max:",upload$sample_max))
})
# Update reactive values when button is clicked
observeEvent(input$run_analysis, {
run_analysis_clicked <- TRUE # update flag after button clicked
print(paste("run_analysis_clicked",run_analysis_clicked))
})
# Update selected tab based on upload and button click events
observe({
print("observe triggered")
print(paste("upload$isUploaded:",upload$isUploaded))
print(paste("run_analysis_clicked:",run_analysis_clicked()))
if (!upload$isUploaded) {
selectedTab("instructions")
} else if (run_analysis_clicked() == FALSE) {
selectedTab("data")
} else {
selectedTab("results")
}
# Update the selected tab directly in the UI
updateTabsetPanel(session, "mainPanelTabs", selected = selectedTab())
})
# Render the slider and action buttons conditionally upon file upload
output$slider_output <- renderUI({
slider_ui()
})
output$action_output <- renderUI({
action_ui()
})
}
#### APP ####
shinyApp(ui = ui, server = server)
Here's the console output (with added comments explaining the actions that triggered the outputs):
Listening on http://xxxxxx
# App Initialized:
[1] "observe triggered"
[1] "upload$isUploaded: FALSE"
[1] "run_analysis_clicked: FALSE"
# File Uploaded:
[1] "upload$sample_max: 15"
[1] "observe triggered"
[1] "upload$isUploaded: TRUE"
[1] "run_analysis_clicked: FALSE"
# Button Clicked:
[1] "run_analysis_clicked TRUE"
For the file upload, I'm just using a CSV file with 15 random numbers I created in Excel. Here's what it looks like:
Sample Data |
---|
0.590024857449706 |
0.0728674995484038 |
0.481874325987865 |
0.960001135837481 |
0.294927454278591 |
0.25254752567793 |
0.460322873384411 |
0.00237222444026342 |
0.169595016393134 |
0.444750644528156 |
0.033684417887163 |
0.973733565927954 |
0.917744500279373 |
0.264506821656346 |
0.998370147928976 |
The one main important thing here to understand is that
run_analysis_clicked <- reactive({
FALSE # Flag is initially set to FALSE
})
does not define a reactive value, it defines a reactive expression. If you define a variable as such a reactive
, it is not possible to change its value outside of its reactive environment. You can imagine it as that you have only "read" permissions on a reactive
, while on a reactiveVal
you have "read" and "write" permissions.
Since you define the reactive
as FALSE
, nowhere inside your app a change of this variable can be observed. A possibility how this could be achieved would be to define a dependency to a reactiveVal
, e.g.
rv <- reactiveValues(blnRunAnalysisClicked = TRUE)
run_analysis_clicked <- reactive({rv$blnRunAnalysisClicked})
But in your case we can skip the reactive
part and rely directly on a reactiveVal
, e.g. as given by the below example (upload$run_analysis_clicked
), which will work.
library(shiny)
#### USER INTERFACE ####
ui <- fluidPage(
titlePanel("Bootstrap Sample Size Simulator"),
sidebarLayout(
sidebarPanel(
# Define the primary inputs needed to setup the sample size simulation
fileInput("file_upload", "Upload a CSV file with sample data to use for sample size optimization:", accept = ".csv"),
uiOutput("slider_output"),
uiOutput("action_output")
),
mainPanel(
tabsetPanel(
id = "mainPanelTabs", # Add an ID for easier reference
tabPanel("instructions", "Instructions content goes here."),
tabPanel("data", "Data content goes here."),
tabPanel("results", "Results content goes goes here.")
)
)
)
)
#### SERVER ####
server <- function(input, output, session) {
# Define reactive values that populate when the file is uploaded
upload <- reactiveValues(
isUploaded = FALSE, # flag signifying the file has been uploaded
data = NULL, # empty placeholder for the data
sample_max = NULL, # initialize as empty
run_analysis_clicked = FALSE
)
# Define reactive value that updates the selected tab
selectedTab <- reactiveVal("instructions")
# Define function for creating the slider UI element for sample size limits selection
slider_ui <- function() {
if (upload$isUploaded) {
sliderInput("sample_range",
label = "Range of Sample Sizes to simulate from the uploaded data:",
min = 2,
max = upload$sample_max,
step = 1,
value = c(2, upload$sample_max)
)
} else {
NULL
}
}
# Define function for creating the run analysis button
action_ui <- function() {
if (upload$isUploaded) {
actionButton("run_analysis",
label = "Run the analysis"
)
} else {
NULL
}
}
# Update reactive values when file is uploaded
observeEvent(input$file_upload, {
upload$isUploaded <- TRUE # update flag after file is uploaded
upload$data <- read.csv(input$file_upload$datapath) # read the uploaded CSV file
upload$sample_max <- nrow(upload$data) # update sample_max after file has been
print(paste("upload$sample_max:",upload$sample_max))
})
# Update reactive values when button is clicked
observeEvent(input$run_analysis, {
upload$run_analysis_clicked <- TRUE # update flag after button clicked
print(paste("run_analysis_clicked", upload$run_analysis_clicked))
})
# Update selected tab based on upload and button click events
observe({
print("observe triggered")
print(paste("upload$isUploaded:",upload$isUploaded))
print(paste("run_analysis_clicked:",upload$run_analysis_clicked))
if (!upload$isUploaded) {
selectedTab("instructions")
} else if (upload$run_analysis_clicked == FALSE) {
selectedTab("data")
} else {
selectedTab("results")
}
# Update the selected tab directly in the UI
updateTabsetPanel(session, "mainPanelTabs", selected = selectedTab())
})
# Render the slider and action buttons conditionally upon file upload
output$slider_output <- renderUI({
slider_ui()
})
output$action_output <- renderUI({
action_ui()
})
}
#### APP ####
shinyApp(ui = ui, server = server)