Search code examples
rshinyr-markdownshinyapps

Rmarkdown - cannot render image in html report when downloaded from shiny apps


I'm trying to make a "downloadable html report" from my shiny app, however when I deploy the app to shinyapps.io and try to download the report, it fails because I can't render the image in the R markdown file. It works fine locally, which means I think the issue is to do with the relative file path.

Short example made for ease:

app.R

library(shiny)
library(dplyr)
library(tidyverse)
library(knitr)
library(here)


#load pca plots from working directory
pca <- list.files(pattern="*pca_check.png")
#move file to www folder for it to render correctly
dir.create("www")
file.copy(pca[[1]], "www")

#pca[[1]] is "sept_2021.pca_check.png"


##################
# Make Shiny App #
##################

ui <- fluidPage(titlePanel("QC output"),
                navbarPage("Menu",
                           tabPanel("Report",
                                    sidebarLayout(
                                      sidebarPanel(downloadButton("report", "Generate report"), width=0
                                      ),
                                      mainPanel(tags$h2("Ancestry prediction Peddy"),
                                                a(img(src=pca[[1]], height = 500, width = 300, slign="center",
                                                      target="_blank"),
                                                  href=pca[[1]])
                                                )))))
                           
                          

server <- function(input, output) {
  
  output$report <- downloadHandler(
    # For PDF output, change this to "report.pdf"
    filename = "report.html",
    content = function(file) {
      tempReport <- file.path(tempdir(), "report.Rmd")
      file.copy("report.Rmd", tempReport, overwrite = TRUE)
      
      # Set up parameters to pass to Rmd document
      params <- list(pca = pca[[1]])
      
      rmarkdown::render(tempReport, output_file = file,
                        params = params,
                        envir = new.env(parent = globalenv())
      )
    }
  )
}

shinyApp(ui = ui, server = server)

NB: the image displays fine in the app when using this code:

a(img(src=pca[[1]], height = 500, width = 300, slign="center",
                                                      target="_blank"),
                                                  href=pca[[1]])

However, when generating the report, it fails...

report.Rmd

---
title: "Dynamic report"
output: html_document
params:
  pca: NULL
---

PCA plot
```{r out.width="70%"}
knitr::include_graphics(here::here(pca))```

If it don't use here::here(pca) the code fails locally. However it's clearly giving the wrong path when deployed. So, instead I tried just:

knitr::include_graphics(pca)

That still fails when deployed. The full app is here: https://lecb.shinyapps.io/QC_sept_21/ and the image in question was successfully uploaded to https://lecb.shinyapps.io/QC_sept_21/sept_2021.pca_check.png, which implies I am referring to the correct directory... perhaps the markdown doesn't know what the "working directory" is?

Anyone have any idea how to get the image to render in the downloadable report please?

Many thanks!


Solution

  • knitr::rendr treats the folder where the .Rmd file sits as root. You are copying your report.Rmd to a temp folder. Thus, copying your png to the same temp folder and referencing it without here should do the trick remotely and locally:

    Untested code snippet:

      output$report <- downloadHandler(
        # For PDF output, change this to "report.pdf"
        filename = "report.html",
        content = function(file) {
          tmp_dir <- tempdir()
          tempReport <- file.path(tmp_dir, "report.Rmd")
          tmp_pic <- file.path(tmp_dir, pca[[1]])
          file.copy("report.Rmd", tempReport, overwrite = TRUE)
          file.copy(pca[[1]], tmp_pic, overwrite = TRUE)
          # Set up parameters to pass to Rmd document
          params <- list(pca = pca[[1]])
          
          rmarkdown::render(tempReport, output_file = file,
                            params = params,
                            envir = new.env(parent = globalenv())
          )
        }
      )
    

    and

    ---
    title: "Dynamic report"
    output: html_document
    params:
      pca: NULL
    ---
    
    PCA plot
    ```{r out.width="70%"}
    knitr::include_graphics(params$pca)
    ```