Generating downloadable reports

After interacting with a Shiny application and getting it certain state, your users may want to download a report in HTML or PDF format. You can easily add the ability to generate a report with knitr and rmarkdown at the click of a button.
Author

Winston Chang

Published

July 1, 2016

After interacting with a Shiny application and getting it certain state, your users may want to download a report in HTML or PDF format. You can easily add the ability to generate a report with knitr and rmarkdown at the click of a button.

There are two key parts for this:

Example

This app takes one input value, and passes it as a parameter to an .Rmd document, which is rendered (or knitted) into an HTML output file. You can see this app in action here.

app.R:

```{r}
shinyApp(
  ui = fluidPage(
    sliderInput("slider", "Slider", 1, 100, 50),
    downloadButton("report", "Generate report")
  ),
  server = function(input, output) {
    output$report <- downloadHandler(
      # For PDF output, change this to "report.pdf"
      filename = "report.html",
      content = function(file) {
        # Copy the report file to a temporary directory before processing it, in
        # case we don't have write permissions to the current working dir (which
        # can happen when deployed).
        tempReport <- file.path(tempdir(), "report.Rmd")
        file.copy("report.Rmd", tempReport, overwrite = TRUE)

        # Set up parameters to pass to Rmd document
        params <- list(n = input$slider)

        # Knit the document, passing in the `params` list, and eval it in a
        # child of the global environment (this isolates the code in the document
        # from the code in this app).
        rmarkdown::render(tempReport, output_file = file,
          params = params,
          envir = new.env(parent = globalenv())
        )
      }
    )
  }
)
```

report.Rmd:

---
title: "Dynamic report"
output: html_document
params:
  n: NA
---

```{r}
# The `params` object is available in the document.
params$n
```

A plot of `params$n` random points.

```{r}
plot(rnorm(params$n), rnorm(params$n))
```

Note that due to an issue in the rmarkdown package, the default value of a parameter in the YAML header cannot be NULL, so we’ve used NA as the default value of n.

Notes

The rmarkdown::render() function has many options to control the processing and output. See the rmarkdown website to learn more. Some commonly used options are described below.

By default, an HTML file generated by rmarkdown::render() will have all plots and other images embedded directly in the HTML, so you can simply publish or send the HTML file, without needing to handle separate image files.

If you want PDF output, the rmarkdown::render() function can do that. This will require two changes:

  • Change the filename argument of downloadHandler() to "report.pdf".
  • Use output: pdf_document in the YAML header of the Rmd file.

It will also require pdflatex to be installed on your system.

Another way to generate a PDF is to pass in a value to output_format argument of rmarkdown::render(), as demonstrated in this app.

To generate a Microsoft Word document:

  • Change the filename argument of downloadHandler() to "report.doc".
  • Use output: word_document in the YAML header of the Rmd file.

When calling rmarkdown::render, it is possible for the Rmd document to directly access variables that are available to the Shiny app, including input values like input$slider. This can be done by using the default value for envir (instead of passing in a new environment). However, we recommend passing in params and using a new envir, because it provides better code isolation and makes things easier to debug.