DavidH
DavidH

Reputation: 639

Shiny displaying only one choice (among several) in pulldown menu

I am new to Shiny, and the answers to similar questions as mine on SO are helping me.

I want to display dynamic choices on the pull down menu, depending on what the user chooses on the radio button. But the snippet below can only show one choice for the subspecies, once the user chooses, first #1 the animal type, and then #2 the whole vs. subspecies choice.

I have three variables: #1. animal type (Lion vs Tiger); #2. whole vs subspecies (radiobutton); #3. subspecies (and if the user chooses "whole" in #2, then the subspecies should be equal to "Not Applicable").

FYI:

Any help is appreciated. Thanks.

    library(shiny)
    if (interactive()) {

    ui <- fluidPage(
     selectizeInput("VarAnimal",
               label = "Animal",
               choices = c("Tiger", "Lion"),
               selected = "Tiger"),

     radioButtons("VarWholeOrSub", 
             "Whole or Sub",
              choices = c("Whole species", "Subspecies"),
              selected = "Whole species"), 

     selectizeInput("VarSubspecies",
               label = "Subspecies",
               choices = c("Not Applicable", "Bengal", "Siberian", "Barbary", "Southwest African", "Transvaal"),
               selected = "")
    )

    server <- function(input, output, session) {
    observe({
       x <- input$VarWholeOrSub

       if (input$VarWholeOrSub == "Whole species"){
         x <- c("Not Applicable")} else{
         x <- ifelse(input$VarAnimal == "Tiger", c("Bengal", "Siberian"), c("Barbary", "Southwest African", "Transvaal"))  
    }

      updateSelectizeInput(session,
                       "VarSubspecies",
                       choices = x)

    })
    }


    shinyApp(ui, server)
    }

Upvotes: 0

Views: 148

Answers (3)

Sandipan Dey
Sandipan Dey

Reputation: 23101

Couple of points:

(1) As mentioned in the previous posts, ifelse is the culprit here. ?ifelse says

ifelse(test, yes, no)
ifelse returns a value with the same shape as test

which is one in your case, you should use if-else block as suggested.

(2) You may want to have less hard-coding in your code, by separating out the data (may be globally, so that later you don't need to change your R code to change data) and getting rid of some redundant codes:

df <- data.frame(Animals = c("Tiger", "Lion"), 
                 WholeSpecies=rep("Not Applicable", 2),
                 SubSpecies=c("Bengal, Siberian", "Barbary, Southwest African, Transvaal"), 
                 stringsAsFactors = FALSE)
head(df)
#  Animals   WholeSpecies                            SubSpecies
#1   Tiger Not Applicable                      Bengal, Siberian
#2    Lion Not Applicable Barbary, Southwest African, Transvaal

library(shiny)
if (interactive()) {

  ui <- fluidPage(
    selectizeInput("VarAnimal",
                   label = "Animal",
                   choices = df$Animals,
                   selected = df$Animals[1]),

    radioButtons("VarWholeOrSub", 
                 "Whole or Sub",
                 choices = c("Whole species", "Subspecies"),
                 selected = "Whole species"), 

    selectizeInput("VarSubspecies",
                   label = "Subspecies",
                   choices = c(unique(df$WholeSpecies), unlist(strsplit(unique(df$SubSpecies), split=','))),
                   selected = "")
  )

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

      x <- df[df$Animals==input$VarAnimal,]$WholeSpecies

      if (input$VarWholeOrSub == "Subspecies"){
        x <- unlist(strsplit(df[df$Animals==input$VarAnimal,]$SubSpecies, split=','))
      }

      updateSelectizeInput(session,
                           "VarSubspecies",
                           choices = x)

    })
  }

  shinyApp(ui, server)
}

enter image description here

Upvotes: 1

HubertL
HubertL

Reputation: 19544

The problem comes from the use of ifelse(test, yes, no) when yes or no have different length of test:

> ifelse("a"=="a", c("a","b"), c("b","a"))
[1] "a"
> ifelse(rep("a"=="a",2), c("a","b"), c("b","a"))
[1] "a" "b"

In your case - with 3 different lengths - you should use if instead:

  if (input$VarWholeOrSub == "Whole species"){
    x <- c("Not Applicable")
    } else {
      if(input$VarAnimal == "Tiger")
        x <- c("Bengal", "Siberian")
      else
        x <- c("Barbary", "Southwest African", "Transvaal")
    }

Upvotes: 2

krish
krish

Reputation: 1438

The documentation for ifelse states:

ifelse returns a value with the same shape as test which is filled with elements selected from either yes or no depending on whether the element of test is TRUE or FALSE.

library(shiny)
if (interactive()) {

  ui <- fluidPage(
    selectizeInput("VarAnimal",
                   label = "Animal",
                   choices = c("Tiger", "Lion"),
                   selected = "Tiger"),

    radioButtons("VarWholeOrSub", 
                 "Whole or Sub",
                 choices = c("Whole species", "Subspecies"),
                 selected = "Whole species"), 

    selectizeInput("VarSubspecies",
                   label = "Subspecies",
                   choices = c("Not Applicable", "Bengal", "Siberian", "Barbary", "Southwest African", "Transvaal"),
                   selected = "")
  )

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

      if (input$VarWholeOrSub == "Whole species"){
        updateSelectizeInput(session, 'VarSubspecies', choices = c("Not Applicable"))
        } else{
          if(input$VarAnimal == "Tiger"){
            updateSelectizeInput(session, 'VarSubspecies', choices = c("Bengal", "Siberian"))
          } else if (input$VarAnimal == "Lion"){
            updateSelectizeInput(session, 'VarSubspecies', choices = c("Barbary", "Southwest African", "Transvaal"))
          }
        }
    })
  }


  shinyApp(ui, server)
} 

Upvotes: 1

Related Questions