petyar
petyar

Reputation: 535

Subsetting the input in R shiny

I have an app that subsets a data frame based on two variables and prints the result.

library(shiny)
library(tidyverse)

# Define a toy data frame in which variables are not crossed.
d = tibble(
    colour = c('blue','blue','yellow','yellow'),
    thing = c('the sea',"my lover's eyes", 'the sun', 'campari')
)


# Define UI for application that takes two vars and returns text
ui <- fluidPage(

    # Sidebar with two var filters
    sidebarLayout(
        sidebarPanel(
            selectInput("my_colour", "Pick a colour:", 
                        choices=unique(d$colour)),
            selectInput("my_thing", "Pick a thing:", 
                        choices=unique(d$thing))
        ),

        # Print text
        mainPanel(
           textOutput("my_text")
        )
    )
)

# Server logic: subset d based on input, print output
server <- function(input, output) {

    output$my_text <- renderText({
        d %>% 
            filter(
                colour == input$my_colour,
                thing == input$my_thing
            ) %>% 
            pull(thing) %>% 
            paste(collapse = ', ')
    })
}

# Run the application 
shinyApp(ui = ui, server = server)

The first sidebar input (my_colour) in principle restricts the second one (my_thing) since some things are yellow, others are blue.

Currently, picking a value for my_thing that doesn't exist in my_colour results in an empty string, which is fair enough.

I'd like to set things up so that the input choices for my_thing are restricted based on the input choice for my_colour so that when my_colour == yellow the only options available in the drop-down menu for my_thing are the sun and campari, while when my_colour == blue these are the sea and my lover's eyes.

This requires some sort of a reactive something and I'm not sure how it would work exactly.

Upvotes: 0

Views: 340

Answers (1)

stefan
stefan

Reputation: 124148

You may use uiOutput and renderUI to build a dynamic UI that reacts to the user input:

library(shiny)
library(tidyverse)

# Define a toy data frame in which variables are not crossed.
d <- tibble(
  colour = c("blue", "blue", "yellow", "yellow"),
  thing = c("the sea", "my lover's eyes", "the sun", "campari")
)

# Define UI for application that takes two vars and returns text
ui <- fluidPage(
  # Sidebar with two var filters
  sidebarLayout(
    sidebarPanel(
      selectInput("my_colour", "Pick a colour:",
        choices = unique(d$colour)
      ),
      uiOutput("my_thing")
    ),
    # Print text
    mainPanel(
      textOutput("my_text")
    )
  )
)

# Server logic: subset d based on input, print output
server <- function(input, output) {
  output$my_thing <- renderUI({
    things <- d %>% 
      filter(colour %in% input$my_colour) %>% 
      pull(thing) %>% 
      unique()
    selectInput("my_thing", "Pick a thing:", things)
  })

  output$my_text <- renderText({
    d %>%
      filter(
        colour %in% input$my_colour,
        thing %in% input$my_thing
      ) %>%
      pull(thing) %>%
      paste(collapse = ", ")
  })
}

# Run the application
shinyApp(ui = ui, server = server)
#> 
#> Listening on http://127.0.0.1:8250

Upvotes: 1

Related Questions