ruser-interfaceshinyuser-inputorganization

What are the options in R Shiny for funneling a user through many choices in performing complex data analysis?


I am working on an App where the user needs to walk through many, many choices to get to where he/she wants to go with data analysis. The App needs to easily "funnel" the user through the myriad choices without confusing the user, without leading the user into dead ends, etc. For example, funneling a user from general to more specific choices:

The image below shows the overall "funneling" structure I am thinking of using tabs/sidebar/main panel. In Shiny are there other efficient and clear ways to funnel a user through many choices?

enter image description here

Reproducible code for the skeleton structure shown in the image:

library(shiny)
library(shinyjs)

ui <- 
  
  pageWithSidebar(
    
    headerPanel("Test"),
    sidebarPanel(
      useShinyjs(),
      fluidRow(helpText(h5(strong("Base Input Panel")),align="center")),
      conditionalPanel(
        condition="input.tabselected==1",
        h5("Selections for Tab 1:")
        ),
      conditionalPanel(
        condition="input.tabselected==2",
        h5("Selections for Tab 2:")
        )
      ), # close sidebar panel
    
    mainPanel(
      useShinyjs(),
      tabsetPanel(
        
        tabPanel("Tab 1", value=1,helpText("Tab 1 outputs")), 

        conditionalPanel(condition = "input.tabselected==1",
            fluidRow(helpText("Tab 1 things happen here")),
          ),                 
        
          tabPanel("Tab 2", value=2,
           
           fluidRow(
              radioButtons(
                 inputId = 'mainPanelBtnTab2',
                 label = h5(strong(helpText("Functions to access:"))),
                 choices = c('Function 1','Function 2','Function 3'),
                 selected = 'Function 1',
                 inline = TRUE
               ) # close radio buttons
             ), # close fluid row
           
           conditionalPanel(condition = "input.tabselected==2",
             fluidRow(helpText("Tab 2 things happen here")),              
             conditionalPanel(condition = "input.mainPanelBtnTab2 == 'Function 1'",
                              helpText("You pressed radio button 1")), 
             conditionalPanel(condition = "input.mainPanelBtnTab2 == 'Function 2'",
                              helpText("You pressed radio button 2")),
             conditionalPanel(condition = "input.mainPanelBtnTab2 == 'Function 3'",
                              helpText("You pressed radio button 3"))
             
             ) # close conditional panel
        ),  # close tab panel
        id = "tabselected"
      ) # close tabsetPanel
    ) # close mainPanel
  ) # close pageWithSidebar

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

shinyApp(ui, server)

Solution

  • One way you can approach this is by updating the input choices with updateSelectInput on the server side. If you define all combinations of countries, provinces, and variables in a dataframe, you can filter this dataframe according to user inputs.

    In the simplified example below, the options for province(s) are updated based on the country selection. You could add a third layer for variable type with similar logic.

    library(shiny)
    
    df <- data.frame(
      country = c(rep("U.S.", 2), rep("Canada", 2)),
      province = c("California", "Oregon", "British Colulmbia", "Alberta")
    )
    
    ui <- fluidPage(
    
        sidebarLayout(
            sidebarPanel(
              selectInput("country", "Country", unique(df$country), multiple = T),
              selectInput("province", "Province:", "Select a country first", multiple = T)         
            ),
    
            mainPanel(
            )
        )
    )
    
    server <- function(input, output, session) {
    
      observe({
        
        # update options based on country selection
        province_list <- df %>%
          filter(country %in% input$country)
        
        # update selector
        updateSelectInput(session, "province", "Province:", choices = unique(province_list$province))
        
      })
      
    }
    
    shinyApp(ui = ui, server = server)
    

    enter image description here