Search code examples
rshinyshiny-reactivityshinymodules

download CSV using filtered dataframe RShiny


I've made an shiny app where I'm filtering a dataset using some values and then I would like to be able to download that filtered dataset. However, I'm struggling to understand how I can pass the filtered dataset to the csv downloader. It is a very large dataset so can't use the buttons available in renderDataTable (I think?) Does anyone have any ideas of how I can do this?

Example app:

### data ###
egDf <- data.frame(col1 = sample(letters,10000,replace=T), col2 = sample(letters,10000, replace=T))

### modules ###
chooseCol1UI <- function(id){
  ns <- NS(id)
  uiOutput(ns('chooserCol1'))
}
chooseCol1 <- function(input, output, session, data){
  output$chooserCol1 <- renderUI({
    ns <- session$ns
    pickerInput(inputId = ns('chosenCol1'),
              label = 'Col1',
              choices = paste(sort(unique(egDf$col1))),
              options = list(`actions-box` = TRUE),
              multiple = TRUE)
  })

  return(reactive(input$chosenCol1))

}

csvDownloadUI <- function(id, label = "Download CSV") {
  ns <- NS(id)
  downloadButton(ns("downloadData"), label)
}
csvDownload <- function(input, output, session, data) {
  output$downloadData <- downloadHandler(
    filename = function() {
      paste(names(data), Sys.Date(), '.csv', sep='')
    },
    content = function(file) {
      write.csv(data, file, row.names = FALSE)
    }
  )
}

displayTableUI <- function(id){
  ns <- NS(id)
  DT::dataTableOutput(ns('displayer'))
}
displayTable <- function(input, output, session, data, col1Input){
  output$displayer <- DT::renderDataTable(egDf %>% filter(col1 %in% col1Input()))
}

### server ###
server <- function(input,output){
  chosenCol1 <- callModule(chooseCol1,
                               id = 'appChooseCol1', data = egDf)
  callModule(module = displayTable, id = "appDisplayTable",
             col1Input = chosenCol1)
}

### ui ###
ui <- fluidPage(
  sidebarPanel(
  chooseCol1UI("appChooseCol1")),
mainPanel(displayTableUI("appDisplayTable")))

### app ###
shinyApp(ui = ui, server = server)

Solution

  • A few years ago I made an app with such a button. In my case I created a reactive expression in the server.R file that is being passed to the downloadHandler.

    Here's the app and here's the github code. Head to the server.R file and search for the "download" string.

    In the app you'll find a blue download button in the "Data" tab. The app let's you apply filters that applies in the datatable, that you can download via the button.

    Edit: here's the server portion of code of interest:

    #data download button
       output$idDwn <- downloadHandler(
        filename = function() { 
         paste('uCount ', format(Sys.time(), "%Y-%m-%d %H.%M.%S"), '.csv', sep='')
        },
        content = function(file) {
         write.csv(datasetInputFilters(), file)
        }
       )