Reputation: 3288
I have the following code which works as such: user uploads a file, presses submit, an external program is run which creates files in an output directory, files are read and rendered in a plot tab and a table tab. It works fine if the user presses submit while on the plot tab; but if the button is pressed while the table tab is active, then it doesn't update to use the newly created output directory for the table. I've added some general code below, can't provide specific examples due to nature of the work.
I've tried to resolve this by adding the observeEvent
to switch to the plot tab when the button is pressed, but it doesn't work. I'm guessing it has something to do with the tab being active when the button is pressed, so it executes the code in output$table1 <- DT::renderDataTable({ ... })
first which still references the old contents of output.dir
. Is there a way to stop it when the button is pressed while this tab is active? Or should I format the flow of the code a different way? Still trying to figure Shiny out.
When the button is pressed, regardless of which tab is active, I need to do things in the order specified above. New directory, run command and output to the directory, then read files from it in each tab. I have it switch to the graph because you'd look at that first then the interactions table. Every time you press submit, the new updated graph and table should be rendered.
ui.R
shinyUI(fluidPage(
sidebarLayout(
sidebarPanel(
fileInput("file1", "Upload a file"),
actionButton("submitButton", "Submit")
),
mainPanel(
tabsetPanel(id = "output",
tabPanel("Graph",plotOutput("plot1")),
tabPanel("Interactions", DT::dataTableOutput("table1"))
)
)
)
))
server.R
shinyServer(function(input, output, session) {
# When button pressed, create output directory and switch to plot tab
observeEvent(input$submitButton, {
updateTabsetPanel(session, "output", "Graph")
dateTime <- as.numeric(as.POSIXct(Sys.time()))
output.dir <<- paste0("~/Sites/Shiny/",dateTime,"/")
dir.create(output.dir)
})
output$plot1 <- renderPlot({
# Check if button pressed and only run if pressed
input$submitButton
isolate({
validate(
need(input$file1, 'Provide a file')
)
})
# External system commands which creates output files in output.dir
# Concatenate some strings for arguments, then run system(...)
# Capture output, check for error string and validate
validate(
need(!(gdata::startsWith(output, "Error:")), 'Error: ...')
)
plot(readLines(paste0(output.dir,"plot.file")))
})
output$table1 <- DT::renderDataTable({
# Check if button pressed and only run if pressed
input$submitButton
isolate({
validate(
# Make sure files exist in the directory
need(length(list.files(output.dir,pattern="^StartsWithA|^StartsWithB")) > 0,
'Run model first to receive interactions')
)
DT::datatable(read.table(
paste0(output.dir,list.files(output.dir,pattern="^StartsWithA|^StartsWithB")),
col.names = c("ColA","ColB","ColC","ColD"), sep="\t"),
options = list(pageLength = 10))
})
})
})
Upvotes: 2
Views: 676
Reputation: 3288
I reworked the order of functions, and wrapped everything in the observeEvent
and moved the system call outside the output and it seems to work now.
shinyServer(function(input, output, session) {
output$plot1 <- renderPlot({
validate(
need(input$file1, 'Provide a file')
)
})
output$table1 <- DT::renderDataTable({
validate(
need(input$file1, 'Provide a file')
)
})
# When button pressed, create output directory, switch to plot tab, run program
observeEvent(input$submitButton, {
input$submitButton
isolate({
validate(
need(input$file1, 'Provide a file')
)
})
updateTabsetPanel(session, "output", "Graph")
dateTime <- as.numeric(as.POSIXct(Sys.time()))
output.dir <<- paste0("~/Sites/Shiny/",dateTime,"/")
dir.create(output.dir)
# External system commands which creates output files in output.dir
# Concatenate some strings for arguments, then run system(...)
# Capture output, check for error string and validate
command.output <- system(..., intern=T)[1]
output$plot1 <- renderPlot({
validate(
need(!(gdata::startsWith(command.output, "Error:")), 'Error: ...')
)
plot(readLines(paste0(output.dir,"plot.file")))
})
output$table1 <- DT::renderDataTable({
validate(
need(!(gdata::startsWith(command.output, "Error:")), 'Error: ...')
)
DT::datatable(read.table(
paste0(output.dir,list.files(output.dir,pattern="^StartsWithA|^StartsWithB")),
col.names = c("ColA","ColB","ColC","ColD"), sep="\t"),
options = list(pageLength = 10))
})
})
})
Upvotes: 4