Зберігайте сюжети, зроблені в блискучому додатку


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 показано працює без помилок, але він не пише графіку.

Будемо вдячні за будь-які поради щодо завантаження HandHander, що працює над написанням сюжетів.

Відповіді:


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    

Оновлення

Починаючи з 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)замість створення функції пристрою (обгортки).
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 у вікнах для набагато приємнішої графіки у форматі PNG.

Будь ласка, додайте будь-які ваші пропозиції.


Без isolateблоку навколо input$filenameбудь-якої зміни в filenameтекстовому полі також буде запропоновано зберегти файл, якщо позначено поле.
jpd527

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 будь-яка ідея, чому ця спроба вивести в pdf подібний (не ggplot2) метод не працює? Я просто отримую непрацюючий PDF, який не відкривається. Чи не може plotInput доставити ділянку замість об’єкта сюжету?
геотеорія

20

Це старе, але все-таки найпопулярніше, коли хтось погуглить "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.