1

I am trying to apply the same basic (reproducible) code as shown below to my application as was provided in this test example (and using the provided solution) found on this question: Download Data from renderDatatable in Shiny

I have customized it a bit so that the table uses selectInput()filters rather than those displayed at the top of the datatable when rendered.

The problem is that in both the example code in the referenced link, and in my case as well, the filters apply as they should to the datatable on screen, but when passed through the downloadHandler(), it does not export the filtered data. It filters out the correct rows filtered, but it is not the correct data.

I am struggling with coming up with a solution to applying what I intend to be a "reactive" application to the table when downloading the file, so that the desired result is that the exported data is the actual data filtered within the app.

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


## === LOAD EXAMPLE DATA =====

cars = mtcars


# do I make the data frame reactive?

reactiveDF = reactive(cars)

## ==== UI ====

ui <- fluidPage(
  titlePanel("Basic DataTable"),
  
  # Create a new Row in the UI for selectInputs
  fluidRow(
    column(4,
           selectInput("cyl",
                       "Cylinders:",
                       c("All",
                         unique(sort(as.character(cars$cyl)))))
    ),
    column(4,
           selectInput("gear",
                       "Gears:",
                       c("All",
                         unique(as.character(cars$gear))))
    ),
    column(4,
           selectInput("carb",
                       "Carburators:",
                       c("All",
                         unique(as.character(cars$carb))))
    )
  ),
  # Create a new row for the table.
  
  DT::dataTableOutput("dt"),
  
  p("Notice that the 'rows_all' attribute grabs the row indices of the data."),
  verbatimTextOutput("filtered_row"),
  
  # Create a new row for the download button
  p("The table responds to the filters perfectly, yet it will not download the data. Test it out."),
  p("Evaluate the csv file and you will see that while it extracts the filtered rows,"),
  p("it is not displaying the actual filtered data in the table!"),
  
  downloadButton(outputId = "download_filtered",
                 label = "Download Filtered Data")
)


## ==== END UI ====

## ==== SERVER ====

server = function(input, output){
  
  output$filtered_row <- 
    renderPrint({
      input[["dt_rows_all"]]
    })
  
  # Filter data based on selections
  
  # This controls the 3 filters displayed on top of the datatable
  output$dt <- DT::renderDataTable(datatable({
    cardata <- cars
    # conditionals 
    
    if (input$cyl != "All") {
      cardata <- cardata[cardata$cyl == input$cyl, ]
    }
    if (input$gear != "All") {
      cardata <- cardata[cardata$gear == input$gear, ]
    }
    if (input$carb != "All") {
      cardata <- cardata[cardata$carb == input$carb, ]
    }
    
    # display the filtered data
    cardata
  }))
  
  
  
# Download handler for exporting the data to csv -this won't work as intended -----
  
  output$download_filtered <- 
    downloadHandler(
      filename = "filtered_report.csv",
      content = function(file){
        write.csv(cardata[input[["dt_rows_all"]], ],file)
      }
    )
}

shinyApp(ui,server)
myClone
  • 1,609
  • 5
  • 17
  • 28

1 Answers1

2

You are not using the reactive object the correct way. In shiny, the idea behind that type of objects is to avoid repeating yourself. Here you can create a reactive object reactiveDF and use that one to generate the dataTableOutput and the download table.

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


## === LOAD EXAMPLE DATA =====

cars = mtcars


# do I make the data frame reactive?



## ==== UI ====

ui <- fluidPage(
  titlePanel("Basic DataTable"),
  
  # Create a new Row in the UI for selectInputs
  fluidRow(
    column(4,
           selectInput("cyl",
                       "Cylinders:",
                       c("All",
                         unique(sort(as.character(cars$cyl)))))
    ),
    column(4,
           selectInput("gear",
                       "Gears:",
                       c("All",
                         unique(as.character(cars$gear))))
    ),
    column(4,
           selectInput("carb",
                       "Carburators:",
                       c("All",
                         unique(as.character(cars$carb))))
    )
  ),
  # Create a new row for the table.
  
  DT::dataTableOutput("dt"),
  
  p("Notice that the 'rows_all' attribute grabs the row indices of the data."),
  verbatimTextOutput("filtered_row"),
  
  # Create a new row for the download button
  p("The table responds to the filters perfectly, yet it will not download the data. Test it out."),
  p("Evaluate the csv file and you will see that while it extracts the filtered rows,"),
  p("it is not displaying the actual filtered data in the table!"),
  
  downloadButton(outputId = "download_filtered",
                 label = "Download Filtered Data")
)


## ==== END UI ====

## ==== SERVER ====

server = function(input, output){
  
  
  reactiveDF = reactive({
    cardata <- cars
    # conditionals 
    
    if (input$cyl != "All") {
      cardata <- cardata[cardata$cyl == input$cyl, ]
    }
    if (input$gear != "All") {
      cardata <- cardata[cardata$gear == input$gear, ]
    }
    if (input$carb != "All") {
      cardata <- cardata[cardata$carb == input$carb, ]
    }
    
    # display the filtered data
    cardata
    
    
  })
  
  output$filtered_row <- 
    renderPrint({
      input[["dt_rows_all"]]
    })
  
  # Filter data based on selections
  
  # This controls the 3 filters displayed on top of the datatable
  output$dt <- DT::renderDataTable(datatable({
    reactiveDF()
  }))
  
  
  
  # Download handler for exporting the data to csv -this won't work as intended -----
  
  output$download_filtered <- 
    downloadHandler(
      filename = "filtered_report.csv",
      content = function(file){
        write.csv(reactiveDF(),file)
      }
    )
}

shinyApp(ui,server)


Johan Rosa
  • 2,797
  • 10
  • 18
  • Many thanks Johan! Yes I know the reactiveDF was the key to the solution, but I was missing the connection in how to wrap it into the filter conditionals. You summarized it perfectly. I tested the code on my end and it worked exactly as it should. – myClone May 04 '21 at 16:12