简体   繁体   English

如何根据 Shiny 中的 select 输入调用不同的模块?

[英]How to call different modules based on a select input in Shiny?

I am trying to create a Shiny app where each module is completely independent from each other.我正在尝试创建一个 Shiny 应用程序,其中每个模块彼此完全独立。 I have two modules which should be saved in different R files.我有两个模块应该保存在不同的 R 文件中。

Module 1 (both functions should be saved in a separate R script as 'module1.R')模块 1(这两个函数都应保存在单独的 R 脚本中作为“module1.R”)

module_ui1 <- function (id) {
    ns <- NS(id)
    tagList(
        fluidRow(
            box(width = 6, 
                sliderInput(ns("mean_first"), label = "Mean Var1",
                            min = 0, max = 100, value = 20)),
            box(width = 6, 
                sliderInput(ns("mean_second"), label = "Mean Var2",
                            min = 0, max = 100, value = 20))),
        fluidRow(box(width = 12, height= 440,
                     plotOutput(ns('output_plot')))))}

# Server
module_server1 <- function (input, output, session ){
    output$output_plot <- renderPlot({
        mean_first <- input$mean_first
        mean_second <- input$mean_second
        
        random_1<- rnorm(4, mean= mean_first, sd=10)
        random_2<- rnorm(4, mean= mean_second, sd=10)
        data<- data.frame(random_1, random_2)
        p<- ggplot(data, aes(x= random_1, y= random_2)) +
            geom_point()+
            ggtitle('Mod1')
        return(p) })
}

Module 2 - both functions should be saved in a separate R script as 'module2.R'模块 2 - 两个函数都应保存在单独的 R 脚本中作为“module2.R”

# UI
module_ui2 <- function (id) {
    ns <- NS(id)
    tagList(
        fluidRow(
            box(width = 6, 
                sliderInput(ns("mean_first"), label = "Mean Var1",
                            min = 0, max = 100, value = 20)),
            box(width = 6, 
                sliderInput(ns("mean_second"), label = "Mean Var2",
                            min = 0, max = 100, value = 20))),
        fluidRow(box(width = 12, height= 440,
                     plotOutput(ns('output_plot')))))}

# Server
module_server2 <- function (input, output, session ){
    output$output_plot <- renderPlot({
        mean_first <- input$mean_first
        mean_second <- input$mean_second
        
        random_1<- rnorm(4, mean= mean_first, sd=10)
        random_2<- rnorm(4, mean= mean_second, sd=10)
        data<- data.frame(random_1, random_2)
        p<- ggplot(data, aes(x= random_1, y= random_2)) +
            geom_point()+
            ggtitle('Mod2')
        return(p) })
}

In this example they will produce the same output except the plot title (Mod 1 or Mod2).在此示例中,它们将生成相同的 output,但 plot 标题(Mod 1 或 Mod2)除外。

The app would look like this该应用程序看起来像这样


source('module1.R', local = TRUE)
source('module2.R', local = TRUE)

library(shiny)
library(shinydashboard)
library(tidyverse)
library(modules)

ui <- fluidPage(
    # Application title
    titlePanel("App Modules"),

    sidebarLayout(
        sidebarPanel(
            selectInput("module", label =  "Module choices", choices =
                             c("Module 1"="mod1", "Module 2"="mod1"), 
                         selected = "mod2")
        ),

        mainPanel(
        
            conditionalPanel(condition = "module = 'mod1'",
                #Module 1
                module_ui1('module1_label') ), # connects with the server label
            conditionalPanel(condition = "module = 'mod2'",
                #Module 2
                module_ui2('module2_label') ) # connects with the server label
            
        )
    )
)

# Define server logic required to draw a histogram

server <- function(input, output) {
    
    # If the select input = mod1 call this
 callModule(module_server1, "module1_label")
    # If the select input = mod2 call this
 callModule(module_server2, "module2_label")
    
}


# Run the application 
shinyApp(ui = ui, server = server)

In the case both server modules are displayed.在这种情况下,会显示两个服务器模块。 I would like that if the select input = mod1 to display module_server1 and if the select input = mod2 to display module_server2 .如果 select 输入 = mod1 以显示module_server1并且如果 select 输入 = mod2 以显示module_server2 ,我希望如此。

I have tried this and it is not working.我已经尝试过了,但它不起作用。

    selected <- reactiveValues()
    observe({input$module})
    
    
    if (selected() == 'mod1') {
        callModule(module_server1, "module1_label")}
    
    else if (selected() == 'mod2') {
        callModule(module_server2, "module2_label")}

I know how to display with if statements insider reactive content, but I need more flexibility with output.我知道如何使用 if 语句显示内部反应内容,但我需要 output 具有更大的灵活性。 Any ideas?有任何想法吗?

Thanks谢谢

Here's a rewrite of your main server and ui functions:这是您的主服务器和 ui 函数的重写:

ui <- fluidPage(
  titlePanel("App Modules"),
  sidebarLayout(
    sidebarPanel(
      # Note: you had a typo in the choices list
      selectInput("module", label =  "Module choices", choices =
                    c("Module 1"="mod1", "Module 2"="mod2"), 
                  selected = "mod2")
    ),
    mainPanel(
      uiOutput("ui")
     )
  )
)

server <- function(input, output) {
  output$ui <- renderUI({
    if (input$module == "mod1") module_ui1("mod1")
    else module_ui1("mod2")
  })
  mod1 <- callModule(module_server1, "mod1")
  mod2 <- callModule(module_server2, "mod2")
}

I hope you have taken the time to simplify your real use case to create this MWE (if so thank you.) because you can get the same result with only one (parameterised) module...我希望你花时间简化你的真实用例来创建这个 MWE(如果是的话,谢谢你。)因为你可以只用一个(参数化的)模块得到相同的结果......

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM