Best practice on adding names/values to server's output$ inside reactive context?

Hello – I need to generate some output values dynamically (i.e. a set of ggplot2 plots via renderPlot). What plots get drawn depends on an input value (so afaik the output assignments need to happen in a reactive context).

Each plot needs to be "independent" so I cannot just combine them with {patchwork}/{cowplot} as one single reactive value and assign it outside of observe() to a single/always-the-same output name.


My current understanding of mutating object in R in nested functions is that you cannot do it without a global assignment.

try_to_mutate <- function(l) {
  print(pryr::where("l"))
  purrr::walk(1:2, function(i) {
    l[[as.character(i)]] <- i # would work on parent l with <<-
    print(pryr::where("l"))
  })
  l
}

a_list <- list()
new_list <- try_to_mutate(a_list)
identical(a_list, new_list)
[1] TRUE

Here new_list will not be changed after try_to_mutate(), as the mutations happening in purrr::walk's function seem scoped to that function envs. I wouldn't try to modify a list this way usually but in the shiny reprex below, it's the only way I found.


Now, in shiny, it seems that the reprex below work and I cannot explain why.
Here is a reprex:

library(shiny)
library(dplyr)
library(purrr)
library(ggplot2)

ui <- fluidPage(
    sidebarLayout(
        sidebarPanel(
            selectInput("species", "Choose species",
                        unique(iris$Species),
                        multiple = TRUE)
        ),
        mainPanel(uiOutput("plots"))
    )
)

server <- function(input, output) {
    output$plots <- renderUI({
        plot_output_list <- purrr::map(input$species, function(sp) {
            plotOutput(paste0("plot_", sp))
        })

        do.call(tagList, plot_output_list) # needed to display properly.

        plot_output_list
    })

    observe({
        purrr::walk(input$species,
                    function(sp) {
                        plot_data <- filter(iris, Species == sp)
                        output[[paste0("plot_", sp)]] <- renderPlot({
                            ggplot(plot_data, aes(x = Sepal.Length, y = Sepal.Width)) +
                                geom_point() +
                                labs(title = sp)
            })
        })
    })

}

shinyApp(ui = ui, server = server)

I don't understand why it works with output[[paste0("plot_", sp)]] <-. I thought I would need at least a double arrow (<<-) to access output.

Thanks a lot

This topic was automatically closed 54 days after the last reply. New replies are no longer allowed.