Reputation: 1271
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:
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.
Upvotes: 0
Views: 499
Reputation: 389275
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)
Upvotes: 2