Search code examples
rshiny

ShinyApp: How to pass plot from one module into another one in order to download it in a report?


I want to generate a report that include a plot from another module, but my code does not work.

I have checked few examples from other shiny developers, but my code does not work.

As far as I understand, I need to:

(1) return the plot the plot module

(2) pass it to the download server

(3) also need to include it in the main server (I don't understand the logic here, I need your help for explanation)

My minimal example:

# Module 1,
plot_ui <- function(id) {
  ns <- NS(id)
  tagList(
    plotOutput(ns("plot"))
    )
  }

plot_server <- function(id) {
  moduleServer(id, function(input, output, session) {
    myplot <- reactive({plot(x = mtcars$wt, y = mtcars$mpg)})
    output$plot <-renderPlot({
      myplot()
    })
    return(myplot)
  })
}

# Module 2
download_ui <- function(id) {
  ns <- NS(id)
  tagList(
    downloadButton(outputId = ns("report_button"),
                   label = "Generate report"
                   )
    )
}

download_server <- function(id, myplot) {
  moduleServer(id, function(input, output, session){
    output$report_button<- downloadHandler(
      filename = "report.html",
      content = function(file) {
        tempReport <- file.path(tempdir(), "myRport.Rmd")
        file.copy("myReport.Rmd", tempReport, overwrite = TRUE)
        params <- list(plot1 = myplot())
        rmarkdown::render(tempReport,
                          output_file = file,
                          params = params
                          )
        }
      )
    }
  )
}


# Application
library(shiny)
app_ui <- function() {
  fluidPage(
    plot_ui("plot_ui_1"),
    download_ui("download_ui_2")
    )
}

app_server <- function(input, output, session) {
  getPlot <- plot_server("plot_ui_1")
  download_server("download_ui_2", myplot = getPlot)
}

shinyApp(app_ui, app_server)

My markdown file

---
title: "Test"
output: html_document
params:
  plot1: NA
---

```{r}
params$plot1
```

Solution

  • Basically you have done everything right. However, to make you code work you have to render your Rmd in a new environment by adding envir = new.env(parent = globalenv()) to rmarkdown::render. See e.g. Generating downloadable reports. Moreover TBMK you can't pass a base R plot to an Rmd via params, i.e. while your code works no plot will be displayed in the rendered report. That's why I switched to ggplot2:

    # Module 1,
    plot_ui <- function(id) {
      ns <- NS(id)
      tagList(
        plotOutput(ns("plot"))
      )
    }
    
    plot_server <- function(id) {
      moduleServer(id, function(input, output, session) {
        myplot <- reactive({
          #plot(x = mtcars$wt, y = mtcars$mpg)
          ggplot(mtcars, aes(wt, mpg)) +
            geom_point()
        })
        output$plot <-renderPlot({
          myplot()
        })
        return(myplot)
      })
    }
    
    # Module 2
    download_ui <- function(id) {
      ns <- NS(id)
      tagList(
        downloadButton(outputId = ns("report_button"),
                       label = "Generate report"
        )
      )
    }
    
    download_server <- function(id, myplot) {
      moduleServer(id, function(input, output, session){
        output$report_button<- downloadHandler(
          filename = "report.html",
          content = function(file) {
            tempReport <- file.path(tempdir(), "myRport.Rmd")
            file.copy("myReport.Rmd", tempReport, overwrite = TRUE)
            params <- list(plot1 = myplot())
            rmarkdown::render(tempReport,
                              output_file = file,
                              params = params,
                              envir = new.env(parent = globalenv())
            )
          }
        )
      }
      )
    }
    
    # Application
    library(shiny)
    library(ggplot2)
    
    app_ui <- function() {
      fluidPage(
        plot_ui("plot_ui_1"),
        download_ui("download_ui_2")
      )
    }
    
    app_server <- function(input, output, session) {
      getPlot <- plot_server("plot_ui_1")
      download_server("download_ui_2", myplot = getPlot)
    }
    
    shinyApp(app_ui, app_server)
    

    enter image description here