R Shiny, Module Input Parameters Not Updating Unless Outside of Reactive Context

Hey all,

I encountered some strange (to me) behavior when I was writing a shiny app with dynamically rendered modules in dashboard tabs. I have a here my reduced app which calls one module twice to produce two different volcano plots representing gene expression from different studies. The modules' servers are stored in a reactiveValues object like this:

module_outputs <- reactiveValues()

 for(i in 1:length(input_data)){
        study <- names(input_data)[i]
        module_outputs[[paste0(study,"_gexpi")]] <- volcano_server(id = paste0(study,"_gexp"), 
                                                                  gprofiler = input_data[[study]]$data$gp_result,
                                                                  dataset = input_data[[study]]$data$gene_expression
                                                                  )
}

where input_data is my gene expression data and is defined like this:

    data_scer <- read.csv("test_data\\GSE4136_25thGen.csv")
    data_cele <- read.csv("test_data\\GSE27338.csv")
   
    scer <- process_data(data_scer, "GSE4136", "scerevisiae")
    cele <- process_data(data_cele, "GSE27338", "celegans")
    
    input_data <- list("GSE4136" = scer,"GSE27338" = cele)

When the app is run, everything works normally except that it refuses to generate two different plots; it would pass the same data through both plots when rendered. Assuming I must have mixed up the ids somewhere, I set a breakpoint at line 116 and stepped through the function calls to get to my module. When in debug mode and after referencing my parameters in the browser to check what they were (dataset and gprofiler), my data suddenly appears in the environment and the expected result is returned. If I simply step through my module then it seems that the parameters do not update and only use the last ones available to it.

The app is on github here

The solution I have for now is to just rename the parameters in the module server, somehow forcing them into the environment.

volcano_server <- function(id, gprofiler, dataset, label = NULL){
    moduleServer(id, 
                 function(input, output, session){
                    
                     ns <- session$ns

                     #added calls to the parameters or else these aren't updated
                     data <- dataset
                     gp <- gprofiler
                     
                     filtered_data <- reactive({
                                                if(input$term_type != "all"){
                                                    genes <- dplyr::filter(gp$result, 
                                                                       source == input$term_type)$intersection
                                                    genes <- unique(unlist(sapply(genes, .format_intersection, USE.NAMES = F)))
                                                    dataset[which(data$Entrez.ID %in% genes),] %>% na.omit
                                                    } else {
                                                        data %>% na.omit
                                                    }
                         
                                                })
                     
                     output$plot <- renderPlotly(
                         volcanoly(filtered_data(), gene = "Entrez.ID", 
                                   effect_size = "logFC", 
                                   p = "adj.P.Val", 
                                   genomewideline = -log10(1e-2), effect_size_line = FALSE, 
                                   snp = "Gene.symbol", annotation1 = "adj.P.Val", title = NULL))
                     
                    
                    })
}

Since this drove me up the wall for a couple of days, I just wanted to know if this behavior is a genuine bug or me just missing some essential information on how shiny handles parameters in modules.

Thanks a ton,
Ben.

its interesting, it does seem like unexpected/undesirable behaviour.

library(shiny)

test_UI <- function(id) {
  ns <- NS(id)
  tagList(uiOutput(ns("modout")))
}

test_Server <- function(id, modcontent) {
  moduleServer(
    id,
    function(input, output, session) {
      stopifnot(is.reactive(modcontent))
      
      output$modout <- renderUI({
        mc <- req(modcontent())
        HTML(mc)
      })


      retvalue <- reactive({
        mc <- req(modcontent())
        substr(mc, 1, 1)
      })

      return(reactive(paste(id, retvalue())))
    }
  )
}

library(shiny)

ui <- fluidPage(
  p("test two modules"),
  textInput("mcont1", label = "Type Here", value = "First"),
  test_UI("t1"),
  textInput("mcont2", label = "Type Here", value = "Second"),
  test_UI("t2")
)

server <- function(input, output, session) {
  # module_outputs <- reactiveValues()

  shiny::isolate({
    for (i in 1:2) {
      modid <- paste0("t", i)
      mcid <- paste0("mcont", i)

      print(paste("module id about to create:",
                  modid,"input id:" ,
                  mcid , "current value:",
                  input[[mcid]]))

      # module_outputs[[modid]] <-
      test_Server(
        id = modid,
        modcontent = reactive(input[[mcid]])
      )
    }
  })
}

shinyApp(ui, server)
1 Like

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

If you have a query related to it or one of the replies, start a new topic and refer back with a link.