Search code examples
rshinyr-markdownprogress-barknitr

R Shiny progress bar for R Mardown HTML rendering


I have an R Shiny app which prompts the user to input a dataset and click a download button to generate an R Markdown report based on that dataset. The bulk of the data transformations are made on the .rmd file, all that the shiny server is doing really is collecting inputs as parameters for RMarkdown and and rendering it as html.

Is it possible to implement any kind of progress bar? I've tried to incorporate withProgress() but there's nothing that increments in my server code to feed on to it. Ideally I'd be able to print the RStudio console messages with the chunks being knitted, but I'm really just after anything that will give some feedback to the user as some reports take very long to process.

Thanks in advance for any ideas.


Solution

  • You can use withProgress in the downloadHandler, and include some incProgress in the Rmd file:

    library(shiny)
    
    ui <- fluidPage(
      textInput("name", "Name", value = "Johan Rosa"),
      downloadButton("render", "Render report")
    )
    
    server <- function(input, output, session) {
      output$render <- downloadHandler(
        filename = function() "report.html",
        content = function(file) {
          withProgress(
            message = 'Calculation in progress',
            detail = 'This may take a while...', value = 0, {
              rmarkdown::render(
                input = "input.Rmd",
                output_file = file
              )
            }
          )
        }
      )
    }
    
    shinyApp(ui, server)
    

    input.Rmd:

    ---
    title: "render with progress"
    author: "Stéphane Laurent"
    date: "2024-02-28"
    output: html_document
    ---
    
    ```{r setup, include=FALSE}
    knitr::opts_chunk$set(echo = TRUE)
    library(shiny)
    ```
    
    ```{r}
    incProgress(1/3)
    Sys.sleep(2)
    ```
    
    ```{r}
    incProgress(1/3)
    Sys.sleep(2)
    ```
    
    ```{r}
    incProgress(1/3)
    Sys.sleep(2)
    ```