保存在闪亮的应用程序中绘制的图


85

我试图弄清楚如何使用downloadButton保存具有光泽的图。包中的示例演示了downloadButton / downloadHandler保存.csv的方法。我将基于此举一个可重复的示例。

对于 ui.R

shinyUI(pageWithSidebar(
  headerPanel('Downloading Data'),
  sidebarPanel(
selectInput("dataset", "Choose a dataset:", 
            choices = c("rock", "pressure", "cars")),
    downloadButton('downloadData', 'Download Data'),
    downloadButton('downloadPlot', 'Download Plot')
  ),
  mainPanel(
    plotOutput('plot')
  )
))

对于 server.R

library(ggplot2)
shinyServer(function(input, output) {
  datasetInput <- reactive({
    switch(input$dataset,
           "rock" = rock,
           "pressure" = pressure,
           "cars" = cars)
  })

  plotInput <- reactive({
    df <- datasetInput()
    p <-ggplot(df, aes_string(x=names(df)[1], y=names(df)[2])) +
      geom_point()
  })

  output$plot <- renderPlot({
    print(plotInput())
  })

  output$downloadData <- downloadHandler(
    filename = function() { paste(input$dataset, '.csv', sep='') },
    content = function(file) {
      write.csv(datatasetInput(), file)
    }
  )
  output$downloadPlot <- downloadHandler(
    filename = function() { paste(input$dataset, '.png', sep='') },
    content = function(file) {
      ggsave(file,plotInput())
    }
  )
})

如果您正在回答此问题,则可能对此很熟悉,但要使其正常工作,请将以上内容保存到单独的脚本中(ui.R以及工作目录中server.R的文件夹(foo)中)。要运行闪亮的应用程序,请运行runApp("foo")

使用ggsave,我收到一条错误消息,指示ggsave无法使用该filename功能(我认为)。如果我使用标准的图形设备(如下所示),则Download Plot可以正常工作,但不会写入图形。

任何使downloadHandler用于编写图的技巧都将受到赞赏。

Answers:


69

不知道这个问题是否仍然有效,但这是搜索“在闪亮的应用程序中保存情节”时出现的第一个问题,因此我想按照原始问题的方式快速添加如何使ggsave与downloadHandler一起使用。

juba建议的使用直接输出而不是ggsave的替代策略以及alexwhan自己提出的替代策略都可以很好地工作,这只适合那些绝对希望在downloadHandler中使用ggsave的用户。

alexwhan报告的问题是由ggsave尝试将文件扩展名匹配到正确的图形设备引起的。但是,该临时文件没有扩展名,因此匹配失败。这可以通过在ggsave函数调用中专门设置设备来解决,就像在原始代码示例(对于png)中一样:

output$downloadPlot <- downloadHandler(
    filename = function() { paste(input$dataset, '.png', sep='') },
    content = function(file) {
        device <- function(..., width, height) grDevices::png(..., width = width, height = height, res = 300, units = "in")
        ggsave(file, plot = plotInput(), device = device)
    }
)

这个调用基本上采用的device函数的pngggsave受让人内部(你可以看看ggsave功能代码来查看语法jpgpdf等)。也许,理想情况下,可以将文件扩展名(如果与文件名不同(如此处的临时文件所示))指定为ggsave参数,但是该选项当前在中不可用ggsave


一个最小的独立工作示例:

library(shiny)
library(ggplot2)
runApp(list(
  ui = fluidPage(downloadButton('foo')),
  server = function(input, output) {
    plotInput = function() {
      qplot(speed, dist, data = cars)
    }
    output$foo = downloadHandler(
      filename = 'test.png',
      content = function(file) {
        device <- function(..., width, height) {
          grDevices::png(..., width = width, height = height,
                         res = 300, units = "in")
        }
        ggsave(file, plot = plotInput(), device = device)
      })
  }
))

sessionInfo()
# R version 3.1.1 (2014-07-10)
# Platform: x86_64-pc-linux-gnu (64-bit)
# 
# locale:
#  [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C              
#  [3] LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8    
#  [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8   
#  [7] LC_PAPER=en_US.UTF-8       LC_NAME=C                 
#  [9] LC_ADDRESS=C               LC_TELEPHONE=C            
# [11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       
# 
# attached base packages:
# [1] stats     graphics  grDevices utils     datasets  methods   base     
# 
# other attached packages:
# [1] ggplot2_1.0.0 shiny_0.10.1 
# 
# loaded via a namespace (and not attached):
#  [1] bitops_1.0-6     caTools_1.17     colorspace_1.2-4 digest_0.6.4    
#  [5] formatR_1.0      grid_3.1.1       gtable_0.1.2     htmltools_0.2.6 
#  [9] httpuv_1.3.0     labeling_0.2     MASS_7.3-34      munsell_0.4.2   
# [13] plyr_1.8.1       proto_0.3-10     Rcpp_0.11.2      reshape2_1.4    
# [17] RJSONIO_1.3-0    scales_0.2.4     stringr_0.6.2    tools_3.1.1     
# [21] xtable_1.7-3    

更新资料

从ggplot2版本2.0.0开始,该ggsave函数支持该device参数的字符输入,这意味着可以通过直接调用来保存由downloadHandler创建的临时文件,方法是ggsave指定要使用的扩展名应为例如"pdf"(而不是传递在设备功能中)。这将上面的示例简化为以下示例

output$downloadPlot <- downloadHandler(
    filename = function() { paste(input$dataset, '.png', sep='') },
    content = function(file) {
        ggsave(file, plot = plotInput(), device = "png")
    }
)

1
我相信您的答案实际上是正确的答案。您也可以使用ggsave(file, plotInput(), device = png)而不是创建设备(包装器)功能。
Yiyi Xie

@sebkopf在接下来的一年中,我错过了您的答案!
alexwhan

1
@Yihui此解决方案不适用于我:R版本3.1.0,ggplot2_1.0.0 Shiny_0.10.1。弹出“保存”框,单击“保存”,但不保存文件。谁能确认?
zx8754 2014年

3
@ zx8754我刚刚在答案中添加了完整的示例。请注意,您应该在Web浏览器中运行它,而不是在RStudio中查看它,因为RStudio查看器存在无法下载文件的已知错误。
Yihui Xie

1
@sebkopf是的,我在尝试了一个真实示例后才意识到这一点,因此我在这里的第一条评论实际上是错误的。感谢您的澄清!
Yihui Xie

24

这是一个允许使用ggsave保存闪亮图的解决方案。它使用逻辑复选框和文本输入来调用ggsave()。将此添加到ui.R文件中sidebarPanel

textInput('filename', "Filename"),
checkboxInput('savePlot', "Check to save")

然后将其添加到server.R文件中,而不是当前的output$plotreactPlot函数:

output$plot <- reactivePlot(function() {
    name <- paste0(input$filename, ".png")
    if(input$savePlot) {
      ggsave(name, plotInput(), type="cairo-png")
    }
    else print(plotInput())
  })

然后,用户可以在文本框中键入所需的文件名(不带扩展名),然后选中复选框以保存在应用程序目录中。取消选中该框将再次打印该图。我敢肯定有更整齐的方法可以做到这一点,但是至少我现在可以在Windows中使用ggsave和cairo来获得更好的png图形。

请添加您可能有的任何建议。


如果没有isolate各地块input$filename,任何改变filename文本框也会提示文件保存,如果复选框被选中。
jpd527 2014年

23

我没有设法使其与一起使用ggsave,但是通过标准调用png()它似乎还可以。

我只更改了文件的output$downloadPlot一部分server.R

 output$downloadPlot <- downloadHandler(
    filename = function() { paste(input$dataset, '.png', sep='') },
    content = function(file) {
      png(file)
      print(plotInput())
      dev.off()
    })

请注意,我在使用0.3版本的Shiny时遇到了一些问题,但是它可以与Github的最新版本一起使用:

library(devtools)
install_github("shiny","rstudio")

好的,我将接受ggsave在downloadHandler的当前程序阶段不起作用。闪亮的0.3与downloadHandler分离,您是对的。我将发布一个替代解决方案,我发现它避免了downloadHandler,它将允许ggsave工作。
alexwhan

1
@juba知道为什么尝试使用类似的(non-ggplot2)方法输出到pdf的尝试无效吗?我只是得到了一个无法打开的损坏的pdf文件。plotInput不能传递图而不是图对象吗?
geotheory 2014年

20

这很旧,但是当有人用谷歌搜索“ R Shiny save ggplot”时仍然是热门话题,所以我将提供另一个解决方法。非常简单...在显示图形的同一函数中调用ggsave,它将图形另存为服务器上的文件。

output$plot <- renderPlot({
    ggsave("plot.pdf", plotInput())
    plotInput()
})

然后,使用downloadHandler并用于file.copy()将数据从现有文件写入“ file”参数。

output$dndPlot <- downloadHandler(
    filename = function() {
        "plot.pdf"
    },
    content = function(file) {
        file.copy("plot.pdf", file, overwrite=TRUE)
    }
)

为我工作。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.