2

I'm learning shiny and I'm creating a shiny app that should enable the user to:

1- Upload the data as .csv file

2- Get Stats and plots

3- Download the table data as .csv and plots as .png

Input file

I created the input .csv file to be used in the app from diamonds data.frame

library(ggplot2)
df <-  diamonds[1:5000, ]
head(df)
write.csv(df, "df.csv")

App.R

library(ggplot2)
library(dplyr)
library(DT)
library(shiny)

ui <- fluidPage(
  sidebarLayout(
    sidebarPanel(fileInput("file","Upload your file"), 
      width =2),
  mainPanel(
   width = 10,
   dataTableOutput("table"),
   downloadButton("downloadtable", "Download the table"),
   tags$br(),
   tags$hr(),
   plotOutput("plot1"),
   downloadButton("downloadplot1", "Download the plot"), 
   tags$br(),
   tags$hr(),
   plotOutput("plot2"),
   downloadButton("downloadplot2", "Download the plot")
   )
)
)

server <- function(input,output){

  data <- reactive({

    file1 <- input$file
    if(is.null(file1)){return()} 

    read.csv(file1$datapath, header=TRUE, sep=',')

  })


  output$table <- renderDataTable({
    if (is.null(data())) { return() }

    df1 <- data()

    df2 <- df1 %>% 
      dplyr::select(cut, color, price) %>% 
      dplyr::group_by(cut, color) %>% 
      dplyr::summarise_each(funs(
        min(.),
        mean(.), 
        median(.),
        max(.),
        sd(.), 
        n() 
      ))  
  })  

  output$downloadtable <- downloadHandler(
    filename = function() {
      paste('stats', '.csv', sep='')
    },
    content = function(file) {
      write.csv(df2, file)
    }
  )

  output$plot1 <- renderPlot({
    if (is.null(data())) { return() }
    df1 <- data()

    ggplot(df1, aes (x =carat, y = price, col = color))+
      geom_point()+
      facet_wrap(~cut)

  }
  )

  output$downloadplot1 <- downloadHandler(
    filename = function() {
      paste('plot1', 'png', sep = ".")
    },
    content = function(file) {
     png(file)

      df1 <- data()

      ggplot(df1, aes (x =carat, y = price, col = color))+
        geom_point()+
        facet_wrap(~cut) 

      dev.off()

    }
  )

  output$plot2 <- renderPlot({
    if (is.null(data())) { return() }
    df1 <- data()

    ggplot(df1, aes (x = price, y = carat, col = color))+
      geom_point()+
      facet_wrap(~clarity)
    }
  )

  output$downloadplot2 <- downloadHandler(
    filename = function() {
      paste('plot2', 'png', sep = ".")
    },
    content = function(file) {
      png(file)

      df1 <- data()

      ggplot(df1, aes (x = price, y = carat, col = color))+
        geom_point()+
        facet_wrap(~clarity)

      dev.off()

    }
  )

}
shinyApp(ui=ui, server = server)

Now, the user can upload the data and get the table and plots but the download buttons are not working. I tried different options and several questions on SO but I couldn't figure out how to get the download buttons to work.

Any suggestion will be highly appreciated?

shiny
  • 3,380
  • 9
  • 42
  • 79
  • 1
    Noticing some issues in the code. In `summarise_each`, remove the brackets and dots inside the `funs()`, they are not needed. Additionally, If you're using ggplot for the figure, just use `ggsave()` and pass it the plot object rather than messing around with device calls within shiny. [This question](https://stackoverflow.com/questions/26764481/downloading-png-from-shiny-r?rq=1) should help with passing the plot to `ggsave()` within shiny. – Jake Kaupp Nov 18 '16 at 00:46
  • 1
    you can also use `ggplotly` – HubertL Nov 18 '16 at 01:58

1 Answers1

3

Your problem with the CSV download is that df2 is not available at that point. You need to generate it.

output$downloadtable <- downloadHandler(
  filename = function() {
    paste('stats', '.csv', sep='')
  },
  content = function(file) {
    df1 <- data()

    df2 <- df1 %>% 
      dplyr::select(cut, color, price) %>% 
      dplyr::group_by(cut, color) %>% 
      dplyr::summarise_each(funs(
        min(.),
        mean(.), 
        median(.),
        max(.),
        sd(.), 
        n() 
      ))  

    write.csv(df2, file)
  }
)

The problem with your plots is that you need to print them (and set the content type).

output$downloadplot1 <- downloadHandler(
  filename <- function() {
    paste('plot1', 'png', sep = ".")
  },
  content <- function(file) {
    png(file)

    df1 <- data()

    plot <- ggplot(df1, aes (x =carat, y = price, col = color))+
      geom_point()+
      facet_wrap(~cut) 

    print(plot)

    dev.off()
  },
  contentType = "image/png"
)
dommer
  • 19,610
  • 14
  • 75
  • 137
  • Thanks for this answer. How to prevent copying the plot lines in the plotoutput and in the download handler ? – Boidot Dec 20 '18 at 08:54