Search code examples
rshiny

The ability to select all potential options in a Shiny input along with a dynamic table


I have the following code below that allows for three different "phases" of selection, each input dependent on the one before. Right now the code exists like this:

  ui <- fluidPage(
  titlePanel("Test Dashboard "),
  sidebarLayout(
    sidebarPanel(
      uiOutput("data1"),   ## uiOutput - gets the UI from the server
      uiOutput("data2"),
      uiOutput("data3")
    ),
    mainPanel()
  ))


server <- function(input, output){
  
  State <- c("NV", "NV","NV", "MD", "MD", "MD", "MD", "NY", "NY", "NY", "OH", "OH", "OH")
  County <- c("CLARK", "WASHOE", "EUREKA", "MONTGOMERY", "HOWARD", "BALTIMORE", "FREDERICK", "BRONX", "QUEENS", "WESTCHESTER", "FRANKLIN", "SUMMIT", "STARK" )
  City <- c("Las Vegas", "Reno", "Eureka", "Rockville", "Columbia", "Baltimore", "Thurmont", "Bronx", "Queens", "Yonkers", "Columbus", "Akron", "Canton")
  Rating<- c(1,2,3,4,5,6,7,8,9,10,11,12,13)
  df <- data.frame(State, County, City, Rating, stringsAsFactors = F)
  
  ## renderUI - renders a UI element on the server
  ## used when the UI element is dynamic/dependant on data
  output$data1 <- renderUI({
    selectInput("data1", "Select State", choices = c(df$State))
  })
  
  ## input dependant on the choices in `data1`
  output$data2 <- renderUI({
    selectInput("data2", "Select County", choices = c(df$County[df$State == input$data1]))
  })
  
  output$data3 <- renderUI({
    selectInput("data3", "select City", choices = c(df$City[df$County == input$data2]))
  })
  
  
}

shinyApp(ui, server)

You will notice the sample data is found in the server side code and binded together to form df.

But what if I didn't want to narrow my choice for each selection? Instead let's say I wanted to follow the following selection path: State = "MD", County = ALL, and City = ALL. While I would have the selection to choose just one or multiple selections, it would also include the selection to choose ALL.

Additionally, I would like to also include a dynamic table that is visible and adjusts itself based on the values selected. So if I were following the same selection path as listed above, it would return all the affiliated results for anything filed under State = "MD".

Whenever I try adding something like

DTOutput('table')

On the UI side and the following on the server side:

output$table <- renderDT(df,
                         options = list(
                           pageLength = 5
                         )
)

It just messes up the whole layout and also doesn't produce the table I need.


Solution

  • Here is something to try out. You can use updateSelectInput to change your inputs and make them dependent. A separate reactive expression can filter your data based on your inputs. See if this gives you the intended behavior.

    library(shiny)
    library(DT)
    
    State <- c("NV", "NV","NV", "MD", "MD", "MD", "MD", "NY", "NY", "NY", "OH", "OH", "OH")
    County <- c("CLARK", "WASHOE", "EUREKA", "MONTGOMERY", "HOWARD", "BALTIMORE", "FREDERICK", "BRONX", "QUEENS", "WESTCHESTER", "FRANKLIN", "SUMMIT", "STARK" )
    City <- c("Las Vegas", "Reno", "Eureka", "Rockville", "Columbia", "Baltimore", "Thurmont", "Bronx", "Queens", "Yonkers", "Columbus", "Akron", "Canton")
    Rating<- c(1,2,3,4,5,6,7,8,9,10,11,12,13)
    df <- data.frame(State, County, City, Rating, stringsAsFactors = F)
    
    ui <- fluidPage(
      titlePanel("Test Dashboard "),
      sidebarLayout(
        sidebarPanel(
          selectInput("data1", "Select State", choices = c("All", unique(df$State))),
          selectInput("data2", "Select County", choices = NULL),
          selectInput("data3", "select City", choices = NULL)
        ),
        mainPanel(
          DTOutput("table")
        )
      ))
    
    server <- function(input, output, session){
      
      observeEvent(input$data1, {
        if (input$data1 != "All") {
          updateSelectInput(session, "data2", "Select County", choices = c("All", unique(df$County[df$State == input$data1])))
        } else {
          updateSelectInput(session, "data2", "Select County", choices = c("All", unique(df$County)))
        }
      }, priority = 2)
      
      observeEvent(c(input$data1, input$data2), {
        if (input$data2 != "All") {
          updateSelectInput(session, "data3", "Select City", choices = c("All", unique(df$City[df$County == input$data2])))
        } else {
          if (input$data1 != "All") {
            updateSelectInput(session, "data3", "Select City", choices = c("All", unique(df$City[df$State == input$data1])))
          } else {
            updateSelectInput(session, "data3", "Select City", choices = c("All", unique(df$City)))
          }
        }
      }, priority = 1)
      
      filtered_data <- reactive({
        temp_data <- df
        if (input$data1 != "All") {
          temp_data <- temp_data[temp_data$State == input$data1, ]
        }
        if (input$data2 != "All") {
          temp_data <- temp_data[temp_data$County == input$data2, ]
        }
        if (input$data3 != "All") {
          temp_data <- temp_data[temp_data$City == input$data3, ]
        }
        temp_data
      })
      
      output$table <- renderDT(
        filtered_data()
      )
      
    }
    
    shinyApp(ui, server)