Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Outputting Shiny (non-ggplot) plot to PDF

Tags:

r

knitr

shiny

Is there a method to output (UI end) Shiny plots to PDF for the app user to download? I've tried various methods similar to those involving ggplot, but it seems downloadHandler can't operate in this way. For example the following just produces broken PDF's that don't open.

library(shiny)
runApp(list(
  ui = fluidPage(downloadButton('foo')),
  server = function(input, output) {
    plotInput = reactive({
      plot(1:10)
    })
    output$foo = downloadHandler(
      filename = 'test.pdf',
      content = function(file) {
        plotInput()
        dev.copy2pdf(file = file, width=12, height=8, out.type="pdf")
      })
  }
))

Very grateful for assistance.

like image 887
geotheory Avatar asked Dec 03 '14 16:12

geotheory


2 Answers

Solved. The plot should be saved locally with pdf(), not the screen device (as with dev.copy2pdf). Here's a working example: shiny::runGist('d8d4a14542c0b9d32786'). For a nice basic model try:

server.R

library(shiny)
shinyServer(
    function(input, output) {

        plotInput <- reactive({
            if(input$returnpdf){
                pdf("plot.pdf", width=as.numeric(input$w), height=as.numeric(input$h))
                plot(rnorm(sample(100:1000,1)))
                dev.off()
            }
            plot(rnorm(sample(100:1000,1)))
        })

        output$myplot <- renderPlot({ plotInput() })
        output$pdflink <- downloadHandler(
            filename <- "myplot.pdf",
            content <- function(file) {
                file.copy("plot.pdf", file)
            }
        )
    }
)

ui.R

require(shiny)
pageWithSidebar(
    headerPanel("Output to PDF"),
    sidebarPanel(
        checkboxInput('returnpdf', 'output pdf?', FALSE),
        conditionalPanel(
            condition = "input.returnpdf == true",
            strong("PDF size (inches):"),
            sliderInput(inputId="w", label = "width:", min=3, max=20, value=8, width=100, ticks=F),
            sliderInput(inputId="h", label = "height:", min=3, max=20, value=6, width=100, ticks=F),
            br(),
            downloadLink('pdflink')
        )
    ),
    mainPanel({ mainPanel(plotOutput("myplot")) })
)
like image 167
geotheory Avatar answered Oct 22 '22 19:10

geotheory


(Hello), just use pdf :

library(shiny)
runApp(list(
  ui = fluidPage(downloadButton('foo')),
  server = function(input, output) {
    plotInput = reactive({
      plot(1:10)
    })
    output$foo = downloadHandler(
      filename = 'test.pdf',
      content = function(file) {
        pdf(file = file, width=12, height=8)
        plotInput()
        dev.off()
      })
  }
))

EDIT : I don't know... It's weird. A workaround is to use dev.copy2pdf like you did in the first place but in the reactive function instead downloadHandler :

## server.R
library(shiny)
shinyServer(
  function(input, output) {
    plotInput <- reactive({plot(rnorm(1000))
                           dev.copy2pdf(file = "plot.pdf")
                           })
    output$myplot <- renderPlot({ plotInput() })
    output$foo <- downloadHandler(
      filename <- "plot.pdf",
      content <- function(file) {
        file.copy("plot.pdf", file)
      })
  }
)
like image 29
Victorp Avatar answered Oct 22 '22 19:10

Victorp