rshinyshinyjsvtree

How to organize selectizeInput fields with dependecies on each other


I have this working app: It is a follow-up question of some previous questions:

library(shiny)
library(vtree)

df <- tibble(A = c(rep("nature", 18), rep("not nature", 9)),
  B = rep(c("animal", "plant", "machine"), each=9),
       C = c(rep(c("dog", "cat", 'mouse'), 3),
             rep(c("tree", "flower", "grass"), 3),
             rep(c("car", "plane", "train"), 3)
             )
       )

# Define UI ----
ui <- pageWithSidebar(
  
  # App title ----
  headerPanel("my app"),
  
  # Sidebar panel for inputs ----
  sidebarPanel(
    selectizeInput("levels", label = "Levels", choices = NULL, multiple = TRUE),
    selectizeInput("valuesA", label= "Values_A", choices = NULL, multiple=TRUE),
    selectizeInput("valuesB", label= "Values_B", choices = NULL, multiple=TRUE),
    selectizeInput("valuesC", label= "Values_C", choices = NULL, multiple=TRUE),
  ),
  
  # Main panel for displaying outputs ----
  mainPanel(
    vtreeOutput("VTREE")
    
  )
)

# Define server logic to plot ----
server <- function(input, output,session) {
  df <- reactiveVal(df)
  vector <- c("A","B", "C")
  
  
  observe({
    updateSelectizeInput(session, "levels", choices = colnames(df()[vector]), selected = NULL) 
    updateSelectizeInput(session, "valuesA", choices = unique(df()$A))
    updateSelectizeInput(session, "valuesB", choices = unique(df()$B))
    updateSelectizeInput(session, "valuesC", choices = unique(df()$C))
  })
  
  output[["VTREE"]] <- renderVtree({
    vtree(df(), c(input$levels),
          sameline = TRUE,
          keep=list(A=input$valuesA,
                    B = input$valuesB,
                    C = input$valuesC),
          pngknit=FALSE,
          horiz=TRUE,height=450,width=850)
  })
  
}
shinyApp(ui, server)

I want to control the selectizeInput fields in that way that they dependent on each other: Let me explain:

Scenario 1: If Levels == A the user should be able to select from Values_A, not Values_B and not Values_C.

In ValuesA

enter image description here

enter image description here

Scenario 2: If Levels==A and Values_A == nature then in Values_B only animal and plant should be visible to select and not machine because machine is not nature. enter image description here

Scenario 3: If Levels == A and Values_A == nature and Values_B == animal then in Values_C only dog cat mouse should be visible:

enter image description here


Solution

  • Hi I think this does what you are looking for

    library(shiny)
    library(vtree)
    library(dplyr)
    
    df <- tibble(A = c(rep("nature", 18), rep("not nature", 9)),
                 B = rep(c("animal", "plant", "machine"), each=9),
                 C = c(rep(c("dog", "cat", 'mouse'), 3),
                       rep(c("tree", "flower", "grass"), 3),
                       rep(c("car", "plane", "train"), 3)
                 )
    )
    
    # Define UI ----
    ui <- pageWithSidebar(
      
      # App title ----
      headerPanel("my app"),
      
      # Sidebar panel for inputs ----
      sidebarPanel(
        selectizeInput("levels", label = "Levels", choices = NULL, multiple = TRUE),
        selectizeInput("valuesA", label= "Values_A", choices = NULL, multiple=TRUE),
        selectizeInput("valuesB", label= "Values_B", choices = NULL, multiple=TRUE),
        selectizeInput("valuesC", label= "Values_C", choices = NULL, multiple=TRUE),
      ),
      
      # Main panel for displaying outputs ----
      mainPanel(
        vtreeOutput("VTREE")
        
      )
    )
    
    # Define server logic to plot ----
    server <- function(input, output,session) {
      df_A <- reactive({
        filtered_df <- df
        if(!is.null(input$valuesA)){
          filtered_df <- filtered_df %>% 
            filter(A %in% input$valuesA)
        }
        filtered_df
      })
      df_B <- reactive({
        if(!is.null(input$valuesB)){
          filtered_df <- df_A() %>% 
            filter(B %in% input$valuesB)
        } else {
          df_A()
        }
      })
      df_C <- reactive({
        if(!is.null(input$valuesC)){
          df_B() %>% 
            filter(C %in% input$valuesC)
        } else {
          df_B()
        }
      })
      vector <- c("A","B", "C")
      
      
      observe({
        # browser()
        updateSelectizeInput(session, "levels", choices = colnames(df[vector]), selected = input$levels) 
        updateSelectizeInput(session, "valuesA", choices = unique(df$A), selected = input$valuesA)
        updateSelectizeInput(session, "valuesB", choices = unique(df_A()$B), selected = input$valuesB)
        updateSelectizeInput(session, "valuesC", choices = unique(df_B()$C), selected = input$valuesC)
      })
      
      output[["VTREE"]] <- renderVtree({
        vtree(df_C(), c(input$levels),
              sameline = TRUE,
              keep=list(A=input$valuesA,
                        B = input$valuesB,
                        C = input$valuesC),
              pngknit=FALSE,
              horiz=TRUE,height=450,width=850)
      })
      
    }
    shinyApp(ui, server)
    

    Hope this helps, Bertil