3

When I want to render multiple outputs linked to a single observer, they are rendered after both outputs are calculated. If there is a long calculation between the outputs it takes a long time before all outputs are displayed.

Is it possible in a Shiny application to render outputs, linked to a single observer, individually or in parallel? Instead of waiting with rendering until all outputs are calculated.

Example

library(shiny)

ui <- fluidPage(
  actionButton('button', 'klik'),
  textOutput('first'),
  textOutput('second')
)

server <- function(input, output, session) {
  observeEvent({input$button},{
    output$first <- renderText({Sys.Date()})
    Sys.sleep(10)
    output$second <- renderText({Sys.Date()})
  })
}

shinyApp(ui, server)
2

1 Answer 1

2

Thanks to @BertilBaron I found out a way to avoid waiting for long calculations in R-Shiny. The article that I used can be found here.

Basically what you do is to run each process in parallel using the package future. With this package every time the user clicks on the button the calculation will be performed. So keep in mind that you have to build in a block for impatient users.

My working example

library(shiny)
library(promises)
library(future)
plan(multiprocess)

ui <- fluidPage(
  actionButton('button', 'klik'),
  textOutput('first'),
  textOutput('second')
)

server <- function(input, output) {
  nclicks <- reactiveVal(0)
  nclicks2 <- reactiveVal(0)
  result_val <- reactiveVal()
  result_val2 <- reactiveVal()

  observeEvent(input$button,{
    # Don't do anything if analysis is already being run
    if(nclicks() != 0 | nclicks2() != 0){
      showNotification("Already running analysis")
      return(NULL)
    }

    # Increment clicks and prevent concurrent analyses
    nclicks(nclicks() + 1)
    nclicks2(nclicks2() + 1)

    result <- future({
      # Long Running Task
      Sys.sleep(10)

      #Some results
      Sys.time()
    }) %...>% result_val()

    result2 <- future({
      #Some results
      Sys.time()
    }) %...>% result_val2()

    # Catch inturrupt (or any other error) and notify user
    result <- catch(result,
                    function(e){
                      result_val(NULL)
                      print(e$message)
                      showNotification(e$message)
                    })
    result2 <- catch(result2,
                    function(e){
                      result_val2(NULL)
                      print(e$message)
                      showNotification(e$message)
                    })

    # After the promise has been evaluated set nclicks to 0 to allow for anlother Run
    result <- finally(result,
                      function(){
                        nclicks(0)
                      })
    result2 <- finally(result2,
                      function(){
                        nclicks2(0)
                      })

    # Return something other than the promise so shiny remains responsive
    NULL
  })

  output$first <- renderText({
    req(result_val())
  })
  output$second <- renderText({
    req(result_val2())
  })
}

# Run the application 
shinyApp(ui = ui, server = server)
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.