0

I am trying to dynamically update a selectInput() value based on a dynamically updated selectInput() value. I can get the first value to update dynamically, but when I try and use those to update further values, I get an error:

Warning: Error in [.data.frame: undefined columns selected
  [No stack trace available]

The behavior I am looking for is:

  1. Select a variable from a dataframe
  2. Filter the dataframe for a selection of values from that variable
  3. Select another variable from the dataframe
  4. Filter the dataframe for a selection of values from that variable

Once a variable has been selected, I don't want that choice to appear as an option in subsequent selections. I want the filter options to populate based on the variable selected.

Here is a reproducible example:

library('shiny')

#create sample data
df = data.frame('first.name' = c('peter', 'paul', 'patricia'), 
                  'family.name' = c('smith', 'jones', 'gibbon'), 
                  'language' = c('english', 'french', 'spanish'))
#create the UI
ui <- fluidPage(
  
  #Create first selector for variable 1, based on column names
  selectInput(inputId = 'var1', 
              label = 'Variable 1', 
              choices = colnames(df)),
  
  #create selector for filtering, populated based on the selection for variable 1
  #leave values for label and choice blank - to be populated by updateSelectInput()
  selectInput(inputId = 'var1_subselect', 
              label = '', 
              choices = ''),
  
  #create selector for variable 2, should not include variable one
  selectInput(inputId = 'var2', 
              label = 'Variable 2', 
              choices = ''),
  
  #create selector for filtering, populated based on the selection for variable 2
  selectInput(inputId = 'var2_subselect', 
              label = '', 
              choices = '')
  
)

#Create the server
server <- function(session, input, output) {
 observe({
   updateSelectInput(session, 
                     inputId = 'var1_subselect', #for var1_subselect
                     label = paste(input$var1, 'selection:'), #Get the label from the value for var1
                     choices = unique(df[input$var1])) #Get the choices based on unique values far var1
 })
  
  observe({
    updateSelectInput(session, 
                      inputId = 'var2', #for var2
                      label = 'Variable 2', #Label is standard 
                      choices = setdiff(colnames(df), input$var1)) #Get choices from the colnames for the df, excluding the choice for var1
  })
  
  #Everything works up to this point, however when i add the following effort to filter the values for var 2, i get an error
  
  observe({
    updateSelectInput(session, 
                      inputId = 'var2_subselect', #for var2_subselect
                      label = paste(input$var2, 'selection:'), #Get the label from the value for var2
                      choices = unique(df[input$var2])) #Get the choices based on the unique values of var2
  })
  
}

#call the app
shinyApp(ui, server)

As soon as I call that third observe({}) function, I get an error. I presume this is because I am trying to call an input that is reactive based on a reactive input.

I tried to solve this using uiOutput() in my UI and renderUI({}) in my server, but ran into the same problem once i got to trying to dynamically update content, based on dynamically updated content.

1 Answer 1

2

A small and simple fix would be to filter the data with [[ instead of [. The higher level difference between the two is explained in this post The difference between bracket [ ] and double bracket [[ ]] for accessing the elements of a list or dataframe .

Here, [[ always returns a vector whereas [ returns a dataframe which works for most of the cases as you expect but fails when there is no selection made for var2 yet meaning when var2 is empty.

[ returns

df['']

Error in [.data.frame(df, "") : undefined columns selected

this is the error message that you receive.

whereas with [[ it returns NULL.

df[['']]
#NULL

which is accepted by choices argument in selectInput.


Complete code -

library(shiny)

#create sample data
df = data.frame('first.name' = c('peter', 'paul', 'patricia'), 
                'family.name' = c('smith', 'jones', 'gibbon'), 
                'language' = c('english', 'french', 'spanish'))
#create the UI
ui <- fluidPage(
  
  #Create first selector for variable 1, based on column names
  selectInput(inputId = 'var1', 
              label = 'Variable 1', 
              choices = colnames(df)),
  
  #create selector for filtering, populated based on the selection for variable 1
  #leave values for label and choice blank - to be populated by updateSelectInput()
  selectInput(inputId = 'var1_subselect', 
              label = '', 
              choices = ''),
  
  #create selector for variable 2, should not include variable one
  selectInput(inputId = 'var2', 
              label = 'Variable 2', 
              choices = ''),
  
  #create selector for filtering, populated based on the selection for variable 2
  selectInput(inputId = 'var2_subselect', 
              label = '', 
              choices = '')
  
)

#Create the server
server <- function(session, input, output) {
  observe({
    updateSelectInput(session, 
                      inputId = 'var1_subselect', #for var1_subselect
                      label = paste(input$var1, 'selection:'), #Get the label from the value for var1
                      choices = unique(df[[input$var1]])) #Get the choices based on unique values far var1
  })
  
  observe({
    updateSelectInput(session, 
                      inputId = 'var2', #for var2
                      label = 'Variable 2', #Label is standard 
                      choices = setdiff(colnames(df), input$var1)) #Get choices from the colnames for the df, excluding the choice for var1
  })
  
  observe({
     updateSelectInput(session, 
                       inputId = 'var2_subselect', #for var2_subselect
                       label = paste(input$var2, 'selection:'), #Get the label from the value for var2
                       choices = unique(df[[input$var2]])) #Get the choices based on the unique values of var2
   })
  
}

#call the app
shinyApp(ui, server)

enter image description here

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks. An oversight on my end.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.