'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 1:[1]

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

Solution 2:[2]

I would create eventReactive function that allows your col1Input.

  # Reactive function based on input
  react_df <- eventReactive(input$chosenCol1, {

    return(egDf %>% filter(col1 %in% input$chosenCol1))

  })

  output$displayer <- renderDataTable(react_df())

  # Download box
  output$downloadData <- downloadHandler(
    filename = function() {
      paste("data-", Sys.Date(), ".csv", sep="")
    },
    content = function(file) {

      output_d <- react_df()

      write.csv(output_d, file, row.names = FALSE)

    }
  )

Solution 3:[3]

I dealt with this issue recently and unfortunately that solution didn't work for me. But simply using writexl::write_xlsx() instead of write.csv() was enough.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 MKa
Solution 3 adan