บันทึกพล็อตที่ทำในแอพเงางาม


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ทำงานได้โดยไม่มีข้อผิดพลาด แต่ไม่ได้เขียนกราฟิก

คำแนะนำใด ๆ ในการดาวน์โหลด

คำตอบ:


69

ไม่แน่ใจว่าคำถามนี้ยังคงใช้งานอยู่หรือไม่ แต่เป็นคำถามแรกที่เกิดขึ้นเมื่อค้นหา "การบันทึกพล็อตในแอปเงา" ดังนั้นฉันจึงต้องการเพิ่มวิธีการทำให้ ggsave ทำงานกับ downloadHandler ตามบรรทัดของคำถามเดิมอย่างรวดเร็ว

กลยุทธ์ทางเลือกที่แนะนำโดย juba โดยใช้เอาต์พุตโดยตรงแทน ggsave และกลยุทธ์ทางเลือกที่อเล็กซ์แนะนำว่าทั้งคู่ทำงานได้ดีนี่เป็นเพียงสำหรับผู้ที่ต้องการใช้ 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 ใน windows สำหรับกราฟิก 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 ของมัน แต่ใช้งานได้กับ Github รุ่นล่าสุด:

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

ตกลงฉันจะยอมรับว่า ggsave จะไม่ทำงานในขั้นตอนนี้ของการดำเนินการกับ downloadHandler เงางาม 0.3 แตกสลายด้วย downloadHandler คุณพูดถูก ฉันจะโพสต์วิธีอื่นที่ฉันคิดว่าหลีกเลี่ยงการดาวน์โหลดตัวจัดการซึ่งจะทำให้ ggsave ทำงานได้
alexwhan

1
@juba มีความคิดว่าทำไมความพยายามที่จะส่งออกเป็น pdfด้วยวิธีการที่คล้ายกัน (ไม่ใช่ ggplot2) ไม่ได้ผล? ฉันเพิ่งได้รับ pdf เสียที่เปิดไม่ได้ plotInput ไม่สามารถส่งพล็อตแทนอ็อบเจ็กต์พล็อตได้หรือไม่?
geotheory

20

นี่เก่าแล้ว แต่ยังคงเป็นที่นิยมมากที่สุดเมื่อมีคน googles "R shiny save ggplot" ดังนั้นฉันจะช่วยแก้ปัญหาให้อีกครั้ง ง่ายมาก ... เรียก ggsave ในฟังก์ชันเดียวกับที่แสดงกราฟของคุณซึ่งจะบันทึกกราฟเป็นไฟล์บนเซิร์ฟเวอร์

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

จากนั้นใช้ downloadHandler และใช้file.copy()เพื่อเขียนข้อมูลจากไฟล์ที่มีอยู่ไปยังพารามิเตอร์ "file"

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

ใช้ได้ผลสำหรับฉัน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.