0

There are several questions on this issue, including here, but I am still not sure what I need to change to get this right.

The selectInput choices are working as expected, other than when I change the second selectInput, it temporarily changes to the desired selection but then automatically goes back to the first filtered selection.

For example, if "gear" is chosen for Variable 1, then the Variable 1 choices correctly display "3, 4, 5" for possible gear choices. If I select "5" for gear, it briefly shows up and then goes back to gear "3" as a choice. I am not sure how to prevent that reactive behavior.

Here is a simple reproducible example using the mtcars built-in data set:

library(tidyverse)
library(shiny)



# Variables interested in selecting
my_vars <- c("cyl", "gear", "carb")



# UI
ui <- fluidPage(
  
  # Title
  titlePanel("Reprex"),
  
  # Sidebar 
  sidebarLayout(
    sidebarPanel(
                 selectInput("sel_1",
                             "Variable 1",
                             choices  = my_vars,
                             selected = my_vars[[1]],
                             multiple = FALSE
                 ),
                 selectInput("sel_2",
                             "Variable 1 choices",
                             choices  = unique(mtcars[[ my_vars[[1]] ]]),
                             multiple = FALSE
                 )
    ), # sidebarPanel close
    
    # Plot
    mainPanel(
      plotOutput("plot_out")
    )  # mainPanel close
  )    # sidebarLayout close
)      # UI close




# Server
server <- function(input, output, session) {
  
  output$plot_out <- renderPlot({
    
    # Assign inputs
    sel_1 <- input$sel_1
    sel_2 <- input$sel_2
    
    
    # Make drop-down choice of sel_2 dependent upon user input of sel_1
    # *** Must put "shiny::observe" instead of "observe" since "observe" is masked by the Tidy infer package ***
    shiny::observe({
      updateSelectInput(session,
                        "sel_2",
                        choices = sort(unique(mtcars[[sel_1]]))
                        )
    })
    
    
    
    # Data to plot
    my_data <- mtcars %>% 
      filter(.data[[sel_1]] == sel_2)

    
    
    # Plot
    p <- ggplot(my_data, aes(x = factor(.data[[sel_1]]), y = hp)) + geom_point()
    p
    
  })
}




# Run the application 
shinyApp(ui = ui, server = server)
DaveM
  • 664
  • 6
  • 19

1 Answers1

1

That's because your observer is inside the renderPlot. It has nothing to do here.

server <- function(input, output, session) {

  # Make drop-down choice of sel_2 dependent upon user input of sel_1
  observeEvent(input$sel_1, {
    updateSelectInput(session,
                      "sel_2",
                      choices = sort(unique(mtcars[[input$sel_1]]))
    )
  })
  
  output$plot_out <- renderPlot({
    
    # Assign inputs
    sel_1 <- input$sel_1
    sel_2 <- input$sel_2
    
    # Data to plot
    my_data <- mtcars %>% 
      filter(.data[[sel_1]] == sel_2)
    
    # Plot
    ggplot(my_data, aes(x = factor(.data[[sel_1]]), y = hp)) + geom_point()

  })
}

Here the observeEvent instead of observe is not necessary, since input$sel_1 is the only reactive value inside the observer, but I find that observeEvent is more readable.

Also, avoid to load tidyverse. That loads a ton of packages you don't need. Here dplyr and ggplot2 are enough

Stéphane Laurent
  • 75,186
  • 15
  • 119
  • 225
  • Agree that `observeEvent` is more clear. Thanks for pointing out the issue with having the reactive (observe) within another reactive (renderPlot) – DaveM Mar 15 '22 at 15:31