【问题标题】:How to include R6 objects to share data across modules in golem Shiny app如何在 golem Shiny 应用程序中包含 R6 对象以跨模块共享数据
【发布时间】:2021-07-08 13:38:43
【问题描述】:

我第一次尝试使用golem 创建一个Shiny 应用程序。 golem 结构 Shiny 带有模块的应用程序有助于保持大型 Shiny 应用程序模块化。但是,默认情况下,模块不会相互通信。我想跨模块共享数据。根据golem 文档,R6 objects are a useful way to share data across modules

但是,在example provided in the golem documentation 中,不清楚将R6 生成器放在哪里。根据AppsilonR6 生成器进入一个单独的.R 文件(例如logger_manager.R),并在global.R 中调用以从该类构造一个新对象:logger_manager = LoggerManager$new()。但是,基于golemShiny 应用程序中没有global.R 文件。

下面是我基于golemShiny 应用程序的最小示例。我尝试遵循example provided in the golem documentation 中的结构,但它似乎没有跨模块共享数据:

app_ui.R:

app_ui <- function(request) {
  tagList(
    # Leave this function for adding external resources
    golem_add_external_resources(),
    
    # List the first level UI elements here 
    fluidPage(
      mod_a_ui("a_ui_1"),
      mod_b_ui("b_ui_1")
    )
  )
}

golem_add_external_resources <- function(){
  
  add_resource_path(
    'www', app_sys('app/www')
  )
 
  tags$head(
    favicon(),
    bundle_resources(
      path = app_sys('app/www'),
      app_title = 'Test'
    ),
    # Add here other external resources
    # for example, you can add shinyalert::useShinyalert()
    shinyjs::useShinyjs()
  )
}

app_server.R:

app_server <- function( input, output, session ) {
  
  # Generate R6 Class
  QuestionnaireResponses <- R6Class(
    classname = "QuestionnaireResponses",
    public = list(
      resp_id = NULL,
      timezone = NULL,
      timestamp = NULL,
      gender = NULL,
    )
  )
  
  # Create new object to share data across modules using the R6 Class
  questionnaire_responses <- QuestionnaireResponses$new()
  
  # List the first level callModules here
  callModule(mod_a_server, "a_ui_1", questionnaire_responses)
  callModule(mod_b_server, "b_ui_1", questionnaire_responses)
}

mod_a.R:

mod_a_ui <- function(id){
  ns <- NS(id)
  
  tagList(
    radioButtons(inputId = "gender",
                 label = "What is your sex?",
                 choices = c("Male" = 1,
                             "Female" = 2),
                 selected = character(0))
)
}

mod_a_server <- function(input, output, session, questionnaire_responses){
  ns <- session$ns
  
  # Add time start to the output vector
  timestamp <- format(Sys.time(), "%Y-%m-%d %H:%M:%OS6")
  timezone <- Sys.timezone()
  
  # Generate a survey-specific ID number
  resp_id <- paste0(sample(c(letters, LETTERS, 0:9), 10), collapse = "")
  
  # Assign values to R6 object
  questionnaire_responses$resp_id <- resp_id
  questionnaire_responses$timezone <- timezone
  questionnaire_responses$timestamp <- timestamp
  questionnaire_responses$gender <- input.gender
}

mod_b.R:

mod_b_ui <- function(id){
  ns <- NS(id)
  tagList(
    print("questionnaire_responses$resp_id")
  )
}

mod_b_server <- function(input, output, session, questionnaire_responses){
  ns <- session$ns
  }

但是,数据不能跨模块共享,因为当我尝试在模块 B(在模块 A 中生成)中打印 resp_id 时,我收到以下错误:

An error has occurred!
object 'questionnaire_responses' not found

【问题讨论】:

    标签: r shiny module r6 golem


    【解决方案1】:

    所以这里的问题是,当您的 R6 对象被传递到服务器函数时,您正试图从 UI 函数打印对象。

    换句话说,当 R6 对象被传递给 mod_b_server 函数时,您正试图在 mod_b_ui 函数中进行打印。

    对于您的原始问题,您可以在标准文件中创建 R6 类,如https://github.com/ColinFay/golemexamples/blob/master/golemR6/R/R6.R

    请注意,尽管您的数据对象不是响应式的,并且在您在模块 A 中更改时不会重新打印 - 这是您可以使用 {gargoyle} 的地方,例如:

    请参阅https://github.com/ColinFay/golemexamples/tree/master/golemR6 以获得完整的工作示例。

    PS : 你的模块中缺少 ns() :)

    科林

    【讨论】:

    • 感谢所有这些建议和代码示例——这非常有帮助。是否可以与模块 B 的 UI 共享 R6 对象,以便我可以将其打印给用户?
    • @itpetersen 当然,但问题是你必须从服务器端更新它——UI 在应用程序启动时生成一次,所以如果你想更新它,你需要做类似@ 987654330@ 或 insertUI()textOutput()github.com/ColinFay/golemexamples/blob/master/golemR6/R/…
    【解决方案2】:

    我对你的代码做了一些更正(一些错字)

    tl;dr :您无法在 UI 中访问问卷调查。

    app_ui.R:

    same as you
    

    app_server.R:

    #' @import shiny
    #' @import R6
    #' @noRd
    app_server <- function( input, output, session ) {
      
      # Generate R6 Class
      QuestionnaireResponses <- R6Class(
        classname = "QuestionnaireResponses",
        public = list(
          resp_id = NULL,
          timezone = NULL,
          timestamp = NULL,
          gender = NULL
        )
      )
      
      # Create new object to share data across modules using the R6 Class
      questionnaire_responses <- QuestionnaireResponses$new()
      
      # List the first level callModules here
      callModule(mod_a_server, "a_ui_1", questionnaire_responses)
      callModule(mod_b_server, "b_ui_1", questionnaire_responses)
    }
    

    mod.R:

    mod_a_ui <- function(id){
      ns <- NS(id)
      
      tagList(
        radioButtons(inputId = ns("gender"),
                     label = "What is your sex?",
                     choices = c("Male" = 1,
                                 "Female" = 2),
                     selected = character(0))
      )
    }
    
    mod_a_server <- function(input, output, session, questionnaire_responses){
      ns <- session$ns
      
      # Add time start to the output vector
      timestamp <- format(Sys.time(), "%Y-%m-%d %H:%M:%OS6")
      timezone <- Sys.timezone()
      
      # Generate a survey-specific ID number
      resp_id <- paste0(sample(c(letters, LETTERS, 0:9), 10), collapse = "")
      
      # Assign values to R6 object
      questionnaire_responses$resp_id <- resp_id
      questionnaire_responses$timezone <- timezone
      questionnaire_responses$timestamp <- timestamp
      questionnaire_responses$gender <- "input$gender"
    }
    
    
    mod_b_ui <- function(id){
      ns <- NS(id)
      tagList(
        print("questionnaire_responses$resp_id") # you can't access questionnaire_responses in the UI
      )
    }
    
    mod_b_server <- function(input, output, session, questionnaire_responses){
      ns <- session$ns
      print(questionnaire_responses$resp_id) # but here you can
    }
    

    【讨论】:

    • 您可以将您的 QuestionnaireResponses
    • 这很有道理——非常感谢您的帮助。是否可以与模块 B 的 UI 共享 R6 对象,以便我可以将其打印给用户?
    猜你喜欢
    • 1970-01-01
    • 2012-08-25
    • 1970-01-01
    • 1970-01-01
    • 2020-02-04
    • 1970-01-01
    • 2010-10-20
    • 2015-02-14
    • 2012-09-19
    相关资源
    最近更新 更多