Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

R shiny: display "loading..." message while function is running

Tags:

r

shiny

People also ask

How do you show a message in shiny?

Simply call shinyalert() with the desired arguments, such as a title and text, and a modal will show up. In order to be able to call shinyalert() in a Shiny app, you must first call useShinyalert() anywhere in the app's UI.

How do you enter shiny data?

To add an input in a Shiny app, we need to place an input function *Input() in the ui object. Each input function requires several arguments. The first two are inputId , an id necessary to access the input value, and label which is the text that appears next to the input in the app.

What is the purpose of the shinyApp () function?

shinyApp is a function that builds Shiny apps. You can use shinyApp to define a complete app in a single R script, or even at the command line. shinyApp builds an app from two arguments that parallel the structure of a standard Shiny app.


I'm already using a simpler and more reliable way than the one I posted before.

A combination of

tags$style(type="text/css", "
           #loadmessage {
             position: fixed;
             top: 0px;
             left: 0px;
             width: 100%;
             padding: 5px 0px 5px 0px;
             text-align: center;
             font-weight: bold;
             font-size: 100%;
             color: #000000;
             background-color: #CCFF66;
             z-index: 105;
           }
  ")

with

conditionalPanel(condition="$('html').hasClass('shiny-busy')",
                 tags$div("Loading...",id="loadmessage")
)

Example:

runApp(list(
  ui = pageWithSidebar(
      headerPanel("Test"),
         sidebarPanel(
           tags$head(tags$style(type="text/css", "
             #loadmessage {
               position: fixed;
               top: 0px;
               left: 0px;
               width: 100%;
               padding: 5px 0px 5px 0px;
               text-align: center;
               font-weight: bold;
               font-size: 100%;
               color: #000000;
               background-color: #CCFF66;
               z-index: 105;
             }
          ")),
           numericInput('n', 'Number of obs', 100),
           conditionalPanel(condition="$('html').hasClass('shiny-busy')",
                            tags$div("Loading...",id="loadmessage"))
         ),
         mainPanel(plotOutput('plot'))
  ),
  server = function(input, output) {
    output$plot <- renderPlot({ Sys.sleep(2); hist(runif(input$n)) })
  }
))

tags$head() is not required, but it's a good practice to keep all the styles inside head tag.


Very simply, you can use built-in shiny functions showModal() at the start of the function and removeModal() at the end. If you remove the footer, said modal cannot be clicked out of.

Example:

observeEvent(input$button, {
     showModal(modalDialog("Doing a function", footer=NULL))
     #Do the stuff here....
     #...
     #...
     #Finish the function
     removeModal()
})

I solved the problem by adding the following code to sidebarPanel():

HTML('<script type="text/javascript">
        $(document).ready(function() {
          $("#DownloadButton").click(function() {
            $("#Download").text("Loading...");
          });
        });
      </script>
')

You can use ShinyJS: https://github.com/daattali/shinyjs

When the actionButton is pressed, you can easily toggle a text component showing "loading...", and when the calculation is finished, you can then toggle this component to hidden.


Though this question is old I think it is still relevant. I have another solution to offer that displays the activity indicator on the button that starts a lengthy process next to the button label.

Button with an activity indicator

We need an action button with a label in a span and some way of identifying that label.

actionButton("btnUpdate", span("Update", id="UpdateAnimate", class=""))

We also need some CSS animation that can be added to the button label, e.g. like this:

            tags$head(tags$style(type="text/css", '
            .loading {
                display: inline-block;
                overflow: hidden;
                height: 1.3em;
                margin-top: -0.3em;
                line-height: 1.5em;
                vertical-align: text-bottom;
                box-sizing: border-box;
            }
            .loading.dots::after {
                text-rendering: geometricPrecision;
                content: "⠋\\A⠙\\A⠹\\A⠸\\A⠼\\A⠴\\A⠦\\A⠧\\A⠇\\A⠏";
                animation: spin10 1s steps(10) infinite;
                animation-duration: 1s;
                animation-timing-function: steps(10);
                animation-delay: 0s;
                animation-iteration-count: infinite;
                animation-direction: normal;
                animation-fill-mode: none;
                animation-play-state: running;
                animation-name: spin10;
            }
            .loading::after {
                display: inline-table;
                white-space: pre;
                text-align: left;
            }
            @keyframes spin10 { to { transform: translateY(-15.0em); } }
            '))

Now we can use shinyjsto manipulate the span class which dynamically adds the animation behind the button label. We add the animation once a user presses the button:

    observeEvent(input$btnUpdate, { # User requests update
        # ... 

        shinyjs::addClass(id = "UpdateAnimate", class = "loading dots")
        shinyjs::disable("btnUpdate")
        
        # ...
    })

When the operation has finished we can remove the class from the span and end the animation:

    output$distPlot <- renderPlot({
        # ...
        
        Sys.sleep(1) # just for show, you probably want to remove it in a real app
        # Button settings        
        shinyjs::enable("btnUpdate")
        shinyjs::removeClass(id = "UpdateAnimate", class = "loading dots")

        # ...
    })

The full code of the sample app is available as gist on GitHub.