如何在R模块之间相互传输无功值?

How to reciprocally transmit reactive values between R modules?

提问人:Curious Jorge - user9788072 提问时间:8/10/2023 最后编辑:Curious Jorge - user9788072 更新时间:8/10/2023 访问量:40

问:

我正在尝试找到一种系统、稳健的方式,以双向流程在 R 模块之间传输反应式数据,我可以将其用作未来的模板。我还不清楚如何在模块之间传输数据。

在运行本文底部所示的示例 R Shiny 代码时,第一个模块将基本数据帧值乘以用户滑块输入值,第二个模块将 10 添加到 .然后,通过 in 函数,将表的第一列传输回,并将表中添加的列命名为“colA_mod2”。到目前为止一切正常。您可以运行底部发布的代码,看看它是如何工作的。mod1dfmod2mod1observe()mod1_server()mod2mod1

但是,如何将“colA_mod2”中的值乘以 100 并将这些值传回表并将这些值作为列附加到表中,以标记为“colA_mod2_mod1”?我想,如果我能看到这一步是如何工作的,我终于可以了解在模块之间双向传输值了。mod2mod2

法典:

library(shiny)
library(DT)

mod1_ui <- function(id) {
  ns <- NS(id)
  DTOutput(ns("tbl"))
}

mod2_ui <- function(id) {
  ns <- NS(id)
  DTOutput(ns("tbl"))
}

mod1_server <- function(input, output, session, common) {
  new_dat <- reactive({
    df <- common$df
    svc <- common$svc()
    df * as.numeric(svc)
  })
  
  # the below transmits mod2 data back to mod1
  observe({
    common$mod1_dat <- new_dat()
    common$colA_mod2 <- common$mod2_table$A
  })
  
  output$tbl <- renderDT({
    dat <- new_dat()
    dat$colA_mod2 <- common$colA_mod2 
    dat
  })
}

mod2_server <- function(input, output, session, common) {
  
  output$tbl <- renderDT({
    mod1_dat <- common$mod1_dat
    dat <- data.frame(mod1_dat + 10)
    common$mod2_table <- dat
    dat
  })
}

ui <- fluidPage(
  mainPanel(
    h5(strong("Base table:")),
    DTOutput("table"),
    h5(strong(paste(
      "Module 1 multiplies slider input by values in above table",
      "and then tacks on column A from mod2 called `ColA_mod2´:"))),
    sliderInput("svc", "", min = 0, max = 10, value = 1),
    mod1_ui("mod1"),
    h5(strong(paste(
      "Module 2 then adds 10 to those Module 1 products [and then tacks on",
      "a new column called `ColA_mod2_mod1` which is `ColA_mod2` from mod1",
      "multipled by 100]:"))),
    mod2_ui("mod2")
  )
)

server <- function(input, output, session) {
  
  common <- reactiveValues(df = data.frame(A = 1:2, B = 3:4))
  
  output$table <- renderDT({datatable(common$df)})
  
  common$svc <- reactive(input$svc)
  
  callModule(mod1_server, "mod1", common)
  callModule(mod2_server, "mod2", common)
}

shinyApp(ui, server)
r 模块 命名空间 shiny-reactive

评论


答:

1赞 YBS 8/10/2023 #1

试试这个

library(shiny)
library(DT)

mod1_ui <- function(id) {
  ns <- NS(id)
  DTOutput(ns("tbl"))
}

mod1_server <- function(id, common) {
  moduleServer(id, function(input, output, session) {
  
    new_dat <- reactive({
      df <- common$df
      svc <- common$svc()
      df * as.numeric(svc)
    })
    
    # the below transmits mod2 data back to mod1
    observe({
      common$mod1_dat <- new_dat()
      common$colA_mod2 <- common$mod2_table$A
    })
    
    output$tbl <- renderDT({
      dat <- new_dat()
      dat$colA_mod2 <- common$colA_mod2 
      dat
    })

  })
}

mod2_ui <- function(id) {
  ns <- NS(id)
  DTOutput(ns("tbl"))
}

mod2_server <- function(id, common) {
  moduleServer(id, function(input, output, session) {
    output$tbl <- renderDT({
      mod1_dat <- common$mod1_dat
      dat <- data.frame(mod1_dat + 10)
      if (!is.null(common$colA_mod2)) dat$colA_mod2_mod1 <- common$colA_mod2 * 10
      common$mod2_table <- dat
      dat
    })
  })
}

ui <- fluidPage(
  mainPanel(
    h5(strong("Base table:")),
    DTOutput("table"),
    h5(strong(paste(
      "Module 1 multiplies slider input by values in above table",
      "and then tacks on column A from mod2 called `ColA_mod2´:"))),
    sliderInput("svc", "", min = 0, max = 10, value = 1),
    mod1_ui("mod1"),
    h5(strong(paste(
      "Module 2 then adds 10 to those Module 1 products [and then tacks on",
      "a new column called `ColA_mod2_mod1` which is `ColA_mod2` from mod1",
      "multipled by 100]:"))),
    mod2_ui("mod2")
  )
)

server <- function(input, output, session) {
  
  common <- reactiveValues(df = data.frame(A = 1:2, B = 3:4))
  
  output$table <- renderDT({datatable(common$df)})
  
  common$svc <- reactive(input$svc)
  
  mod1_server("mod1", common)
  mod2_server("mod2", common)
  
}

shinyApp(ui, server)

output

0赞 Curious Jorge - user9788072 8/10/2023 #2

我很难找到有关管理 R 模块之间数据流的好教程。但是,这篇文章对我很有帮助:https://rviews.rstudio.com/2021/10/20/a-beginner-s-guide-to-shiny-modules/

下面我为 YBS 解决方案添加注释,我还发布了一个我认为有用的数据流图。

法典:

library(shiny)
library(DT)

mod1_ui <- function(id) {
  ns <- NS(id)
  DTOutput(ns("tbl"))
}

mod1_server <- function(id, common) {
  moduleServer(id, function(input, output, session) {
    
    # Create a reactive expression to perform data multiplication on base DF
    new_dat <- reactive({
      df <- common$df
      svc <- common$svc()
      df * as.numeric(svc)
    })
    
    # When the new_dat is updated, store it in common$mod1_dat
    observe({
      common$mod1_dat <- new_dat()
      
      # Below pulls in Col A from mod2 for appending to mod1 table:  
      common$colA_mod2 <- common$mod2_table$A
      
    })
    
    # Render the DT table with mod1 data, including the appended column
    output$tbl <- renderDT({
      dat <- new_dat()
      dat$colA_mod2 <- common$colA_mod2 
      dat
    })
    
  })
}

mod2_ui <- function(id) {
  ns <- NS(id)
  DTOutput(ns("tbl"))
}

mod2_server <- function(id, common) {
  moduleServer(id, function(input, output, session) {
    
    # Render the DT table with mod2 data, including added columns
    output$tbl <- renderDT({
      
      mod1_dat <- common$mod1_dat
      
      dat <- data.frame(mod1_dat + 10) # add 10 to mod1 cols A and B
      
      # Below pulls in last added column from mod1 and multiply by 100 for
      # appending to mod2 table:
      if (!is.null(common$colA_mod2)) {
        dat$colA_mod2_mod1 <- common$colA_mod2 * 100
      }
      
      common$mod2_table <- dat
      
      dat
    })
  })
}

ui <- fluidPage(
  mainPanel(
    h5(strong("Base table:")),
    DTOutput("table"),
    h5(strong(paste(
      "Module 1 multiplies slider input by values in above table and",
      " then tacks on column A from mod2 called `ColA_mod2´:"))),
    sliderInput("svc", "", min = 0, max = 10, value = 1),
    mod1_ui("mod1"),
    h5(strong(paste(
      "Module 2 adds 10 to those Module 1 products for cols A and B and", 
      "then tacks on a new column called `ColA_mod2_mod1` which is",
      "`ColA_mod2` from mod1 multiplied by 100:"))),
    mod2_ui("mod2")
  )
)

server <- function(input, output, session) {
  
  # Create a reactiveValues object to store common data across modules
  common <- reactiveValues(df = data.frame(A = 1:2, B = 3:4))
  
  # Render the base table
  output$table <- renderDT({datatable(common$df)})
  
  # Store the slider input as a reactive value
  common$svc <- reactive(input$svc)
  
  # Call the server modules
  mod1_server("mod1", common)
  mod2_server("mod2", common)
  
}

shinyApp(ui, server)

图:

enter image description here

下面是另一个可能更易于理解的代码数据流图:

enter image description here