I've been struggling to get my Shiny app to perform multiple operations upon pressing a single actionButton. I've looked around a lot and haven't been able to solve it. I've tried eventReactive, observeEvent, putting everything in one block, separating them out - you can see the eventReactive and observeEvent attempts in the server.R code.
I have a button which is supposed to run some models, once pressed. Upon pressing the button, I'd like to do quite a few things:
- Print a message letting the user know that something is happening
- Concatenate the previously-defined user options into a .sh file and execute model prediction
- Periodically check for the model output file
- Once output file has been created, print "Done" and save as a global variable for further analysis
This is what I have so far (it doesn't work, the model runs [yay!] and that's it). It's particularly confusing to me that the sys command runs fine, but the "Running" message doesn't get printed. I've made sure that I haven't misspelt any var names.
Dummy python script to produce an output: Let's call it script_shiny.py
import time
import pandas as pd
# construct dummy df
d = {'col1': [1, 2], 'col2': [3, 4], 'col3': [5,6]}
df = pd.DataFrame(data=d)
time.sleep(15) # let's add a delay to simulate the 'real' situation
df.to_csv("test_out.txt",sep="\t") # create the output file to be detected
The relevant part of ui.R:
*CODE TO CAPTURE PARAMS, WORKS FINE*
shiny::actionButton("button", "Run PIDGIN"), # RUN MODELS
tags$br(),
textOutput("pidginrunning"), # OUTPUT RUNNING MESSAGE
textOutput("pidgindone"), # OUTPUT DONE MESSAGE
The relevant part of server.R:
# One approach - observeEvent and defining renderText and .sh file creation and running all together
observeEvent(input$button, { # OBSERVE BUTTON BEING PRESSED
output$pidginrunning <- renderText({ # LET USER KNOW ITS RUNNING - NOT WORKING
paste0("Running PIDGIN...")
})
# CREATE .SH FILE AND RUN DUMMY SCRIPT - WORKING (params previously defined)
bin_bash <- "#!/bin/bash"
output_name <<- "test_out.txt"
runline <- paste0("python script_shiny.py")
bash_file <- data.frame(c(bin_bash,runline))
write.table(bash_file,"./run_pidgin.sh",quote=F,row.names=F,col.names=F)
system("bash -i run_pidgin.sh")
})
# CHECK OUTPUT - NOT WORKING
# Defining output_name in the previous code block works, its defined as a global variable
# Other approach, use eventReactive to define a 'function' which is called separately
checkOutput <- eventReactive(input$button, {
reactivePoll(1000, session, checkFunc = function() {
if (file.exists(output_name)==T) # check for the output file
assign(x = "preds", # Read it in if so, and define global variable
value = read.csv(output_name,header=T,sep="\t"),
envir = .GlobalEnv)
paste0("Done. Please move onto the Results tab.")
})
})
output$pidgindone <- renderText({ # PRINT DONE MESSAGE SO USER KNOWS TO MOVE ON
checkOutput()
})
Cheers for your time and help.