Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generate progress bar in modal in shiny app, that closes automatically

I am working on a shiny app that takes a long time to do calculations, I want to have a modal progress bar that closes automatically as soon as all calculations work.

The ideal solution would have two features

  1. Covers most of the screen and prevents the user to interact with app
  2. Closes automatically as soon as it finishes making calulations

I found this solution in the following question:

library("shiny")
library("shinyWidgets")

ui <- fluidPage(
  actionButton(inputId = "go", label = "Launch long calculation"), #, onclick = "$('#my-modal').modal().focus();"

  # You can open the modal server-side, you have to put this in the ui :
  tags$script("Shiny.addCustomMessageHandler('launch-modal', function(d) {$('#' + d).modal().focus();})"),
  tags$script("Shiny.addCustomMessageHandler('remove-modal', function(d) {$('#' + d).modal('hide');})"),

  # Code for creating a modal
  tags$div(
id = "my-modal",
class="modal fade", tabindex="-1", `data-backdrop`="static", `data-keyboard`="false",
tags$div(
  class="modal-dialog",
  tags$div(
    class = "modal-content",
    tags$div(class="modal-header", tags$h4(class="modal-title", "Calculation in progress")),
    tags$div(
      class="modal-body",
      shinyWidgets::progressBar(id = "pb", value = 0, display_pct = TRUE)
    ),
    tags$div(class="modal-footer", tags$button(type="button", class="btn btn-default", `data-dismiss`="modal", "Dismiss"))
  )
)
  )
)

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

   value <- reactiveVal(0)

  observeEvent(input$go, {
    shinyWidgets::updateProgressBar(session = session, id = "pb", value = 0) # reinitialize to 0 if you run the calculation several times
session$sendCustomMessage(type = 'launch-modal', "my-modal") # launch the modal
    # run calculation
    for (i in 1:10) {
      Sys.sleep(0.5)
      newValue <- value() + 1
      value(newValue)
      shinyWidgets::updateProgressBar(session = session, id = "pb", value = 100/10*i)
}
    Sys.sleep(0.5)
    # session$sendCustomMessage(type = 'remove-modal', "my-modal") # hide the modal programmatically
  })

}

shinyApp(ui = ui, server = server)

This solves issue 1, but I have to click on dismiss to see the results

like image 995
Derek Corcoran Avatar asked Sep 30 '18 02:09

Derek Corcoran


2 Answers

The original progressbar provided in shiny is exactly what you need.

But I use css to make the progessbar display in the middle in the screen.

You can find the detail of using progress bar in shiny here.

library("shiny")

ui <- fluidPage(
  actionButton(inputId = "go", label = "Launch long calculation"), #, onclick = "$('#my-modal').modal().focus();"

  # css to center the progress bar
  tags$head(
    tags$style(
      HTML(".shiny-notification {
           height: 100px;
           width: 800px;
           position:fixed;
           top: calc(50% - 50px);
           left: calc(50% - 400px);
           font-size: 250%;
           text-align: center;
           }
           "
      )
    )
  )
)

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

  value <- reactiveVal(0)

  observeEvent(input$go, {
    withProgress(message = 'Calculation in progress', value = 0,detail="0%", {
      # run calculation
      for (i in 1:10) {
        Sys.sleep(0.5)
        newValue <- value() + 1
        value(newValue)
        incProgress(1/10,detail = paste0(i*10,"%"))
      }
      Sys.sleep(0.5)
    })
  })

}

shinyApp(ui = ui, server = server)
like image 80
Jim Chen Avatar answered Nov 02 '22 07:11

Jim Chen


Not a whole answer, just answering the additional css requests. You could change the css to, which will make the panel fill up the whole page.

.shiny-notification {
  height: 100%;
  width: 100%; 
  top: 0;
  left: 0;
  position:fixed;
  font-size: 250%;
  text-align: center;
  background-color: rgba(0, 0, 0, 0.7);
  color: white;
}
like image 21
SeGa Avatar answered Nov 02 '22 07:11

SeGa