1

This question is quite basic and related to some questions before How to save reactive plot as png to working directory in a shiny app

I had to change my strategy creating a plot from a shiny app in Rmarkdown.

For this I need to accomplish this simple task:

How can I save this plot to the temp folder as png?

Background: After saving to temp folder I will transfer it to R markdown to create a report.

library(shiny)

ui <- basicPage(
  plotOutput("plot1"),
)

server <- function(input, output) {
  output$plot1 <- renderPlot({
    plot(mtcars$wt, mtcars$mpg)
  })
}
shinyApp(ui, server)

Update: My original code looks like this. I can't provide a reproducible example with this because it is to complex:

How can I implement the answer by ismirsehregal to this code:

# plot: Radarplot ------

output$radar <- renderChartJSRadar({
  chartJSRadar(PSA_13()[,c(1,2,6)],
               main = "XXX",
               maxScale = 100, scaleStepWidth = 10, scaleStartValue = 0, labelSize = 12, 
               addDots = TRUE, showToolTipLabel = TRUE, showLegend = TRUE, lineAlpha = 0.8, 
               polyAlpha = 0.2, responsive = FALSE, 
               colMatrix = col2rgb(c("orange", "navy" ,"grey")))
})

# create markdown report with radar plot ----------------------------------

output$report <- downloadHandler(
  filename = "report.pdf",
    content = function(file) {
      td <- tempdir()
      tempReport <- file.path(td, "report.Rmd")
      tempLogo <- file.path(td, "logo.png")
      file.copy("report.Rmd", tempReport, overwrite = TRUE)
      file.copy("logo.png", tempLogo, overwrite = TRUE)
    
    params <- list(scores = PSA_13()[,c(1,2,6)])
                   
    
    rmarkdown::render(tempReport, output_file = file,
                      params = params,
                      envir = new.env(parent = globalenv())
    )
  }
)

report.Rmd

    ---
geometry: margin=20truemm
fontfamily: mathpazo
fontsize: 11pt
documentclass: article
classoption: a4paper
urlcolor: blue
output: 
    pdf_document
header-includes:
   - \usepackage{fancyhdr}
   - \pagestyle{fancy}
   - \rhead{\includegraphics[width = .05\textwidth]{logo.png}}
params: 
    scores: NA
    plot_object: NA
---
\pagenumbering{gobble}

```{r setup, include=FALSE}
knitr::opts_chunk$set()
library(draw)
```

```{r rectangle, echo=FALSE}
drawBox(x =1.3, y = 3.7, width = 2.5, height = 1)
```

\vspace{-80truemm}

```{r plotout, echo=FALSE, message=FALSE, out.width='100%'}
params$plot_object
```


<!-- ```{r, echo=FALSE, out.width="100%", } -->
<!-- chartJSRadar(params$scores, width = 700, height = 700, -->
<!--              main = "Peritoneal Surface Calculator Radarchart", -->
<!--              maxScale = 100, -->
<!--              scaleStepWidth = 10, -->
<!--              scaleStartValue = 0, -->
<!--              labelSize = 14, -->
<!--              addDots = TRUE, -->
<!--              showToolTipLabel = FALSE, -->
<!--              showLegend = TRUE, -->
<!--              lineAlpha = 0.8, -->
<!--              polyAlpha = 0.2, -->
<!--              responsive = FALSE, -->
<!--              colMatrix = col2rgb(c("orange", "navy" ,"grey"))) -->
<!-- ``` -->

I feel quite near to the solution and I am very grateful for your time!

TarJae
  • 72,363
  • 6
  • 19
  • 66

3 Answers3

2

There is no need to save a temporary png file. We can use recordPlot instead:

library(shiny)
library(datasets)

writeLines(con = "report.Rmd", text = "---
title: 'Plot report'
output: html_document
params:
  plot_object: NA
---

```{r plotout, echo=FALSE, message=FALSE, out.width='100%'}
params$plot_object
```")

ui = fluidPage(
  plotOutput("plot1"),
  downloadButton("report_button", "Generate report")
)

server = function(input, output, session) {
  reactivePlot1 <- reactive({
    plot(mtcars$wt, mtcars$mpg)
    recordPlot()
  })
  
  output$plot1 <- renderPlot({
    reactivePlot1()
  })
  
  output$report_button <- downloadHandler(
    filename = "report.html",
    content = function(file) {
      tempReport <- tempfile(fileext = ".Rmd") # make sure to avoid conflicts with other shiny sessions if more params are used
      file.copy("report.Rmd", tempReport, overwrite = TRUE)
      rmarkdown::render(tempReport, output_format = "html_document", output_file = file, output_options = list(self_contained = TRUE),
                        params = list(plot_object = reactivePlot1())
      )
    }
  )
}

shinyApp(ui, server)

Please see my related answer here.


After OPs update - using dummy data:

app.R:

library(shiny)
library(radarchart)

scores <- data.frame("Label"=c("Communicator", "Data Wangler", "Programmer",
                               "Technologist",  "Modeller", "Visualizer"),
                     "Rich" = c(9, 7, 4, 5, 3, 7),
                     "Andy" = c(7, 6, 6, 2, 6, 9),
                     "Aimee" = c(6, 5, 8, 4, 7, 6))

ui = fluidPage(
  chartJSRadarOutput("radar", width = "450", height = "300"),
  downloadButton("report", "Generate report")
)

server = function(input, output, session) {
  reactiveRadar <- reactive({
    chartJSRadar(scores, maxScale = 10, showToolTipLabel=TRUE)
  })
  
  # plot: Radarplot ------
  output$radar <- renderChartJSRadar({
    reactiveRadar()
  })
  
  # create markdown report with radar plot ----------------------------------
  
  output$report <- downloadHandler(
    filename = "report.html",
    content = function(file) {
      td <- tempdir()
      tempReport <- file.path(td, "report.Rmd")
      # tempLogo <- file.path(td, "logo.png")
      file.copy("report.Rmd", tempReport, overwrite = TRUE)
      # file.copy("logo.png", tempLogo, overwrite = TRUE)
      
      params <- list(scores = "Test", plot_object = reactiveRadar()) # scores = PSA_13()[,c(1,2,6)]
      
      rmarkdown::render(tempReport, output_file = file,
                        params = params,
                        envir = new.env(parent = globalenv())
      )
    }
  )
}

shinyApp(ui, server)

report.Rmd:

---
geometry: margin=20truemm
fontfamily: mathpazo
fontsize: 11pt
documentclass: article
classoption: a4paper
urlcolor: blue
output: 
    html_document
header-includes:
   - \usepackage{fancyhdr}
   - \pagestyle{fancy}
   # - \rhead{\includegraphics[width = .05\textwidth]{logo.png}}
params: 
    scores: NA
    plot_object: NA
---
\pagenumbering{gobble}

```{r setup, include=FALSE}
knitr::opts_chunk$set()
library(draw)
```

```{r rectangle, echo=FALSE}
drawBox(x =1.3, y = 3.7, width = 2.5, height = 1)
```

\vspace{-80truemm}

```{r plotout, echo=FALSE, message=FALSE, out.width='100%'}
params$plot_object
```
ismirsehregal
  • 30,045
  • 5
  • 31
  • 78
1

There are multiple options here. In your case you could go with a simple option like this:

library(shiny)

ui <- basicPage(
  plotOutput("plot1"),
  actionButton("save", "Click to save")
)

server <- function(input, output) {
  output$plot1 <- renderPlot({
    plot(mtcars$wt, mtcars$mpg)
  })
  
  
  observeEvent("save", {
    png('C:/path/to/your_plot/plot_saved.png')
    plot(mtcars$wt, mtcars$mpg)
    dev.off()
  })
  
  
}
shinyApp(ui, server)

If you want to specify size, resolution, etc. you will have to customize the code within the observeEvent

fschier
  • 180
  • 10
1

The shinyscreenshot library seems like a good option. similar to fschier answer, but this will work with interactive plot elements as well.

library(shiny)
library(shinyscreenshot) 

ui <- basicPage(
  actionButton("screenshot2", "Capture plot"),
  plotOutput("plot1")
  
)

server <- function(input, output) {
  output$plot1 <- renderPlot({
    plot(mtcars$wt, mtcars$mpg)
  })
  observeEvent(input$screenshot2, {
    screenshot(id = "plot1",
               filename = "image1",
               server_dir = ".")
  })
}
shinyApp(ui, server)

The server_dir parameter defines where the image is saved. In this example the file image1.png will be save in your local directory. ".png" is automatically added to the filename parameter. Once written out file can be read into your rmd document as any image would.

carverd
  • 196
  • 1
  • 9