web-dev-qa-db-fra.com

Enregistrer des tracés réalisés dans une application brillante

J'essaie de comprendre comment utiliser downloadButton pour enregistrer un tracé avec brillant. L'exemple dans le package illustre downloadButton/downloadHandler pour enregistrer un .csv. Je vais faire un exemple reproductible basé sur cela.

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

Pour 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 vous répondez à cette question, vous la connaissez probablement, mais pour que cela fonctionne, enregistrez ce qui précède dans des scripts séparés (ui.R Et server.R Dans un dossier (foo) dans le répertoire de travail. Pour exécuter l'application brillante, exécutez runApp("foo").

En utilisant ggsave, j'obtiens un message d'erreur indiquant que ggsave ne peut pas utiliser la fonction filename (je pense). Si j'utilise le périphérique graphique standard (comme ci-dessous), le Download Plot Fonctionne sans erreur, mais il n'écrit pas le graphique.

Tous les conseils pour que downloadHandler travaille pour l'écriture de tracés seraient appréciés.

75
alexwhan

Je ne sais pas si cette question est toujours active, mais c'est la première qui est apparue lors de la recherche de "l'enregistrement des tracés dans une application brillante", j'ai donc voulu ajouter rapidement comment faire fonctionner ggsave avec downloadHandler dans le sens de la question d'origine.

Les stratégies alternatives suggérées par juba en utilisant la sortie directe au lieu de ggsave et la stratégie alternative suggérée par alexwhan lui-même fonctionnent très bien, ceci est juste pour ceux qui veulent absolument utiliser ggsave dans le downloadHandler).

Le problème signalé par alexwhan est dû au fait que ggsave essaie de faire correspondre l'extension de fichier au périphérique graphique approprié. Cependant, le fichier temporaire n'a pas d'extension et la correspondance échoue. Cela peut être résolu en définissant spécifiquement le périphérique dans l'appel de fonction ggsave, comme dans l'exemple de code d'origine (pour 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)
    }
)

Cet appel prend essentiellement la fonction device pour un png que ggsave affecte en interne (vous pouvez consulter le code de fonction ggsave pour voir la syntaxe de jpg, pdf, etc.). Peut-être, idéalement, on pourrait spécifier l'extension du fichier (s'il est différent du nom du fichier - comme c'est le cas ici pour le fichier temporaire) en tant que paramètre ggsave mais cette option n'est actuellement pas disponible dans ggsave.


Un exemple de travail autonome minimal:

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    

Mise à jour

Depuis la version 2.0.0 de ggplot2, la fonction ggsave prend en charge la saisie de caractères pour le paramètre device, ce qui signifie que le fichier temporaire créé par le downloadHandler peut maintenant être enregistré avec un appel direct à ggsave en spécifiant que l'extension à utiliser doit être par exemple "pdf" (plutôt que de passer une fonction de périphérique). Cela simplifie l'exemple ci-dessus pour ce qui suit

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

Voici une solution qui permet d'utiliser ggsave pour enregistrer des tracés brillants. Il utilise une case à cocher logique et une entrée de texte pour appeler ggsave(). Ajoutez ceci au ui.R fichier à l'intérieur sidebarPanel:

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

Ajoutez ensuite ceci au server.R fichier au lieu de l'actuel output$plot fonction reactivePlot:

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

Un utilisateur peut ensuite taper le nom de fichier souhaité dans la zone de texte (sans extension) et cocher la case pour enregistrer dans le répertoire de l'application. Décocher la case imprime à nouveau le tracé. Je suis sûr qu'il existe des façons plus nettes de le faire, mais au moins je peux maintenant utiliser ggsave et cairo dans Windows pour des graphismes png beaucoup plus agréables.

Veuillez ajouter toute suggestion que vous pourriez avoir.

22
alexwhan

Je n'ai pas réussi à le faire fonctionner avec ggsave, mais avec un appel standard à png() cela semble aller.

J'ai seulement changé le output$downloadPlot une partie de votre server.R fichier :

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

Notez que j'ai eu quelques problèmes avec la version 0.3 de shiny, mais cela fonctionne avec la dernière version de Github:

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

C'est vieux, mais c'est quand même le top hit quand quelqu'un google "R shiny save ggplot", donc je vais apporter une autre solution. Très simple ... appelez ggsave dans la même fonction qui affiche votre graphique, ce qui enregistrera le graphique en tant que fichier sur le serveur.

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

Ensuite, utilisez downloadHandler et utilisez file.copy() pour écrire les données du fichier existant dans le paramètre "file".

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

Travaille pour moi.

17
vocaloidict