如何在 renderUI R Shiny 中观察模块输出

How do I observe module output inside renderUI R Shiny

提问人:Nikoa 提问时间:7/27/2022 最后编辑:Nikoa 更新时间:7/28/2022 访问量:518

问:

我从模块之间的通信中获取了示例,并将第二个输入模块更改为渲染模块。所以基本上,一旦你点击“显示”按钮,它就会呈现模块UI和服务器。模块输出 2 秒(2 秒列表)中的选择项。我已经为第一个元素设置了一个观察者,作为我所面临的问题的最小示例。它只触发一次,但在我选择新值后不会再次触发。selectInputlistreactive

有趣的是,通过调试按钮检查模块反应输出表明该值确实发生了变化。browser()

#' Variable selection for plot user interface
#'
#' @param id, character used to specify namespace, see \code{shiny::\link[shiny]{NS}}
#'
#' @return a \code{shiny::\link[shiny]{tagList}} containing UI elements
varselect_mod_ui <- function(id) {
    ns <- NS(id)
    
    # define choices for X and Y variable selection
    var_choices <- setNames(colnames(iris)[1:4], colnames(iris)[1:4])
    
    # assemble UI elements
    tagList(
        selectInput(
            ns("xvar"),
            "Select X variable",
            choices = var_choices,
            selected = colnames(iris)[1]
        ),
        selectInput(
            ns("yvar"),
            "Select Y variable",
            choices = var_choices,
            selected = colnames(iris)[2]
        )
    )
}

#' Variable selection module server-side processing
#'
#' @param input,output,session standard \code{shiny} boilerplate
#'
#' @return list with following components
#' \describe{
#'   \item{xvar}{reactive character indicating x variable selection}
#'   \item{yvar}{reactive character indicating y variable selection}
#' }
varselect_mod_server <- function(input, output, session) {
    
    return(
        list(
            xvar = reactive({ input$xvar }),
            yvar = reactive({ input$yvar })
        )
    )
}

#' Scatterplot module user interface
#'
#' @param id, character used to specify namespace, see \code{shiny::\link[shiny]{NS}}
#'
#' @return a \code{shiny::\link[shiny]{tagList}} containing UI elements
#' @export
#'
#' @examples
scatterplot_mod_ui <- function(id) {
    ns <- NS(id)
    
    tagList(
        fluidRow(
            column(
                width = 6,
                plotOutput(ns("plot1"))
            ),
            column(
                width = 6,
                plotOutput(ns("plot2"))
            )
        )
    )
}

#' Scatterplot module server-side processing
#'
#' This module produces a scatterplot with the sales price against a variable selected by the user.
#'
#' @param input,output,session standard \code{shiny} boilerplate
#' @param dataset data frame (non-reactive) with variables necessary for scatterplot
#' @param plot1_vars list containing reactive x-variable name (called `xvar`) and y-variable name (called `yvar`) for plot 1
#' @param plot2_vars list containing reactive x-variable name (called `xvar`) and y-variable name (called `yvar`) for plot 2
scatterplot_mod_server <- function(input,
                                   output,
                                   session,
                                   dataset,
                                   plot1vars,
                                   plot2vars) {
    
    plot1_obj <- reactive({
        p <- scatter_sales(dataset, xvar = plot1vars$xvar(), yvar = plot1vars$yvar())
        return(p)
    })
    
    plot2_obj <- reactive({
        p <- scatter_sales(dataset, xvar = plot2vars$xvar(), yvar = plot2vars$yvar())
        return(p)
    })
    
    output$plot1 <- renderPlot({
        plot1_obj()
    })
    
    output$plot2 <- renderPlot({
        plot2_obj()
    })
}


#' Produce scatterplot with variables selected by the user
#'
#' @param data data frame with variables necessary for scatterplot
#' @param xvar variable (string format) to be used on x-axis
#' @param yvar variable (string format) to be used on y-axis
#'
#' @return {\code{ggplot2} object for the scatterplot
#' @export
#'
#' @examples
#' plot_obj <- scatter_sales(data = ames, xvar = "Lot_Frontage", yvar = "Sale_Price")
#' plot_obj
scatter_sales <- function(dataset, xvar, yvar) {
    
    x <- rlang::sym(xvar)
    y <- rlang::sym(yvar)
    
    p <- ggplot(dataset, aes(x = !!x, y = !!y)) +
        geom_point() +
        theme(axis.title = element_text(size = rel(1.2)),
              axis.text = element_text(size = rel(1.1)))
    
    return(p)
}

# load packages
library(shiny)
library(AmesHousing)
library(dplyr)
library(rlang)
library(ggplot2)
library(scales)

# load separate module and function scripts
#source("modules.R")
#source("helpers.R")

# user interface
ui <- fluidPage(
    
    titlePanel("Iris Data Explorer"),
    
    fluidRow(
        column(
            width = 3,
            wellPanel(
                varselect_mod_ui("plot1_vars")
            )
        ),
        column(
            width = 5,
            scatterplot_mod_ui("plots")
        ),
        column(1, actionButton("show","Show"), actionButton("dbg","Debug")),
        column(
            width = 3,
            wellPanel(
                uiOutput("plot2_vars_ui")#varselect_mod_ui("plot2_vars")
            )
        )
    )
)

# server logic
server <- function(input, output, session) {
    observer = NULL
    # prepare dataset
    data <- iris
    
    # execute plot variable selection modules
    plot1vars <- callModule(varselect_mod_server, "plot1_vars")
    plot2vars <- list(xvar = reactive({colnames(iris)[1]}), yvar = reactive({colnames(iris)[2]}))#callModule(varselect_mod_server, "plot2_vars")
    
    observeEvent(input$show, {
        output$plot2_vars_ui = renderUI({
            
            plot2vars__ <<- callModule(varselect_mod_server, "plot2_vars")
            observer <<- observeEvent(plot2vars__$xvar, {
                print("observer inside renderUI is triggered!")
                print(plot2vars$xvar())
                #browser()
            })
            varselect_mod_ui("plot2_vars")
        })
    })
    
    observeEvent(plot2vars$xvar, {
        print("observer outside renderUI")
        print(plot2vars$xvar())
        #browser()
    })
    
    observeEvent(input$dbg, {
        
        browser()
    })
    # execute scatterplot module
    res <- callModule(scatterplot_mod_server,
                      "plots",
                      dataset = data,
                      plot1vars = plot1vars,
                      plot2vars = plot2vars)
}

# Run the application
shinyApp(ui = ui, server = server)
R 闪亮 的 ShinyModules 动态用户界面

评论

0赞 Limey 7/27/2022
欢迎来到 SO!441 行几乎不是一个最小的工作示例,尤其是当您希望帮助者能够访问一个相当不寻常的包(例如 .这大大减少了能够为您提供帮助的人数。就我个人而言,我会先做一个(“反应式列表”)而不是一个简单的列表。其次,我怀疑嵌套反应式,即使有全局分配,也可能是有问题的。我会更改您的工作流程,以便您不会嵌套渲染 UI 或 。AmesHousingplot2varsreactiveValuescallModuleobserveEvent
0赞 Nikoa 7/27/2022
谢谢,现在@Limey简化的代码并使用了虹膜数据。
0赞 Limey 7/27/2022
所以你希望右边的 plot/selectInputs 以与左边相同的方式做出反应?这是对的吗?
0赞 Limey 7/28/2022
我无法理解你要做什么。 “一旦你点击'显示'按钮,它就会呈现模块UI和服务器”。什么?为什么?如何“渲染”服务器?当这正是模块 UI 函数的作用时,为什么要使用?您正在 中“定义”modeule 服务器的实例,但未将其返回值分配给任何对象 - 该对象的范围将限定为 (除非分配与您在其他地方所做的那样被捏造或类似),因此您的其余代码无法访问。...renderUIrenderUIrenderUI<<-
0赞 Limey 7/28/2022
...同样,我相信,尽管分配了 .(请参阅此处。这就是为什么你的“外部”观察者不会开火的原因。由于缺乏明确性而投票结束,但如果你能很好地解释你要做什么(以及为什么)以使答案成为可能,我将撤回。observeEventrenderUIobserver

答:

0赞 Nikoa 7/28/2022 #1

在这里,我在示例中进一步减少了问题,我的困惑是 和 。 反应值需要,输入不需要。observeEvent(input$show, {observeEvent(plot_vars$xvar(), {()

#' Variable selection for plot user interface
#'
#' @param id, character used to specify namespace, see \code{shiny::\link[shiny]{NS}}
#'
#' @return a \code{shiny::\link[shiny]{tagList}} containing UI elements
varselect_mod_ui <- function(id) {
    ns <- NS(id)
    
    # define choices for X and Y variable selection
    var_choices <- setNames(colnames(iris)[1:4], colnames(iris)[1:4])
    
    # assemble UI elements
    tagList(
        selectInput(
            ns("xvar"),
            "Select X variable",
            choices = var_choices,
            selected = colnames(iris)[1]
        ),
        selectInput(
            ns("yvar"),
            "Select Y variable",
            choices = var_choices,
            selected = colnames(iris)[2]
        )
    )
}

#' Variable selection module server-side processing
#'
#' @param input,output,session standard \code{shiny} boilerplate
#'
#' @return list with following components
#' \describe{
#'   \item{xvar}{reactive character indicating x variable selection}
#'   \item{yvar}{reactive character indicating y variable selection}
#' }
varselect_mod_server <- function(input, output, session) {
    
    return(
        list(
            xvar = reactive({ input$xvar }),
            yvar = reactive({ input$yvar })
        )
    )
}

#' Scatterplot module user interface
#'
#' @param id, character used to specify namespace, see \code{shiny::\link[shiny]{NS}}
#'
#' @return a \code{shiny::\link[shiny]{tagList}} containing UI elements
#' @export
#'
#' @examples
scatterplot_mod_ui <- function(id) {
    ns <- NS(id)
    
    tagList(
        width = 6,
        plotOutput(ns("plot"))
    )
}

#' Scatterplot module server-side processing
#'
#' This module produces a scatterplot with 2 variables
#'
#' @param input,output,session standard \code{shiny} boilerplate
#' @param dataset data frame (non-reactive) with variables necessary for scatterplot
#' @param plot1_vars list containing reactive x-variable name (called `xvar`) and y-variable name (called `yvar`) for plot 1
#' @param plot2_vars list containing reactive x-variable name (called `xvar`) and y-variable name (called `yvar`) for plot 2
scatterplot_mod_server <- function(input,
                                   output,
                                   session,
                                   dataset,
                                   plotvars) {
    
    plot_obj <- reactive({
        p <- scatter_plot(dataset, xvar = plotvars$xvar(), yvar = plotvars$yvar())
        return(p)
    })
    
    output$plot <- renderPlot({
        plot_obj()
    })
}


#' Produce scatterplot with variables selected by the user
#'
#' @param data data frame with variables necessary for scatterplot
#' @param xvar variable (string format) to be used on x-axis
#' @param yvar variable (string format) to be used on y-axis
#'
#' @return {\code{ggplot2} object for the scatterplot
#' @export
#'
#' @examples
#' plot_obj <- scatter_sales(data = ames, xvar = "Lot_Frontage", yvar = "Sale_Price")
#' plot_obj
scatter_plot <- function(dataset, xvar, yvar) {
    
    x <- rlang::sym(xvar)
    y <- rlang::sym(yvar)
    
    p <- ggplot(dataset, aes(x = !!x, y = !!y)) +
        geom_point() +
        theme(axis.title = element_text(size = rel(1.2)),
              axis.text = element_text(size = rel(1.1)))
    
    return(p)
}

# load packages
library(shiny)
library(AmesHousing)
library(dplyr)
library(rlang)
library(ggplot2)
library(scales)

# user interface
ui <- fluidPage(
    
    titlePanel("Iris Data Explorer"),
    
    fluidRow(
        column(3, actionButton("show","Show"), actionButton("dbg","Debug"),
               textOutput("selection")),
        column(
            width = 3,
            wellPanel(
                uiOutput("plot_vars_ui")#varselect_mod_ui("plot2_vars")
            )
        ),
        column(
            width = 6,
            scatterplot_mod_ui("plots")
        )
    )
)

# server logic
server <- function(input, output, session) {
    observer = NULL
    # prepare dataset
    data <- iris
    
    # execute plot variable selection modules
    plot_vars <- list(xvar = reactive({colnames(iris)[1]}), yvar = reactive({colnames(iris)[2]}))#callModule(varselect_mod_server, "plot2_vars")
    
    observeEvent(input$show, {
        output$plot_vars_ui = renderUI({
            
            plot_vars <<- callModule(varselect_mod_server, "plot_vars")
            # observer <<- observeEvent(plot_vars$xvar, {
            #   browser()
            #   print("observer inside renderUI is triggered!")
            #   print(plot_vars$xvar())
            #   #browser()
            # })
            
            #observe({#plot_vars$xvar
            observeEvent(plot_vars$xvar(), {
                #browser()
                print("observer inside renderUI is triggered!")
                print(plot_vars$xvar())
                #browser()
            })
            
            #output$selection = renderText({
            #   plot_vars$xvar()
            #})
            
            varselect_mod_ui("plot_vars")
        })
    })
    
    observeEvent(plot_vars$xvar, {
        print("observer outside renderUI")
        print(plot_vars$xvar())
        #browser()
    })
    
    observeEvent(input$dbg, {
        
        browser()
    })
    # execute scatterplot module
    res <- callModule(scatterplot_mod_server,
                      "plots",
                      dataset = data,
                      plotvars = plot_vars)
}

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