2
votes

I am working on a Shiny app to let users select columns, filter rows, and download the result. I am using Data Tables to do this. The data file is moderately large and using client-side processing results in a fairly significant slowdown; however, using server side processing I am unable to get access to the filtered dataset.

In other words, when server=FALSE in renderDataTable(), input$foo_rows_all returns all filtered rows but when server=TRUE input$foo_rows_all returns just the rows on the currently displayed page, not all rows. How can I get access to all filtered rows when server = TRUE.

An example that shows the problem:

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

dat<-data.frame(letters=c(rep("A",15),rep("B",5),rep("C",5)))

server<-shinyServer(function(input, output) {
  #Returns filtered data
  output$dat_false <- renderDataTable(dat,filter = "top",server = FALSE)
  #Returns just the currently visible values 
  output$dat_true <- renderDataTable(dat,filter = "top",server = TRUE)

  #This code modified from: https://yihui.shinyapps.io/DT-info/
  output$x5 = renderPrint({
    cat('\n\nAll rows with server = TRUE:\n\n')
    cat(input$dat_true_rows_all, sep = ', ')
    cat('\n\nAll rows with server = FALSE:\n\n')
    cat(input$dat_false_rows_all, sep = ', ')
  })
})

ui<-shinyUI(
  fluidPage(
    sidebarLayout(
      sidebarPanel(verbatimTextOutput('x5')),
      mainPanel(dataTableOutput("dat_true"),
                dataTableOutput("dat_false"))
    )
  )
)

shinyApp(ui,server)
1
Could it be that this issue has been resolved with later versions of DT? Just tested your example, and both server= TRUE and server=FALSE work as intended, and in the same way ... - martin

1 Answers

1
votes

You have the input$data_true_search_columns and input$data_true_search variables to work with. So, for example you could write a function like this to get the selected rows (note I am using fromJSON to convert the json, but you could use chartr("[]", "()", ...) or similar to do it manually. I don't know if this is the proper way, and to deal with the numeric range selections you would need to modify the function to deal with those.

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

dat<-data.frame(letters=c(rep("A",15),rep("B",5),rep("C",5)))

activeRows <- function(cols) {
    active <- which(cols!='')
    if (!length(active)) return( seq_len(nrow(dat)) )
    vals <- lapply(cols[active], fromJSON)
    which(
      Reduce("&", lapply(seq_along(vals), function(i) dat[,i] %in% vals[[i]])))
}

server<-shinyServer(function(input, output) {
  #Returns filtered data
  output$dat_false <- renderDataTable(dat,filter = "top",server = FALSE)
  #Returns just the currently visible values 
  output$dat_true <- renderDataTable(dat,filter = "top",server = TRUE)

  #This code modified from: https://yihui.shinyapps.io/DT-info/
  output$x5 = renderPrint({
    cat('\n\nAll rows with server = TRUE:\n\n')
    cat(activeRows(input$dat_true_search_columns), sep = ', ')
    cat('\n\nAll rows with server = FALSE:\n\n')
    cat(input$dat_false_rows_all, sep = ', ')
  })
})

ui<-shinyUI(
  fluidPage(
    sidebarLayout(
      sidebarPanel(verbatimTextOutput('x5')),
      mainPanel(dataTableOutput("dat_true"),
                dataTableOutput("dat_false"))
    )
  )
)
shinyApp(ui,server)