TomNash
TomNash

Reputation: 3288

How to stop output code from running if certain tab is active when event occurs in Shiny?

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

Answers (1)

TomNash
TomNash

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

Related Questions