Search code examples
rshiny

Double for loop to check dynamic number of plots in shiny app


I find myself faced with a problem:

I already have my shiny application (server part) like this :

observe({
      data <- my_function() %>%
       filter(col1 == "X1")

h <- sort(unique(data$year))

nb <- length(h)
lst <- as.list(h)

output$plot_name <- renderUI({
  plot_output <- lapply(1:nb,
                                 function(n1) {
                                   plotname <- paste0("plots", n1)
                                   plotOutput(plotname)
                                 })
  do.call(tagList, plot_output)
})

my_data <- list()

i <- 0
for (i in 1:length(lst)) {
  
  local({
    my_i <- i
    plotname <- paste0("plots", my_i)
    my_data[[my_i]] <- data %>% 
      filter(year == lst[[my_i]])
    
    output[[plotname]] <- renderPlot({
      
      g <- ggplot(..........)
      
      print(g)
      
    })
    
  })
}


})

that allows me to output, for each year, graphs for a given X.

However I would like to remove the filter and have for each year of each X a graph, knowing that I do not have the same number of years for all X (X1: 2000, X2: 2000 and 2001, X3 : 2001 etc.....).

Since I would like to determine dynamically the number of graphs.


Solution

  • We can create all the plots inside a data frame and then count how many of them are they in order to create the corresponding outputs.

    library(tidyverse)
    library(shiny)
    
    
    df <-
      read_table("col1 col2 year pts
    X1 1 2000 24 
    X1 2 2001 36 
    X2 1 2000 48
    X1 0 2000 24
    X3 1 2000 72
    X2 1 2000 24
    X2 2 2002 48
    X3 2 2001 24")
    
    
    
    ui <- fluidPage(
      uiOutput("plot_name")
    )
    
    server <- function(input, output, session) {
      my_function <- reactive({
        df
      })
      
      observeEvent(my_function, {
        data <- my_function() 
        
    
    # Create the plots --------------------------------------------------------
    
        
        plots_df <- 
          data %>% 
          group_by(col1, year) %>%
          summarise(plot = list(
            ggplot(cur_data_all() ,aes(x = pts, y = col2)) +
              geom_point() +
              ggtitle(paste('col:', col1 ,'year:', year))
          ))
        
    
    # plots UI ----------------------------------------------------------------
    
        
        nb <- length(plots_df$plot)
        plotname <- paste0("plots", 1:nb) # save the names for renderPlot functions
    
        output$plot_name <- renderUI({
          plot_output <- lapply(
            plotname,
            function(n1) {
              plotOutput(n1)
            }
          )
          do.call(tagList, plot_output)
        })
    
    
    # renderPlot funcitons ----------------------------------------------------
    
    
        walk2(plotname, plots_df$plot, ~ {
          output[[.x]] <<- renderPlot({
            .y
          })
        })
       })
    }
    
    shinyApp(ui, server)