2
votes

I've been trying to extend the second solution posted by Ramnath (the one using updateSelectInput) in the problem originally posted at R shiny passing reactive to selectInput choices . I'd like to allow the user to select inputs from a hierarchical series of inputs where the choice in each selection updates the possible values in the next selection. As an example, in the following I modify Ramnath's code by simply adding a third input that lists the values of the variable selected in the second input. This example is based on the mtcars and iris datasets, and was run on R v 3.1.1 and RStudio v 0.98.1062. It doesn't throw an error but you'll see that I'm stuck on how to add a second reactive() that takes as its input a combination of input$dataset and input$column.

library(shiny)

runApp(list(

  ui = bootstrapPage(
    selectInput('dataset', 'Choose data set', c('mtcars', 'iris')),
    selectInput('columns', 'Choose variable', ""),
    selectInput('values', 'Show values', "")
  ),

  server = function(input, output, session){

    # updates variable names based on selected dataset 
    outVar = reactive({
      names(get(input$dataset))
    })

    # i want this to update the values of the selected variable
    outVar2 = reactive({
      sort(unique(get(input$dataset)[, 2]))  # this works but of course I don't want the second variable every time
      #sort(unique(get(input$dataset)[, input$columns]))   # this fails but this is the idea I'm after
    })

    # i want these to update the UI based on the reactive output above 
    observe({
      updateSelectInput(session, "columns", choices = outVar())
      updateSelectInput(session, "values", choices = outVar2())
    })       
  }
))
1
possible duplicate of R shiny passing reactive to selectInput choices, one way to do what you want is to wrap the selectInput in a renderUI on the server side.Alex

1 Answers

3
votes

Responding to my first ever question. Seems this is old but since I've been playing around with Shiny for the past week, I figured I would help answer this one directly.

To answer the question directly, the sort(unique(get(input$dataset)[, input$columns])) statement doesn't fail, it is the observe statement. Because both outVar() and outVar2() are in the observe statement, the observe statement will run when either variable updates. Therefore, when a change to the second selectInput (the input$columns variable), it will actually cause the first selectInput to update via updateSelectInput(session, "columns", choices = outVar()).

This then resets the column dropdown list back to the original choice, making it seem as if the application is broken. To see this in slow motion, I would recommend adding a browser() call in the observe statement to how the code steps through:

observe({
  browser()
  updateSelectInput(session, "columns", choices = outVar())
  updateSelectInput(session, "values", choices = outVar2())
})

Overall, I broke up the observe statement into 2 observeEvent statements (I got errors when only breaking the statement up into two separate observe statements when I changed the dataset). By wrapping the updateSelectInput functions in the observeEvent they will only try to run when the necessary input is actually updated as seen below:

library(shiny)

runApp(list(

  ui = bootstrapPage(
    selectInput('dataset', 'Choose data set', c('mtcars', 'iris')),
    selectInput('columns', 'Choose variable', ""),
    selectInput('values', 'Show values', "")
  ),

  server = function(input, output, session){

    # updates variable names based on selected dataset 
    outVar = reactive({
      names(get(input$dataset))
    })

    # i want this to update the values of the selected variable
    outVar2 = reactive({
      if (input$columns == "") return()
      sort(unique(get(input$dataset)[, input$columns]))
    })

    # create separate observeEvents to 
    observeEvent(input$dataset, {
      updateSelectInput(session, "columns", choices = outVar())
    })

    observeEvent(input$columns, {
      updateSelectInput(session, "values", choices = outVar2())
    })

  }
))