fv8392
fv8392

Reputation: 47

Create dynamic tabs with their own content

I am trying to create an application which dynamically creates different tabs in which there is a version of my initial table filtered according to a variable (among all those selected by the CheckboxGroupInput).

For example if I try with the table iris in which there is a variable Species taking the 3 modalities virginita, setosa and versicolor, then I would like to obtain a first tab with the observations where Species = virginita, a second where Species = setosa etc ...

I found a solution on this forum for dynamically create the tabs but in all of them, the dataset obtained is the one filtered by the last input selected (here versicolor).

I suspect a problem with lapply but I'm new on R and shiny and I can't seem to find a solution.

A little help would be appreciated !

Thanks everyone!

library(shiny)

ui <- pageWithSidebar(
    headerPanel = headerPanel('iris'),
    sidebarPanel = sidebarPanel(checkboxGroupInput("filter","Choices",c("virginita","setosa","versicolor"), selected=c("virginita","setosa","versicolor"))
    ),

    mainPanel(uiOutput("my_tabs"))
)

server <- function(input, output, session) {
    df = iris

    output$my_tabs = renderUI({

        dt <- list()

        for ( i in 1:3) {
            output[[paste0("tab",as.character(i))]] <- DT::renderDataTable ({
                dt2 <- subset(df, Species==input$filter[i]) 
                return(dt2)
            })
            dt[[i]] <- DT::DTOutput(paste0("tab",as.character(i)))
        }

        criteria <- input$filter
        n=length(criteria)
        myTabs = lapply(1:n, function(j){
            tabPanel(criteria[j],
                     renderUI(dt[[j]])
            )

        })
        do.call(tabsetPanel, myTabs)
    })

}


runApp(list(ui = ui, server = server))

Upvotes: 2

Views: 334

Answers (1)

Ben
Ben

Reputation: 30474

There can be problems using for loops in shiny apps:

https://chasemc.github.io/post/the-subtleties-of-shiny-reactive-programming-lapply-and-for-loops/

Instead would use lapply.

Also, I would separate your dynamic creation of output for different tabs to an observe expression (although you could put it at the top of output$my_tabs).

In addition, I noticed that virginica was misspelled in the ui. Otherwise, this includes most of your same code and seems to work.

library(shiny)
library(DT)

ui <- pageWithSidebar(
  headerPanel = headerPanel('iris'),
  sidebarPanel = sidebarPanel(checkboxGroupInput("filter","Choices",c("virginica","setosa","versicolor"), 
                                                 selected=c("virginica","setosa","versicolor"))
  ),
  mainPanel(uiOutput("my_tabs"))
)

server <- function(input, output, session) {
  df = iris

  output$my_tabs = renderUI({
    myTabs = lapply(1:length(input$filter), function(i) {
      tabPanel(input$filter[i],
               DT::DTOutput(paste0("tab",i))       
      )
    })
    do.call(tabsetPanel, myTabs)
  })

  observe(
    lapply(1:length(input$filter), function(i) {
      output[[paste0("tab",i)]] <- DT::renderDataTable({
        subset(df, Species == input$filter[i])
      })
    })  
  ) 
}

runApp(list(ui = ui, server = server))

Upvotes: 1

Related Questions