Pregunta Guarde las parcelas en una aplicación brillante


Estoy tratando de averiguar cómo usar downloadButton para guardar una trama con brillante. El ejemplo en el paquete muestra downloadButton / downloadHandler para guardar un .csv. Voy a hacer un ejemplo reproducible basado en eso.

por 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')
  )
))

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

Si está respondiendo esta pregunta, probablemente esté familiarizado con esto, pero para que esto funcione, guarde lo anterior en scripts separados (ui.R y server.R en una carpeta (foo) dentro del directorio de trabajo. Para ejecutar la aplicación brillante, ejecuta runApp("foo").

Utilizando ggsave, Aparece un mensaje de error que indica que ggsave no puede usar filename función (creo). Si uso el dispositivo gráfico estándar (como a continuación), Download Plot funciona sin un error, pero no escribe el gráfico.

Se agradecerá cualquier sugerencia para obtener downloadHandler trabajando para escribir tramas.


67
2018-02-11 10:36


origen


Respuestas:


No estoy seguro de si esta pregunta aún está activa, pero es la primera que surgió cuando buscaba "guardar tramas en una aplicación brillante", así que quería agregar rápidamente cómo hacer que ggsave funcione con downloadHandler siguiendo las líneas de la pregunta original.

Las estrategias alternativas sugeridas por juba usando output directo en lugar de ggsave y la estrategia alternativa sugerida por el propio alexwhan funcionan muy bien, esto es solo para aquellos que desean usar ggsave en el downloadHandler.

El problema informado por alexwhan es causado por ggsave tratando de hacer coincidir la extensión del archivo con el dispositivo gráfico correcto. Sin embargo, el archivo temporal no tiene una extensión, por lo que la coincidencia falla. Esto se puede remediar configurando específicamente el dispositivo en ggsave llamada de función, como en el ejemplo del código original (para un 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)
    }
)

Esta llamada básicamente toma el device función para un png ese ggsave asigna internamente (puede mirar el ggsave código de función para ver la sintaxis de jpg, pdf, etc.) Quizás, idealmente, se podría especificar la extensión del archivo (si es diferente del nombre del archivo, como es el caso aquí para el archivo temporal) como una ggsave parámetro pero esta opción no está disponible actualmente en ggsave.


Un ejemplo mínimo de trabajo autónomo:

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    

Actualizar

A partir de ggplot2 versión 2.0.0, el ggsave la función admite la entrada de caracteres para device parámetro, eso significa que el archivo temporal creado por el downloadHandler ahora se puede guardar con una llamada directa a ggsave especificando que la extensión que se utilizará debe ser, p. "pdf" (en lugar de pasar una función de dispositivo). Esto simplifica el ejemplo anterior a lo siguiente

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

44
2018-04-06 22:54



Aquí hay una solución que permite usar ggsave para guardar tramas brillantes. Utiliza una casilla de verificación lógica y entrada de texto para llamar ggsave(). Añadir esto a la ui.R archivo dentro sidebarPanel:

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

Luego agrega esto a la server.R archivo en lugar de la actual output$plot función reactivePlot:

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

Un usuario puede escribir el nombre de archivo deseado en el cuadro de texto (sin extensión) y marcar la casilla de verificación para guardar en el directorio de la aplicación. Al deseleccionar la casilla, se imprime la trama nuevamente. Estoy seguro de que hay formas más claras de hacerlo, pero al menos ahora puedo usar ggsave y cairo en windows para obtener gráficos png mucho más agradables.

Por favor agregue cualquier sugerencia que pueda tener.


21
2018-02-12 22:58



No logré hacerlo funcionar con ggsave, pero con una llamada estándar a png() parece estar bien.

Solo cambié el output$downloadPlot parte de tu server.R archivo :

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

Tenga en cuenta que tuve algunos problemas con la versión 0.3 de brillante, pero funciona con la última versión de Github:

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

18
2018-02-11 13:15



Esto es viejo, pero sigue siendo el mejor éxito cuando alguien busca "R shiny save ggplot", así que contribuiré con otra solución alternativa. Muy simple ... llama a ggsave en la misma función que muestra tu gráfico, que guardará el gráfico como un archivo en el servidor.

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

Luego, use downloadHandler y use file.copy() para escribir datos del archivo existente en el parámetro "archivo".

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

Funciona para mi.


15
2017-07-30 05:08