R shiny: Update tabsetpanel before finishing all the observeEvent code

I want to update the tabsetpanel immediately, and not wait untill finishing the download function. here you can find a simple code It has a button, and when it presed, it simulate a download, and update a tabsetpanel. I want to update the panel before finishing the download.

Thanks!

server <- function(input, output,session) {

observeEvent(input$goPlot,{

updateTabsetPanel(session, "inTabset",
                  selected = 'Summary'
)

output$plot <- renderPlot({
  input$goPlot # Re-run when button is clicked

  # Create 0-row data frame which will be used to store data
  dat <- data.frame(x = numeric(0), y = numeric(0))

  withProgress(message = 'Making plot', value = 0, {
    # Number of times we'll go through the loop
    n <- 10

    for (i in 1:n) {
      # Each time through the loop, add another row of data. This is
      # a stand-in for a long-running computation.
      dat <- rbind(dat, data.frame(x = rnorm(1), y = rnorm(1)))

      # Increment the progress bar, and update the detail text.
      incProgress(1/n, detail = paste("Doing part", i))

      # Pause for 0.1 seconds to simulate a long computation.
      Sys.sleep(1)
    }
  })

  plot(dat$x, dat$y)
})



})
}

ui <- shinyUI(fluidPage(
actionButton('goPlot', 'Go plot'),
tabsetPanel(id = "inTabset",
tabPanel("Plot", plotOutput("plot")),
tabPanel("Summary")

)
)   

)

shinyApp(ui = ui, server = server)

Upvotes: 3

Views: 691

Answers (3)

St&#233;phane Laurent
St&#233;phane Laurent

Reputation: 84649

You can do:

  observeEvent(input$goPlot, {
    updateTabsetPanel(session, "inTabset",
                      selected = 'Summary'
    )       
  })

  output$plot <- renderPlot({
    req(input$inTabset == "Summary") # require "Summary" is the active tab
    input$goPlot # Re-run when button is clicked
    ......

Or execute some Javascript code to change the active tab, e.g. with shinyjs:

library(shiny)
library(shinyjs)

server <- function(input, output,session) {

  observeEvent(input$goPlot, {

    runjs("$('a[data-value=Summary]').click();") # go to Summary tab

    output$plot <- renderPlot({
      input$goPlot # Re-run when button is clicked

      # Create 0-row data frame which will be used to store data
      dat <- data.frame(x = numeric(0), y = numeric(0))

      withProgress(message = 'Making plot', value = 0, {
        # Number of times we'll go through the loop
        n <- 10
        for (i in 1:n) {
          # Each time through the loop, add another row of data. This is
          # a stand-in for a long-running computation.
          dat <- rbind(dat, data.frame(x = rnorm(1), y = rnorm(1)))
          # Increment the progress bar, and update the detail text.
          incProgress(1/n, detail = paste("Doing part", i))
          # Pause for 0.1 seconds to simulate a long computation.
          Sys.sleep(1)
        }
      })

      plot(dat$x, dat$y)
    })

  })


}

ui <- shinyUI(fluidPage(
  useShinyjs(),
  actionButton('goPlot', 'Go plot'),
  tabsetPanel(id = "inTabset",
              tabPanel("Plot", plotOutput("plot")),
              tabPanel("Summary")
  )
))

shinyApp(ui = ui, server = server)

Upvotes: 1

Bertil Baron
Bertil Baron

Reputation: 5003

Shiny only updates the UI after all invalidated observe or reactive statements has been updated. Therefore you have to build reactive chains when you want a workflow like this. I solved this though pulling out the data preparation in a separate reactive statement (this is not really necessary but always a good idea) then I moved the plot to the summary tab. I supposed the reason to switch tab was to see the plot. Please correct me if this is not correct. But this postpones the calculations until the tab is shown. Now to prevent that the calculations start before the goPlot button is clicked I just added the line

req(input$goPlot) 

to the beginning of the the reactive statement.

server <- function(input, output,session) {
  observeEvent(input$goPlot,{

    updateTabsetPanel(session, "inTabset",
                      selected = 'Summary'
    )
    generate_plot <- reactive({

      req(input$goPlot) 

      # Create 0-row data frame which will be used to store data
      dat <- data.frame(x = numeric(0), y = numeric(0))

      withProgress(message = 'Making plot', value = 0, {
        # Number of times we'll go through the loop
        n <- 10

        for (i in 1:n) {
          # Each time through the loop, add another row of data. This is
          # a stand-in for a long-running computation.
          dat <- rbind(dat, data.frame(x = rnorm(1), y = rnorm(1)))

          # Increment the progress bar, and update the detail text.
          incProgress(1/n, detail = paste("Doing part", i))

          # Pause for 0.1 seconds to simulate a long computation.
          Sys.sleep(1)
        }
      })

      plot(dat$x, dat$y)

    })
    output$plot <- renderPlot({
      generate_plot()
    })



  })
}

ui <- shinyUI(fluidPage(
  actionButton('goPlot', 'Go plot'),
  tabsetPanel(id = "inTabset",
              tabPanel("Plot"),
              tabPanel("Summary", plotOutput("plot"))

  )
)   

)

shinyApp(ui = ui, server = server)

Hope this helps!!

Upvotes: 2

Anders Ellern Bilgrau
Anders Ellern Bilgrau

Reputation: 10253

Not really an answer, I know, but I do not really understand why the following does not work. It ensures the correct execution order, but the problem persists. I guess the problem is the updates are not flushed before both have finished.

server <- function(input, output,session) {

  rv <- reactiveValues(goPlot_wait = 0)

  observeEvent(input$goPlot,{
    cat("A EXECUTED\n")
    updateTabsetPanel(session, "inTabset", selected = 'Summary')
    rv$goPlot_wait <- rv$goPlot_wait + 1
  })

  observeEvent(rv$goPlot_wait,{
    if(rv$goPlot_wait == 0) {
      return()
    }
    cat("B EXECUTED\n")

    output$plot <- renderPlot({
      # Create 0-row data frame which will be used to store data
      dat <- data.frame(x = numeric(0), y = numeric(0))

      withProgress(message = 'Making plot', value = 0, {
        # Number of times we'll go through the loop
        n <- 10

        for (i in 1:n) {
          # Each time through the loop, add another row of data. This is
          # a stand-in for a long-running computation.
          dat <- rbind(dat, data.frame(x = rnorm(1), y = rnorm(1)))

          # Increment the progress bar, and update the detail text.
          incProgress(1/n, detail = paste("Doing part", i))

          # Pause for 0.1 seconds to simulate a long computation.
          Sys.sleep(0.25)
        }
      })

      plot(dat$x, dat$y)
    })

  })
}

ui <- shinyUI(fluidPage(
  actionButton('goPlot', 'Go plot'),
  tabsetPanel(id = "inTabset",
              tabPanel("Plot", plotOutput("plot")),
              tabPanel("Summary"))))

shinyApp(ui = ui, server = server)

When running this app and pressing the button, I get:

> shinyApp(ui = ui, server = server)

Listening on http://127.0.0.1:6800
A EXECUTED
B EXECUTED

Yet the tabset is updated after the plot has rendered. Perhaps someone can shed some light on what is going on here.

Upvotes: 0

Related Questions