How do you download the result of the datatable search?

I have a table with 500,000 rows. I would like to be able to use the shinyapps data table to search the table, and then download the result of the search. I was able to get the download button to work, but even after using the search function to filter the data, I'm still given the full set of data when I click download. I'm reading through a few guides, including mastering shiny, but can't seem to find any tips or instructions to include this feature. Any information would be greatly appreciated.

Here's the shiny code I'm using:

ui <-  fluidPage(
  downloadButton("download", "Download .csv"),
  align="center",
  theme = shinytheme("spacelab"),
  titlePanel("Data"),
  fluidRow(
    column(3),
    column(6,
           DT::dataTableOutput("df_filtered")
    ),
    column(3)
  )
)

server <- function(input, output) {
  datasetInput1 <- reactive({
    df_filtered
  })
  output$df_filtered <- renderDataTable({
    dataset <- datasetInput1()
  })
  output$download <- downloadHandler(
    filename = "report.csv",
    content = function(file) {
      write.csv(datasetInput1(), file)
    }
  )
}

shinyApp(ui = ui, server = server)

With some iris data:

library(shiny)
library(dplyr)

ui <-  fluidPage(
  downloadButton("download", "Download .csv"),
  align="center",
  # theme = shinytheme("spacelab"),
  titlePanel("Data"),
  fluidRow(
    column(3,
           selectInput("sp",
                       "Species",
                       unique(iris$Species),
                       "setosa")),
    column(6,
           DT::dataTableOutput("df_filtered")
    ),
    column(3)
  )
)

server <- function(input, output, session) {

  datasetInput1 <- reactive(
    iris %>%
      filter(Species == input$sp)
  )

  output$df_filtered <- renderDT(datasetInput1())

  output$download <- downloadHandler(
    filename = "report.csv",
    content = function(file) {
      write.csv(datasetInput1(), file)
    }
  )
}

shinyApp(ui = ui, server = server)

Hi williaml,

Thanks for your response. This works with the selectInput filter, but is there a way to also filter with the renderDataTable search feature like below?

Here I typed "4.7" in the search box -- is it possible to only return those rows when downloading?

You would get rid of the search box, but create one as an input (like the species filter) and use that to updatedatasetInput1.

Like this:

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

ui <-  fluidPage(
  downloadButton("download", "Download .csv"),
  align="center",
  # theme = shinytheme("spacelab"),
  titlePanel("Data"),
  fluidRow(
    column(3,
           selectInput("sp",
                       "Species",
                       unique(iris$Species),
                       "setosa"),
           sliderInput("length",
                       "Sepal length filter",
                       min = min(iris$Sepal.Length),
                       max = max(iris$Sepal.Length),
                       value = c(min(iris$Sepal.Length) + 1,
                                 max(iris$Sepal.Length) -1))
           ),
    column(6,
           dataTableOutput("df_filtered")
    ),
    column(3)
  )
)

server <- function(input, output, session) {
  
  datasetInput1 <- reactive({
    iris %>%
      filter(Species == input$sp,
             Sepal.Length >= input$length[1] & Sepal.Length <= input$length[2])
  })
  
  output$df_filtered <- renderDT({
    datatable(datasetInput1(),
              options = list(dom = 't'))
    })
  
  output$download <- downloadHandler(
    filename = "report.csv",
    content = function(file) {
      write.csv(datasetInput1(), file)
    }
  )
}

shinyApp(ui = ui, server = server)
1 Like

Oh I see. Okay, in that case I will play around with this a bit to get that working. Thanks for help getting me steered in the right direction.

1 Like

One last question. I think I'm almost there.

I was able to set up a search input that updates datasetInput1. One minor issue I'm experiencing is the filter is on by default. I'm wanting to conditionally filter the data only if text is entered into the search input.

So far I've tried writing a conditional if statement that does this but I can't seem to get it to work. Any ideas?

#reprex

library(shiny)
library(dplyr)
library(shinyWidgets)
library(DT)

df <- iris
df$Species <- as.character(df$Species)

#shiny server ui
ui <-  fluidPage(
  downloadButton("download", "Download .csv"),
  align="center",
  titlePanel("Data"),
  fluidRow(
    column(3,
           searchInput(inputId = "Species",
                       label = "Species filter",
                       btnSearch = icon("search"),
                       btnReset = icon("remove"),
                       width = "75%"
           )
    ),
    column(6,
           DT::dataTableOutput("df")
    ),
    column(3)
  )
)

#shiny server back end
server <- function(input, output, session) {
  
  datasetInput1 <- reactive({
    reactivedata <- df
    if (is.character(input$Species)) {
      reactivedata <- reactivedata %>%
        filter(str_detect(Species, regex(input$Species, ignore_case = T)))
    }
    reactivedata <- reactivedata
    return(reactivedata)
  })
  
  output$df <- renderDT({
    datatable(datasetInput1(), rownames = TRUE, options = list(dom = 'p', ordering = T))
  })
  
  output$download <- downloadHandler(
    filename = "report.csv",
    content = function(file) {
      write.csv(datasetInput1(), file)
    }
  )
}

#run shiny server
shinyApp(ui = ui, server = server)

This works.

I have added some packages that you missed, and also presented some options that work with this dataset. Not sure how they will play with your real data though:

# the options:
#1 filter(str_detect(Species, fixed(input$Species, ignore_case=TRUE))) # starts with nothing
#2 filter(str_detect(Species, str_to_lower(input$Species))) # starts with all data - converts to lower, which matches the data
library(shiny)
library(tidyverse) # changed
library(shinyWidgets)
library(DT) # added

df <- iris
df$Species <- as.character(df$Species)

#shiny server ui
ui <-  fluidPage(
  downloadButton("download", "Download .csv"),
  align="center",
  titlePanel("Data"),
  fluidRow(
    column(3,
           searchInput(inputId = "Species",
                       label = "Species filter",
                       btnSearch = icon("search"),
                       btnReset = icon("remove"),
                       width = "75%"
           )
    ),
    column(6,
           DT::dataTableOutput("df")
    ),
    column(3)
  )
)

#shiny server back end
server <- function(input, output, session) {
  
  datasetInput1 <- reactive({
    reactivedata <- df
    if (is.character(input$Species)) {
      reactivedata <- reactivedata %>%
        # filter(str_detect(Species, fixed(input$Species, ignore_case=TRUE))) # starts with nothing
        filter(str_detect(Species, str_to_lower(input$Species))) # starts with all data - converts to lower, which matches the data
    }
    reactivedata <- reactivedata
    return(reactivedata)
  })
  
  output$df <- renderDT({
    datatable(datasetInput1(), rownames = TRUE, options = list(dom = 'p', ordering = T))
  })
  
  output$download <- downloadHandler(
    filename = "report.csv",
    content = function(file) {
      write.csv(datasetInput1(), file)
    }
  )
}

#run shiny server
shinyApp(ui = ui, server = server)
1 Like

Thanks again with your help with this. This works on the iris data but not on the data I'm working with since the characters I'm working with aren't all lowercase. I suppose I can mutate everything to lower. I'll keep playing around with it to see if anything else works. Any other ideas you may have would be greatly appreciated as well.

1 Like

I wound up using str_to_title on as a compromise and everything seems to look great. Thanks again.

library(shiny)
library(tidyverse) 
library(shinyWidgets)
library(DT)

df <- iris
df$Species <- as.character(df$Species)

#shiny server ui
ui <-  fluidPage(
  downloadButton("download", "Download .csv"),
  align="center",
  titlePanel("Data"),
  fluidRow(
    column(3,
           searchInput(inputId = "Species",
                       label = "Species filter",
                       btnSearch = icon("search"),
                       btnReset = icon("remove"),
                       width = "75%"
           )
    ),
    column(6,
           DT::dataTableOutput("df")
    ),
    column(3)
  )
)

#shiny server back end
server <- function(input, output, session) {
  
  datasetInput1 <- reactive({
df$Species <- str_to_title(df$Species)    
reactivedata <- df
    if (is.character(input$Species)) {
      reactivedata <- reactivedata %>%
        filter(str_detect(Species, str_to_title(input$Species)))
    }
    reactivedata <- reactivedata
    return(reactivedata)
  })
  
  output$df <- renderDT({
    datatable(datasetInput1(), rownames = TRUE, options = list(dom = 'p', ordering = T))
  })
  
  output$download <- downloadHandler(
    filename = "report.csv",
    content = function(file) {
      write.csv(datasetInput1(), file)
    }
  )
}

#run shiny server
shinyApp(ui = ui, server = server)
1 Like

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.