Search code examples
javascriptrshinyshinybsselectinput

Expand/Collapse Shiny selectInput function


I would like to find a resource that would allow my Shiny selectInput function to expand/collapse based on the category headings that I have created. I have searched through some bootstrap resources, but am not yet successful. Please forgive my minimal working example, I acknowledge that there may be more efficient ways to provide a MWE. Thanks for any advice you can offer.

library(shiny)
library(tidyverse)
#create a quick dataset to plot
schools <-  as.data.frame(table(
    c('Adams', 'Van Buren', 'Clinton', 'Douglas', 'Edwards', 
              'Franklin', 'Grant', 'Harrison', 'Ignatius', 'Justice', 
              'Kellogg', 'Lincoln'), 
    dnn = list("school")))

enrollment <- as.data.frame(table(
    c(300, 305, 265, 400, 500, 450, 475, 900, 800, 850, 1200, 1500), 
    dnn = list("enrollment")))

schoolsDataframe <- schools %>% 
    bind_cols(enrollment) %>% 
    select(school, enrollment)

#define data elements for selectInput choices argument
elem <- c('Adams', 'Van Buren', 'Clinton', 'Douglas')
mid <- c('Edwards', 'Franklin', 'Grant')
high <- c('Harrison', 'Ignatius', 'Justice')
multi <- c('Kellogg', 'Lincoln')

# Define UI 
ui <- fluidPage(
    tags$style(".optgroup-header { color: #FFFFFF !important; background: #000000 !important; }"),
    # Application title
    titlePanel("Expandable selectInput"),

    # Sidebar with a select input
    sidebarLayout(
        sidebarPanel(
            selectInput(inputId = 'schoolsInput',
                        label = 'Select a school',
                        choices = list('Elementary' = elem, 
                                       'Middle' = mid, 
                                       'High' = high, 
                                       'Multi-level' = multi), 
                        selectize = TRUE)
        ),

        # Show a plot 
        mainPanel(
           plotOutput("myPlot")
        )
    )
)

# Define server logic required to draw a plot
server <- function(input, output) {

    output$myPlot <- renderPlot({
        #filter the data based on selectInput
schoolsDataframe <- schoolsDataframe %>% 
    filter(school == input$schoolsInput)
        # draw the plot
ggplot(data = schoolsDataframe, 
       mapping = aes(x = school, 
                     y = enrollment))+
    geom_col()
    })
}

# Run the application 
shinyApp(ui = ui, server = server)

enter image description here

enter image description here


Solution

  • Here's a start for you, although it may not be exactly what you want. I think you want a dynamic selection list, based on the school type (elementary, middle...). Here's a way you can do that with 2 selection lists, where the lower one is dynamic, responding to the choice in the upper selection list.

    I also tried to simplify your data setup. You can copy/paste the code to run it.

    library(shiny)
    library(tidyverse)
    
    #define data elements 
    schools <- data.frame (schoolName=  c('Adams', 'Van Buren', 'Clinton', 'Douglas', 'Edwards','Franklin', 'Grant', 'Harrison', 'Ignatius', 'Justice', 'Kellogg', 'Lincoln'),
                          schoolType = c('Elementary','Elementary','Elementary','Elementary','Middle','Middle','Middle','High','High','High','Multi-level','Multi-level'),
                          schoolEnrollment = c(300, 305, 265, 400, 500, 450, 475, 900, 800, 850, 1200, 1500))
    
    # Define UI 
    ui <- fluidPage(
      tags$style(".optgroup-header { color: #FFFFFF !important; background: #000000 !important; }"),
      # Application title
      titlePanel("Expandable selectInput"),
    
      # Sidebar with a select input
      sidebarLayout(
        sidebarPanel(
          selectInput(inputId = 'schoolType',
                      label = 'Select a School Type',
                      choices = list('Elementary',
                                     'Middle', 
                                     'High', 
                                     'Multi-level'), 
                      ),
          selectInput("schoolName", "Select School:","Elementary"),
        ),
    
        # Show a plot 
        mainPanel(
          plotOutput("myPlot")
        )
      )
    )
    
    # Define server logic required to draw a plot
    server <- function(input, output, session) {
    
      # Set up the selection for counties
      observe ({
        selectionSchoolNames <- sort(unique(unlist(subset(schools$schoolName,schools$schoolType==input$schoolType))))
        updateSelectInput(session, "schoolName", choices = selectionSchoolNames)
      })
    
      output$myPlot <- renderPlot({
        #filter the data based on selectInput
        schoolsDataframe <- schools %>% 
          filter(schoolType == input$schoolType)
        # draw the plot
        ggplot(data = schoolsDataframe, 
               mapping = aes(x = schoolName, 
                             y = schoolEnrollment))+
          geom_col()
      })
    }
    
    # Run the application 
    shinyApp(ui = ui, server = server)