如何使用具有多个输出的 R Shiny moduleServer

Posted

技术标签:

【中文标题】如何使用具有多个输出的 R Shiny moduleServer【英文标题】:How to use R Shiny moduleServer with multiple outputs 【发布时间】:2021-11-28 07:13:49 【问题描述】:

下午好!

我正在尝试创建一个模块,用于闪亮的应用程序,它将输出用户可以与之交互的图形和数据表,其想法是用户可以创建各种场景,然后进行评估/分析。我无法理解的是如何在服务器代码中使用模块的输出。我显然在做一些愚蠢的事情,但两天后我已经用完了可供阅读的选项和文章。这是我对模块的第一次探索。

我正在尝试复制这篇文章(尽管我更愿意同时显示两种输入法,而不是使用按钮在两者之间切换)https://www.r-bloggers.com/2021/09/how-to-use-shinymatrix-and-plotly-graphs-as-inputs-in-a-shiny-app/ 使用类似于此的 DT::datatablehttps://www.r-bloggers.com/2019/04/edit-datatables-in-r-shiny-app/

这是我要去的地方的一个代表,它不远(在第一个障碍上掉下来!)...... 我试图通过渲染模块生成的数据来重用它并证明我可以单独使用这些数据。

library(shiny)
library(tidyverse)
library(plotly)
library(DT)
library(shinydashboard)

#base data----
default_df <- structure(list(`0` = 70, `1` = 70, `2` = 70, `3` = 70, `4` = 70, 
                             `5` = 70, `6` = 70, `7` = 70, `8` = 70, `9` = 70, `10` = 70, 
                             `11` = 70, `12` = 70, `13` = 70, `14` = 70, `15` = 70, `16` = 70, 
                             `17` = 70, `18` = 70, `19` = 70, `20` = 70, `21` = 70, `22` = 70, 
                             `23` = 70), row.names = "calls", class = "data.frame")

#module----
##mod server----
mod_editable_srv <- function(id, data) 
    moduleServer(id, function(input, output, session) 
        x = data
        
        proxy = dataTableProxy('x1')
        
        observeEvent(input$x1_cell_edit, 
            info = input$x1_cell_edit
            str(info)
            i = info$row
            j = info$col
            v = info$value
            x[i, j] <<- DT::coerceValue(v, x[i, j])
            replaceData(proxy, x, resetPaging = FALSE)  # important
            print(x)
        )
        
        output$x1 = renderDT(x, selection = 'none', editable = TRUE)
        
        return(x)
    )


##mod ui----
mod_editable_ui <- function(id) 
    tagList(
        DT::dataTableOutput(NS(id, "x1")),
        NS(id,"x")
    )


#ui----
header <- dashboardHeader(title = "Density based clustering using file upload")

table <- column(width = 4,
                box(width = 12, title = "Input hours",
                    mod_editable_ui('x1')
                ),
                box(width = 12, title = "Input hours",
                    renderDT('test_dat')
                )
)

body <- dashboardBody(table)

ui <- dashboardPage(
    header,
    dashboardSidebar(disable = TRUE),
    body
)

#server----
server <- function(input, output) 

    datafile <- mod_editable_srv("x1", default_df)
    
    output$test_dat <- renderDataTable(
        datafile()$x
        )


#run app----
shinyApp(ui = ui, server = server)

我可以通过使用打印调试看到模块正在工作(ish)。

似乎有很多关于 callModule 模式的教程,但没有多少关于 moduleServer 模式的教程。还有什么往往会遗漏服务器端,解释模块如何在彼此之间移动数据。由于 RStudio 不建议使用 moduleServer,我更愿意学习这些模式。

任何帮助将不胜感激!

【问题讨论】:

那么,你想要的是mod_editable_uimod_editable_srv 来输出一个绘图和一个数据表?您是否已经成功完成了相同但没有模块的操作?如果没有,请先尝试。然后我们可以从那里进入模块。 这暴露了我不了解反应值。我会玩一会,看看我能做些什么 【参考方案1】:

这里尝试解释如何在主应用程序中使用模块的返回值。在这个玩具示例中,主应用程序定义了一个全局数字 y,它被传递给模块。该模块又定义了另一个数字x,并分别返回总和和乘积。

library(shiny)
rows <- 1:2

sample_ui <- function(id, idx = 1) 
  ns <- NS(id)
  fluidRow(numericInput(ns("x"), paste0("x_", idx), 10, 1, 100)) 

sample_server <- function(id, y) 
   moduleServer(id, function(input, output, session) 
      add <- reactive(input$x + y())
      multiply <- reactive(input$x * y())
      list(add = add, multiply = multiply)
   )


ui <- fluidPage(fluidRow(numericInput("y", "y", 1, 1, 10)), 
                lapply(rows, function(i) sample_ui(paste0("x", i), i)), 
                fluidRow(verbatimTextOutput("out")))
server <- function(input, output, session) 
   get_y <- reactive(req(input$y))
   hdl <- lapply(paste0("x", rows), sample_server, get_y)

   output$out <- renderPrint(
      ## this would be normally also a loop, but to illustrate I define it explicitely
      ## lapply(hdl, function(h) c(add = h$add(), mult = h$multiply()))
      list(c(add  = hdl[[1]]$add(),
             mult = hdl[[1]]$multiply()),
           c(add  = hdl[[2]]$add(),
             mult = hdl[[2]]$multiply()))
    )


shinyApp(ui, server) 

理念

您的模块服务器仅返回您要在主应用程序中使用的所有元素的列表(通常是反应式)。 如果需要,您还可以从主应用中传入一些反应式以在模块中使用。 在您的主应用程序中,您只需调用模块服务器并将结果存储在某处。 这是一个包含之前定义的反应器的列表。 要使用它们,您只需像使用任何其他响应式一样“调用”它们。

【讨论】:

啊,现在我想这就是我所追求的!到目前为止,这是我在这方面看到的最有用的代码。你还能在列表中删除一个情节吗? 您的模块可以返回他们想要的任何内容(通常在列表中),并且您可以从您的主模块中通过使用列表中的相应插槽来使用此信息。如果您可以将您的情节转换为一个对象(例如通过ggplotGrob),您可以从您的模块中返回它。但我不确定这是否是你想要做的。最好将一些反应从主模块传递到模块并在那里进行绘图,或者从模块传递原始数据并在主模块中进行绘图,所以我没有真正看到需要传递 plot 的用例 本身。 原因是我们在这里输出渲染数据表的反应值和潜在的绘图。 我还是不明白。模块返回值的想法是您可以在主应用程序中进一步操作它。也就是说,您在模块中渲染表格/绘图并将反应(如点击事件)返回到主应用程序。 Righto,那肯定是有道理的。我会继续玩的,谢谢你的指导!

以上是关于如何使用具有多个输出的 R Shiny moduleServer的主要内容,如果未能解决你的问题,请参考以下文章

如何通过 div 标签要求在 R Shiny 中输入?

在 Shiny 中保存多个 TinyMCE 的内容

如何使用操作按钮在 R Shiny 中显示和隐藏表格输出?

如何在 R Shiny 中仅使用一个下载按钮下载多个图?

如何从 R/Shiny 应用程序下载多个文件?

在 R Shiny 中使用 renderTable 时如何格式化数字行输出?