Сохраняйте графики, сделанные в блестящем приложении


85

Я пытаюсь понять, как использовать downloadButton для сохранения сюжета с помощью shiny. Пример в пакете демонстрирует 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 для написания графиков.

Ответы:


69

Не уверен, что этот вопрос все еще активен, но это первый вопрос, который возник при поиске «сохранение графиков в блестящем приложении», поэтому я хотел быстро добавить, как заставить ggsave работать с downloadHandler в соответствии со строками исходного вопроса.

Альтернативные стратегии, предложенные juba с использованием прямого вывода вместо ggsave, и альтернативная стратегия, предложенная самим alexwhan, отлично работают, это как раз для тех, кто абсолютно хочет использовать ggsave в downloadHandler).

Проблема, о которой сообщил 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функцию для того, pngчто ggsaveправопреемников внутренне (вы можете посмотреть на ggsaveфункцию коде , чтобы увидеть синтаксис jpg, pdfи т.д.). Возможно, в идеале можно было бы указать расширение файла (если оно отличается от имени файла - как в случае с временным файлом) в качестве 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    

Обновить

Начиная с версии 2.0.0 ggplot2, 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)вместо создания функции устройства (оболочки).
— Yihui Xie

@sebkopf Я пропустил ваш ответ за год с небольшим!
— alexwhan

1
@Yihui Это решение не работает для меня: R версии 3.1.0, ggplot2_1.0.0 shiny_0.10.1. Появится окно «Сохранить», нажмите «Сохранить», но файл не сохраняется. Кто-нибудь может подтвердить?
— zx8754

3
@ zx8754 Я только что добавил к ответу полный пример. Обратите внимание, что вы должны запускать его в своем веб-браузере, а не просматривать в 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$plotфункции reactivePlot:

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

Затем пользователь может ввести желаемое имя файла в текстовое поле (без расширения) и установить флажок, чтобы сохранить его в каталоге приложения. При снятии флажка график снова печатается. Я уверен, что есть более изящные способы сделать это, но, по крайней мере, теперь я могу использовать ggsave и cairo в Windows для гораздо более красивой графики в формате png.

Пожалуйста, добавьте любые предложения, которые у вас могут быть


Без isolateблока вокруг input$filename, любое изменение в filenameтекстовом поле также будет запрашивать сохранение файла, если этот флажок установлен.
— jpd527 03

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()
    })

Обратите внимание, что у меня были проблемы с версией shiny 0.3, но она работает с последней версией от Github:

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

Хорошо, я собираюсь согласиться с тем, что ggsave не будет работать на данном этапе разбирательства с downloadHandler. shiny 0.3 разваливается с downloadHandler, вы правы. Я опубликую альтернативное решение, которое я выяснил, избегая downloadHandler, которое позволит ggsave работать.
— alexwhan

1
@juba есть идеи, почему эта попытка вывода в PDF с помощью аналогичного метода (не ggplot2) не работает? У меня просто сломанный PDF-файл, который не открывается. Может ли plotInput не выдавать сюжет вместо сюжетного объекта?
— geotheory 03

20

Это старый, но по-прежнему самый популярный вариант, когда кто-то набирает в Google «R shiny save ggplot», поэтому я предложу другой обходной путь. Очень просто ... вызовите ggsave в той же функции, которая отображает ваш график, которая сохранит график как файл на сервере.

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

Затем используйте downloadHandler и используйте file.copy()для записи данных из существующего файла в параметр «файл».

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

Работает на меня.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.