0

I'm developing a shiny app where the user will be able to describe the room occupancy of multiple houses. The main idea of the code is to input the number of houses (inputId = 'n_houses'), i.e. the number of tabs in the mainPanel is equal to the number of houses inputed. Each house tab should be connected to a different sidebarPanel, i.e. when accessing the house tab in the mainPanel, the correspondent sidebarPanel is displayed. In the sidebarPanel, the number of rooms (inputId = 'n_rooms') of the correspondent house tab is inputed. Finally, each room is inputed with an occupancy value (inputId = 'occup'), that can be either 'liv' (living room) or 'dorm' (dormitory). Each mainPanel tab should display the occupancy of all its correspondent rooms.

A simple example of the inputs follows:

  1. n_houses = 2 (two houses)
  2. n_rooms1 = 2 (two rooms in the first house) - 2.a. occup11 = 'liv' (living room); 2.b. occup12 = 'dorm' (dormitory)
  3. n_rooms2 = 3 (three rooms in the second house) - 3.a. occup21 = 'dorm' (dormitory); 3.b. occup22 = 'liv' (living room); 3.c. occup23 = 'dorm' (dormitory) Ps.: it sums a total of 5 room occupancies.

Then, the outputs should be:

  • mainPanel tab 1 (house 1): 'Results for house 1: liv dorm dorm'
  • mainPanel tab 2 (house 2): 'Results for house 2: liv dorm'

The code chunk below shows my last efforts to solve this issue.


# shiny user interface
ui = shinyUI(
  fluidPage(
    headerPanel(
      h1('ROOMS OCCUPANCY', align = 'center')
    ),
    sidebarPanel(
      sliderInput(
        inputId = 'n_rooms',
        label = 'Choose the number of rooms in the correspondet house:',
        min = 2, max = 5, step = 1, value = 3
      ),
      uiOutput('rooms')
    ),
    mainPanel(
      sliderInput(
        inputId = 'n_houses', 
        label = 'Choose the number of houses:',
        min = 1, max = 20, step = 1, value = 1
      ),
      uiOutput('houses')
    )
  )
)

# auxiliar functions to shiny server
# generate room tab panel
GenRoomTab = function(ind_room, ind_house) {
  panel = tabPanel(
    title = paste('Room', ind_room),
    value = paste0(ind_house, ind_room),
    radioButtons(
      inputId = paste0('occup', ind_house, ind_room),
      label = 'Room occupancy:',
      choices = list('Living room' = paste0('liv', ind_house, ind_room),
                     'Dormitory' = paste0('dorm', ind_house, ind_room)),
      selected = paste0('liv', ind_house, ind_room)
    )
  )
  return(panel)
}
# generate room tabset panel
GenRoomTabset = function(ind_house, n_rooms) {
  tab_panels = lapply(1:n_rooms, GenRoomTab, ind_house)
  tabset_panel = do.call(tabsetPanel, tab_panels)
  condition_panel = list(condition = paste('input.tabselected ==', ind_house), tabset_panel)
  return(condition_panel)
}
# generate house tab panel
GenHouseTab = function(ind_house) {
  panel = tabPanel(
    title = paste('House', ind_house),
    value = ind_house,
    h4(paste('Results for house', ind_house, ':'))
  )
  return(panel)
}
# generate summary tab panel
GenSummTab = function() {
  panel = tabPanel(
    title = 'Summary'
  )
  return(list(panel))
}

# shiny server
server = shinyServer(
  function(input, output) {
    # define room tabset panels
    output$rooms = renderUI({
      room_tabsets = do.call(GenRoomTabset, list(1:input$n_houses, input$n_rooms))
      do.call(conditionalPanel, room_tabsets)
    })
    # define house tab panels
    output$houses = renderUI({
      house_tab_panels = lapply(1:input$n_houses, GenHouseTab)
      summ_tab_panel = GenSummTab()
      tab_panels = c(list(type = 'tab', id = 'tabselected'),
                     house_tab_panels, summ_tab_panel)
      do.call(tabsetPanel, tab_panels)
    })
  }
)

# associate ui to server

shinyApp(ui = ui, server = server)

When I run this code the following warning message shows up:

Warning: Error in radioButtons: The 'selected' argument must be of length 1 105: stop 104: radioButtons 100: FUN [/home/rodox/git/giz/app/app.r#29] 99: lapply 98: [/home/rodox/git/giz/app/app.r#44] 96: renderUI [/home/rodox/git/giz/app/app.r#71] 95: func 82: origRenderFunc 81: output$rooms 1: runApp

I think it is related to selected = paste0('liv', ind_house, ind_room), inside function GenRoomTab(). The GenRoomTab() is applied within lapply(1:n_rooms, GenRoomTab, ind_house), inside the function GenRoomTabset(). However it seems strange to me, since ind_house is a vector as well as ind_room.

Another difficulty that I have is to display the occupancy of all the rooms into the correspondent house tab.

I've been trying to solve this for a while, but couldn't solve it... I hope someone can save me!

  • Welcome to SO! "I'm stuck" isn't really a helpful description of your problem. What doesn't work? What error messages do you get, if any? What is the desired outcome? Although the OP's question was different to yours, my answer [this post](https://stackoverflow.com/questions/62341353/saving-dynamic-ui-to-global-r-workspace/62342118#62342118) demonstrates one way of generating a dynamic UI with elements that vary depending on a user's input. – Limey Jun 18 '20 at 06:55
  • Thanks a lot for your feedback @Limey, my description was really short and not helpful. I edited the post and hopefully you'll have a better overview of the problem. I'll take a look at the post you recommended and keep you updated if a found a solution. –  Jun 18 '20 at 21:33

0 Answers0