Guest User

Untitled

a guest
Apr 19th, 2018
83
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.96 KB | None | 0 0
  1. library(shiny)
  2.  
  3. columnFilterUI <- function(id) {
  4. ns <- NS(id)
  5. uiOutput(ns("filter_container"))
  6. }
  7.  
  8. columnFilter <- function(input, output, session, df, col_num, choice_filter, multi = TRUE) {
  9. # This renders a selectInput and only re-renders when the selected data
  10. # frame changes. (i.e. it doesn't re-render when filters change state.)
  11. output$filter_container <- renderUI({
  12. # Don't render if col_num is > actual number of cols
  13. req(col_num <= ncol(df()))
  14.  
  15. choices <- c(
  16. "Select" = "",
  17. sort(unique(df()[,col_num,drop=TRUE]))
  18. )
  19.  
  20. freezeReactiveValue(input, "filter_value")
  21. selectInput(session$ns("filter_value"), names(df())[[col_num]],
  22. choices = choices,
  23. multiple = multi)
  24. })
  25.  
  26. # When the other filters change, update this filter to remove rows that
  27. # are filtered out by the other filters' criteria. (We also add in the
  28. # currently selected values for this filter, so that changing other
  29. # filters does not cause this filter's selected values to be unselected;
  30. # while that behavior might make sense logically, it's a poor user
  31. # experience.)
  32. observeEvent(choice_filter(), {
  33. current_values <- input$filter_value
  34.  
  35. choices <- c(
  36. "Select" = "",
  37. sort(unique(c(current_values, df()[choice_filter(),col_num,drop=TRUE])))
  38. )
  39.  
  40. updateSelectInput(session, "filter_value",
  41. choices = choices,
  42. selected = current_values
  43. )
  44. })
  45.  
  46. # Return a reactive that is a row index of selected rows, according to
  47. # just this filter. If this filter shouldn't be taken into account
  48. # because its col_num is too high, or if there are no values selected,
  49. # just return TRUE to accept all rows.
  50. reactive({
  51. if (col_num > ncol(df())) {
  52. TRUE
  53. } else if (!isTruthy(input$filter_value)) {
  54. TRUE
  55. } else {
  56. df()[,col_num,drop=TRUE] %in% input$filter_value
  57. }
  58. })
  59. }
  60.  
  61. columnFilterSetUI <- function(id, maxcol, colwidth) {
  62. ns <- NS(id)
  63.  
  64. fluidRow(
  65. lapply(1:maxcol, function(i) {
  66. column(colwidth,
  67. columnFilterUI(ns(paste0("col", i)))
  68. )
  69. })
  70. )
  71. }
  72.  
  73. columnFilterSet <- function(input, output, session, df, maxcol, multi = TRUE) {
  74.  
  75. # Each column filter needs to only display the choices that are
  76. # permitted after all the OTHER filters have had their say. But
  77. # each column filter must not take its own filter into account
  78. # (hence we do filter[-col], not filter, in the reactive below).
  79. create_choice_filter <- function(col) {
  80. reactive({
  81. filter_values <- lapply(filters[-col], do.call, args = list())
  82. Reduce(`&`, filter_values, TRUE)
  83. })
  84. }
  85.  
  86. # filters is a list of reactive expressions, each of which is a
  87. # logical vector of rows to be selected.
  88. filters <- lapply(1:maxcol, function(i) {
  89. callModule(columnFilter, paste0("col", i), df, i, create_choice_filter(i), multi = multi)
  90. })
  91.  
  92. reactive({
  93. # Unpack the list of reactive expressions to a list of logical vectors
  94. filter_values <- lapply(filters, do.call, args = list())
  95. # Combine all the logical vectors using & operator
  96. selected_rows <- Reduce(`&`, filter_values, TRUE)
  97. # Return the data frame, filtered by the selected rows
  98. df()[selected_rows,]
  99. })
  100. }
  101.  
  102. ui <- fluidPage(
  103. selectInput("dataset", "Dataset", c("mtcars", "pressure", "cars"), selected = "mtcars"),
  104. columnFilterSetUI("filterset", maxcol = 4, colwidth = 3),
  105. DT::dataTableOutput("table"),
  106. columnFilterSetUI("filtersetsingle", maxcol = 4, colwidth = 3),
  107. DT::dataTableOutput("table_single")
  108. )
  109.  
  110. server <- function(input, output, session) {
  111. selected_data <- reactive({
  112. get(input$dataset, "package:datasets")
  113. })
  114.  
  115. filtered_data <- callModule(columnFilterSet, "filterset", df = selected_data, maxcol = 4)
  116. filtered_data_single <- callModule(columnFilterSet, "filtersetsingle", df = selected_data, maxcol = 4, multi = FALSE)
  117.  
  118. output$table <- DT::renderDataTable({ filtered_data() })
  119. output$table_single <- DT::renderDataTable({ filtered_data_single() })
  120. }
  121.  
  122. shinyApp(ui, server)
Add Comment
Please, Sign In to add comment