代码之家  ›  专栏  ›  技术社区  ›  J.Con

从空白png文件保存ggplot

  •  2
  • J.Con  · 技术社区  · 7 年前

    我想救一个孩子 ggplot2 在一个盒子里做的东西 shiny 应用程序。基本上这个代码允许 .xlsx 从某些选项中选择后要上载的文件和创建的绘图。然后我加入了一个下载按钮,用户可以下载他们创建的图。我正在使用 downloadHandler() grDevices::png() . 按下按钮确实会导致 .png

    #initialize
    library(shiny)
    library(ggplot2)
    library(purrr)
    library(dplyr)
    library(plotly)
    
    
    #example data
    data(iris)
    
    #make some factors
    #easier to let ggplot2 control plotting (color, fill) based on type
    data(mtcars)
    uvals<-sapply(mtcars,function(x){length(unique(x))})
    mtcars<-map_if(mtcars,uvals<4,as.factor) %>%
      as.data.frame()
    
    
    #plotting theme for ggplot2
    .theme<- theme(
      axis.line = element_line(colour = 'gray', size = .75),
      panel.background = element_blank(),
      plot.background = element_blank()
    )
    
    
    # UI for app
    ui<-(pageWithSidebar(
      # title
      headerPanel("Select Options"),
    
      #input
      sidebarPanel
      (
        # Input: Select a file ----
    
        fileInput("file1", "Choose xlsx File",
                  multiple = TRUE,
                  accept = c(".xlsx")),
    
    
        # Horizontal line ----
        tags$hr(),
    
    
        #download button
         fluidPage(downloadButton('down')),
    
        # Input: Select what to display
        selectInput("dataset","Data:",
                    choices =list(iris = "iris", mtcars = "mtcars",
                                  uploaded_file = "inFile"), selected=NULL),
        selectInput("xaxis","X axis:", choices = NULL),
        selectInput("yaxis","Y axis:", choices = NULL),
        selectInput("fill","Fill:", choices = NULL),
        selectInput("group","Group:", choices = NULL),
        selectInput("plot.type","Plot Type:",
                    list(boxplot = "boxplot", histogram = "histogram", density = "density", bar = "bar")
        ),
        checkboxInput("show.points", "show points", TRUE)
      ),
    
      # output
      mainPanel(
        h3(textOutput("caption")),
        #h3(htmlOutput("caption")),
        uiOutput("plot") # depends on input
      )
    ))
    
    
    # shiny server side code for each call
    server<-function(input, output, session){
    
      #update group and
      #variables based on the data
      observe({
        #browser()
        if(!exists(input$dataset)) return() #make sure upload exists
        var.opts<-colnames(get(input$dataset))
        updateSelectInput(session, "xaxis", choices = var.opts)
        updateSelectInput(session, "yaxis", choices = var.opts)
        updateSelectInput(session, "fill", choices = var.opts)
        updateSelectInput(session, "group", choices = var.opts)
      })
    
      output$caption<-renderText({
        switch(input$plot.type,
               "boxplot"    =   "Boxplot",
               "histogram" =    "Histogram",
               "density"    =   "Density plot",
               "bar"        =   "Bar graph")
      })
    
    
      output$plot <- renderUI({
        plotOutput("p")
      })
    
      #get data object
      get_data<-reactive({
    
        if(!exists(input$dataset)) return() # if no upload
    
        check<-function(x){is.null(x) || x==""}
        if(check(input$dataset)) return()
    
        obj<-list(data=get(input$dataset),
                  yaxis=input$yaxis,
                  xaxis=input$xaxis,
                  fill=input$fill,
                  group=input$group
        )
    
        #require all to be set to proceed
        if(any(sapply(obj,check))) return()
        #make sure choices had a chance to update
        check<-function(obj){
          !all(c(obj$yaxis,obj$xaxis, obj$fill,obj$group) %in% colnames(obj$data))
        }
    
        if(check(obj)) return()
    
    
        obj
    
      })
    
      #plotting function using ggplot2
      output$p <- renderPlot({
    
        plot.obj<-get_data()
    
        #conditions for plotting
        if(is.null(plot.obj)) return()
    
        #make sure variable and group have loaded
        if(plot.obj$yaxis == "" | plot.obj$xaxis =="" | plot.obj$fill ==""| plot.obj$group =="") return()
    
        #plot types
        plot.type<-switch(input$plot.type,
                          "boxplot"     = geom_boxplot(),
                          "histogram" = geom_histogram(alpha=0.5,position="identity"),
                          "density"     =   geom_density(alpha=.75),
                          "bar"         =   geom_bar(position="dodge")
        )
    
    
        if(input$plot.type=="boxplot")  {       #control for 1D or 2D graphs
          p<-ggplot(plot.obj$data,
                    aes_string(
                      x         = plot.obj$xaxis,
                      y         = plot.obj$yaxis,
                      fill  = plot.obj$fill,# let type determine plotting
                      group = plot.obj$group
                    )
          ) + plot.type
    
          if(input$show.points==TRUE)
          {
            p<-p+ geom_point(color='black',alpha=0.5, position = 'jitter')
          }
    
        } else {
    
          p<-ggplot(plot.obj$data,
                    aes_string(
                      x         = plot.obj$xaxis,
                      fill  = plot.obj$fill,
                      group     = plot.obj$group
                      #color    = as.factor(plot.obj$group)
                    )
          ) + plot.type
        }
    
        p<-p+labs(
          fill  = input$fill,
          x         = "",
          y         = input$yaxis
        )  +
          .theme
        print(p)
      })
    
      # set uploaded file
      upload_data<-reactive({
    
        inFile <- input$file1
    
        if (is.null(inFile))
          return(NULL)
    
        #could also store in a reactiveValues
        read_excel(inFile$datapath)
      })
    
      observeEvent(input$file1,{
        inFile<<-upload_data()
      })
    
      # downloadHandler contains 2 arguments as functions, namely filename, content
      output$down <- downloadHandler(
        filename =  function() {
          paste(input$dataset,"png" , sep=".")
        },
        # content is a function with argument file. content writes the plot to the device
        content = function(file) {
          png(file) # open the png device
          p # for GGPLOT
          dev.off()  # turn the device off
    
        } 
      )
    
    }
    
    # Create Shiny app ----
    shinyApp(ui, server)
    
    1 回复  |  直到 7 年前
        1
  •  4
  •   Phil    7 年前

    我作为一个评论回应,但我认识到这有点难以理解,所以我将张贴完整的修订代码,以使其更清楚。

    我一般都建议不要做太多的事情 render*() 电话。相反,将要创建的对象设置为一个单独的 reactive() renderPlot() . 在下面的代码中,我将创建绘图的所有代码移动到 reactive 名为的对象 p ,然后我可以在 ggsave() 用于下载。

    #initialize
    library(shiny)
    library(ggplot2)
    library(purrr)
    library(dplyr)
    library(plotly)
    
    
    #example data
    data(iris)
    
    #make some factors
    #easier to let ggplot2 control plotting (color, fill) based on type
    data(mtcars)
    uvals<-sapply(mtcars,function(x){length(unique(x))})
    mtcars<-map_if(mtcars,uvals<4,as.factor) %>%
      as.data.frame()
    
    
    #plotting theme for ggplot2
    .theme<- theme(
      axis.line = element_line(colour = 'gray', size = .75),
      panel.background = element_blank(),
      plot.background = element_blank()
    )
    
    
    # UI for app
    ui<-(pageWithSidebar(
      # title
      headerPanel("Select Options"),
    
      #input
      sidebarPanel
      (
        # Input: Select a file ----
    
        fileInput("file1", "Choose xlsx File",
                  multiple = TRUE,
                  accept = c(".xlsx")),
    
    
        # Horizontal line ----
        tags$hr(),
    
    
        #download button
        fluidPage(downloadButton('down')),
    
        # Input: Select what to display
        selectInput("dataset","Data:",
                    choices =list(iris = "iris", mtcars = "mtcars",
                                  uploaded_file = "inFile"), selected=NULL),
        selectInput("xaxis","X axis:", choices = NULL),
        selectInput("yaxis","Y axis:", choices = NULL),
        selectInput("fill","Fill:", choices = NULL),
        selectInput("group","Group:", choices = NULL),
        selectInput("plot.type","Plot Type:",
                    list(boxplot = "boxplot", histogram = "histogram", density = "density", bar = "bar")
        ),
        checkboxInput("show.points", "show points", TRUE)
      ),
    
      # output
      mainPanel(
        h3(textOutput("caption")),
        #h3(htmlOutput("caption")),
        uiOutput("plot") # depends on input
      )
    ))
    
    
    # shiny server side code for each call
    server<-function(input, output, session){
    
      #update group and
      #variables based on the data
      observe({
        #browser()
        if(!exists(input$dataset)) return() #make sure upload exists
        var.opts<-colnames(get(input$dataset))
        updateSelectInput(session, "xaxis", choices = var.opts)
        updateSelectInput(session, "yaxis", choices = var.opts)
        updateSelectInput(session, "fill", choices = var.opts)
        updateSelectInput(session, "group", choices = var.opts)
      })
    
      output$caption<-renderText({
        switch(input$plot.type,
               "boxplot"    =   "Boxplot",
               "histogram" =    "Histogram",
               "density"    =   "Density plot",
               "bar"        =   "Bar graph")
      })
    
    
      output$plot <- renderUI({
        plotOutput("p")
      })
    
      #get data object
      get_data<-reactive({
    
        if(!exists(input$dataset)) return() # if no upload
    
        check<-function(x){is.null(x) || x==""}
        if(check(input$dataset)) return()
    
        obj<-list(data=get(input$dataset),
                  yaxis=input$yaxis,
                  xaxis=input$xaxis,
                  fill=input$fill,
                  group=input$group
        )
    
        #require all to be set to proceed
        if(any(sapply(obj,check))) return()
        #make sure choices had a chance to update
        check<-function(obj){
          !all(c(obj$yaxis,obj$xaxis, obj$fill,obj$group) %in% colnames(obj$data))
        }
    
        if(check(obj)) return()
    
    
        obj
    
      })
    
      p <- reactive({
        plot.obj<-get_data()
    
        #conditions for plotting
        if(is.null(plot.obj)) return()
    
        #make sure variable and group have loaded
        if(plot.obj$yaxis == "" | plot.obj$xaxis =="" | plot.obj$fill ==""| plot.obj$group =="") return()
    
        #plot types
        plot.type<-switch(input$plot.type,
                          "boxplot"     = geom_boxplot(),
                          "histogram" = geom_histogram(alpha=0.5,position="identity"),
                          "density"     =   geom_density(alpha=.75),
                          "bar"         =   geom_bar(position="dodge")
        )
    
    
        if(input$plot.type=="boxplot")  {       #control for 1D or 2D graphs
          p<-ggplot(plot.obj$data,
                    aes_string(
                      x         = plot.obj$xaxis,
                      y         = plot.obj$yaxis,
                      fill  = plot.obj$fill,# let type determine plotting
                      group = plot.obj$group
                    )
          ) + plot.type
    
          if(input$show.points==TRUE)
          {
            p<-p+ geom_point(color='black',alpha=0.5, position = 'jitter')
          }
    
        } else {
    
          p<-ggplot(plot.obj$data,
                    aes_string(
                      x         = plot.obj$xaxis,
                      fill  = plot.obj$fill,
                      group     = plot.obj$group
                      #color    = as.factor(plot.obj$group)
                    )
          ) + plot.type
        }
    
        p<-p+labs(
          fill  = input$fill,
          x         = "",
          y         = input$yaxis
        )  +
          .theme
        print(p)
      })
    
      #plotting function using ggplot2
      output$p <- renderPlot({
        p()
      })
    
      # set uploaded file
      upload_data<-reactive({
    
        inFile <- input$file1
    
        if (is.null(inFile))
          return(NULL)
    
        #could also store in a reactiveValues
        read_excel(inFile$datapath)
      })
    
      observeEvent(input$file1,{
        inFile<<-upload_data()
      })
    
      # downloadHandler contains 2 arguments as functions, namely filename, content
      output$down <- downloadHandler(
        filename =  function() {
          paste(input$dataset,"png" , sep=".")
        },
        # content is a function with argument file. content writes the plot to the device
        content = function(file) {
          ggsave(file, p())
        } 
      )
    
    }
    
    # Create Shiny app ----
    shinyApp(ui, server)