Speichern Sie Plots, die in einer glänzenden App erstellt wurden

83

Ich versuche herauszufinden, wie man downloadButton verwendet, um eine Handlung mit glänzendem zu speichern. Das Beispiel im Paket zeigt downloadButton / downloadHandler zum Speichern einer CSV-Datei. Darauf aufbauend werde ich ein reproduzierbares Beispiel machen.

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

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

Wenn Sie diese Frage beantworten, sind Sie wahrscheinlich damit vertraut. Um dies zu erreichen, speichern Sie die oben genannten Informationen in separaten Skripten ( ui.Rund server.Rin einem Ordner ( foo) im Arbeitsverzeichnis. Um die glänzende App auszuführen, führen Sie sie aus runApp("foo").

Bei Verwendung ggsaveerhalte ich eine Fehlermeldung, dass ggsave die filenameFunktion nicht verwenden kann (glaube ich). Wenn ich das Standard-Grafikgerät (wie unten) verwende, Download Plotfunktioniert das fehlerfrei, aber die Grafik wird nicht geschrieben.

Alle Tipps, um downloadHandler zum Schreiben von Plots zu bewegen, sind willkommen.

alexwhan
quelle

Antworten:

67

Ich bin mir nicht sicher, ob diese Frage noch aktiv ist, aber es ist die erste, die bei der Suche nach "Plots in glänzender App speichern" auftauchte. Daher wollte ich schnell hinzufügen, wie ggsave mit downloadHandler in Anlehnung an die ursprüngliche Frage funktioniert.

Die von juba vorgeschlagenen alternativen Strategien mit direkter Ausgabe anstelle von ggsave und die von alexwhan selbst vorgeschlagene alternative Strategie funktionieren beide hervorragend. Dies ist nur für diejenigen gedacht, die ggsave unbedingt im downloadHandler verwenden möchten.

Das von alexwhan gemeldete Problem wird dadurch verursacht, dass ggsave versucht, die Dateierweiterung dem richtigen Grafikgerät zuzuordnen. Die temporäre Datei hat jedoch keine Erweiterung, sodass der Abgleich fehlschlägt. Dies kann behoben werden, indem das Gerät im ggsaveFunktionsaufruf speziell eingestellt wird , wie im ursprünglichen Codebeispiel (für ein 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)
    }
)

Dieser Aufruf erfolgt grundsätzlich die deviceFunktion für ein , pngdass ggsaveAbtretungsempfänger intern (Sie können an dem aussehen ggsaveFunktionscode die Syntax , um zu sehen jpg, pdfusw.). Idealerweise könnte man die Dateierweiterung (falls sie vom Dateinamen abweicht - wie hier für die temporäre Datei) als ggsaveParameter angeben, aber diese Option ist derzeit in nicht verfügbar ggsave.


Ein minimales in sich geschlossenes Arbeitsbeispiel:

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    

Aktualisieren

Ab ggplot2 Version 2.0.0 unterstützt die ggsaveFunktion die Zeicheneingabe für den deviceParameter. Das bedeutet, dass die vom downloadHandler erstellte temporäre Datei jetzt mit einem direkten Aufruf ggsavevon gespeichert werden kann, indem angegeben wird, dass die zu verwendende Erweiterung z. B. sein soll "pdf"(anstatt zu übergeben) in einer Gerätefunktion). Dies vereinfacht das obige Beispiel wie folgt

output$downloadPlot <- downloadHandler(
    filename = function() { paste(input$dataset, '.png', sep='') },
    content = function(file) {
        ggsave(file, plot = plotInput(), device = "png")
    }
)
Sebkopf
quelle
1
Ich glaube, Ihre Antwort ist hier tatsächlich die richtige. Sie können auch einfach ggsave(file, plotInput(), device = png)eine Gerätefunktion (Wrapper) verwenden, anstatt sie zu erstellen.
Yihui Xie
@sebkopf Ich habe deine Antwort in der Zwischenzeit verpasst und ein bisschen!
Alexwhan
1
@Yihui Diese Lösung funktioniert bei mir nicht: R Version 3.1.0, ggplot2_1.0.0 shiny_0.10.1. Das Feld Speichern wird angezeigt. Klicken Sie auf Speichern, es wird jedoch keine Datei gespeichert. Kann jemand bestätigen?
zx8754
3
@ zx8754 Ich habe der Antwort gerade ein vollständiges Beispiel hinzugefügt. Beachten Sie, dass Sie es in Ihrem Webbrowser ausführen sollten, anstatt es in RStudio anzuzeigen, da der RStudio-Viewer den bekannten Fehler hat, dass er keine Dateien herunterladen kann.
Yihui Xie
1
@sebkopf Ja, ich habe es realisiert, nachdem ich ein echtes Beispiel ausprobiert habe, also war mein erster Kommentar hier tatsächlich falsch. Danke für die Klarstellung!
Yihui Xie
24

Hier ist eine Lösung, mit der Sie ggsave zum Speichern glänzender Diagramme verwenden können. Es verwendet ein logisches Kontrollkästchen und eine Texteingabe zum Aufrufen ggsave(). Fügen Sie dies der ui.RDatei hinzu sidebarPanel:

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

Fügen Sie dies dann server.Ranstelle der aktuellen output$plotreactivePlot-Funktion zur Datei hinzu :

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

Ein Benutzer kann dann den gewünschten Dateinamen in das Textfeld (ohne Erweiterung) eingeben und das Kontrollkästchen aktivieren, um es im App-Verzeichnis zu speichern. Wenn Sie das Kontrollkästchen deaktivieren, wird das Diagramm erneut gedruckt. Ich bin mir sicher, dass es bessere Möglichkeiten gibt, dies zu tun, aber zumindest kann ich jetzt ggsave und cairo in Windows für viel schönere PNG-Grafiken verwenden.

Bitte fügen Sie Ihre Vorschläge hinzu.

alexwhan
quelle
Ohne einen isolateBlock um das input$filenamewird bei jeder Änderung des filenameTextfelds auch ein Speichern der Datei veranlasst, wenn das Kontrollkästchen aktiviert ist.
jpd527
23

Ich habe es nicht geschafft, damit es funktioniert ggsave, aber mit einem Standardaufruf png()scheint es in Ordnung zu sein.

Ich habe nur den output$downloadPlotTeil Ihrer server.RDatei geändert :

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

Beachten Sie, dass ich einige Probleme mit der Version 0.3 von shiny hatte, aber es funktioniert mit der neuesten Version von Github:

library(devtools)
install_github("shiny","rstudio")
Juba
quelle
OK, ich werde akzeptieren, dass ggsave in dieser Phase des Verfahrens mit downloadHandler nicht funktioniert. glänzende 0,3 fällt mit downloadHandler auseinander, du hast recht. Ich werde eine alternative Lösung veröffentlichen, die ich herausgefunden habe, um DownloadHandler zu vermeiden, damit ggsave funktioniert.
Alexwhan
1
@juba Irgendeine Idee, warum dieser Versuch, mit einer ähnlichen Methode (nicht ggplot2) als PDF auszugeben, nicht funktioniert? Ich bekomme nur ein kaputtes PDF, das sich nicht öffnen lässt. Kann plotInput kein Diagramm anstelle eines Diagrammobjekts liefern?
Geotheory
19

Dies ist alt, aber immer noch der Top-Hit, wenn jemand "R shiny save ggplot" googelt, also werde ich eine weitere Problemumgehung beitragen. Sehr einfach ... rufen Sie ggsave in derselben Funktion auf, in der Ihr Diagramm angezeigt wird, wodurch das Diagramm als Datei auf dem Server gespeichert wird.

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

Verwenden Sie dann downloadHandler und file.copy()schreiben Sie Daten aus der vorhandenen Datei in den Parameter "file".

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

Funktioniert bei mir.

Vocaloidict
quelle