1

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)
unknown
  • 853
  • 1
  • 10
  • 23
  • Basically, you're asking how to use download buttons in shiny. Save your data in a variable and pass it to `downloadHandler()`. See an example [here](https://stackoverflow.com/questions/45236368/how-to-use-the-download-button-in-shiny), run example app from R: `runExample("10_download")` – vladli Mar 13 '19 at 12:25
  • 1
    I think the question is more about how to get the filtered data from the displayTable - right? – ill Mar 13 '19 at 13:08
  • @ill exactly, that's what I'm trying to do – unknown Mar 13 '19 at 13:25

3 Answers3

3

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)
    }
   )
Alessio
  • 910
  • 7
  • 16
1

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)

    }
  )
MKa
  • 2,248
  • 16
  • 22
0

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.

adan
  • 1