【问题标题】:Shiny Modules: Pass values from renderUI (in server function) to another module's server functionShiny Modules:将值从 renderUI(在服务器函数中)传递到另一个模块的服务器函数
【发布时间】:2018-08-24 15:07:10
【问题描述】:

(我通读了this 问题,尽管标题相似,但它与我的问题无关——或者,如果是的话,我太笨了,看不出它是如何应用的。)

我正在模块化我的 Shiny 代码,以便添加额外的图表只需要在单独的文件中添加几个函数。存在三个面板——侧面板(用户在其中选择图形)、底部面板(用户在其中选择图形参数)和主面板(在其中显示图形)。

侧面板不变,但底部面板会根据侧面板中的选择而变化。

side_panel.R

# UI function
sidePanelInput <- function(id, label='side panel') { # Some input w/ ns = selected_graph }

# Server function
sidePanel <- function(input, output, session) {
    selected_graph <- reactive({input$selected_graph})
    return(selected_graph)

在我的 app.R 文件中,selected_graph 被传递到底部面板和主面板:

app.R

# ...
sidePanel <- callModule(sidePanel, 'side')
bottomPanel <- callModule(bottomPanel, 'bottom', data=some_data, selected_graph=sidePanel)
mainPanel <- callModule(mainPanel, "main", data=some_data, selected_graph=sidePanel, params=bottomPanel)

# ...

到目前为止一切都很好(注意bottomPanel 返回了一些东西,然后传递给了mainPanel)。所有这些来回传递都很好。这是我的问题:每个图表的底部面板都不同,并在单独的文件中定义。这意味着bottomPanel 模块需要知道从sidePanel 吐出的反应中渲染什么。这意味着我不使用bottomPanel的UI功能,我只使用renderUI的服务器功能:

bottom_panel.R

source('graphs')
bottomPanel <- function(input, output, session, data, selected_graph) {
    # Call the function of the graph, depending on what the selected graph is
    output$bottomPanel <- renderUI({
        tagList(
            match.fun(paste(selected_graph(), '_bottom_panel', sep=''))(session$ns('id'))
        )
    })

    # So, if the selected graph is 'scatter_1', then the function call will be
    # scatter_1_bottom_panel(session$ns('id')) -- An example of a bottom_panel function
    # is provided at the end of this question, but it works as intended

    # Now, we set the defaults (specific to the graph); for example, slider-ranges
    # will be set according to mins and maxes in the data. Similar to above, a 
    # match.fun() call is used here to determine how the defaults are set
    observe({
        match.fun(paste(selected_graph(), '_bottom_panel_defaults', sep=''))(session, data)
    })

    # Here is my problem. I need to output the parameters of the newly-rendered
    # bottom panel, so that those parameters can be passed to the main panel. This
    # as it is doesn't work, because one apparently can't read from server output
    params <- reactive({output$bottomPanel})
    return(params)
}

渲染后的UI渲染并调用默认值函数后如何输出参数?


example_bottom_panel.R

scat_2_bottom_panel <- function(id) {
    ns <- NS(id)
    panel <- wellPanel(
        sliderInput(
            inputId = ns('duration_range'),
            label = 'Duration of Sound [ms]',
            min = 0,
            max = 10000,
            value = c(0, 10000),
            step = 100,
            round = FALSE,
            ticks = TRUE
        )
    )
    return(panel)
}

example_default_function.R

scatter_1_bottom_panel_defaults <- function(session, data) { 
    updateSliderInput(session, 'duration_range', value=c(min(data$duration), max(data$duration)))
}

我已经阅读了上面链接的问题几次,似乎这是在服务器功能中所做的:

xvar <- reactive({input[[ "xvar" ]] })
yvar <- reactive({input[[ "yvar" ]] })

然后xvaryvar 被用作renderUI 调用中的参数。乍一看,这对我不起作用;每个底部面板所需的反应值根据用户选择的图表而变化。也许我可以在 bottom_panel 函数中包含 renderUI 调用,将这些 ID 声明为响应式,然后在面板生成中使用它们?

【问题讨论】:

  • 你能做一个小的复制例子吗?如果我理解正确,您想让侧面板返回一些由底部面板动态使用的反应值吗?
  • @KotaMori 不完全是。我想让底部面板返回在服务器函数的renderUI 调用中生成的参数(以便这些可以传递到主面板)。渲染的 UI 通过单独的函数调用,并取决于侧面板的选择。我将处理一个小的复制示例,但我担心它不会比我上面发布的小很多!
  • @KotaMori 重申一下,我的问题不是从侧面板获取反应值并将其传递到底部面板,而是从底部面板发送值(从变量 @ 987654339@ 调用,不是来自 UI 函数)
  • 我明白了......也许问题是“输出”不是反应对象,所以我们不能像“输入”那样传递。你到底想通过什么?我认为通过output$bottomPanel 没有意义。也许您想传递“来自动态创建的 UI 的输入”?
  • @KotaMori 是的!这正是我想要通过的。我只是不确定如何从服务器功能中做到这一点(因为这是呈现 UI 的地方)。现在,我正在尝试将 UI 创建函数中的 ID 声明为响应式,然后在函数本身中返回这些 ID。

标签: r shiny


【解决方案1】:

从动态创建的对象中检索输入值(通过renderUI),

  • 使用session$ns访问服务器模块中的命名空间
  • 将动态创建的对象命名为ns("ID")

这是一个简单的例子,其中

  1. 您在第一个 ui/module 中选择单元,将其传递给第二个和第三个。
  2. 您在第二个 ui/module 中选择值,传递给第三个。
  3. 在第三个 ui/module 中显示选定的值。

这符合你想做的吗?

library(shiny)


setUnitUI <- function(id) {
  ns <- NS(id)
  selectInput(ns('unit'), 'unit', c('km', 'mile'))
}

setValueUI <- function(id) {
  ns <- NS(id)
  uiOutput(ns('dynamicSlider'))
}

showValueUI <- function(id) {
  ns <- NS(id)
  textOutput(ns('value'))
}

ui <- fluidPage(
  setUnitUI('unit'),
  setValueUI('value'),
  showValueUI('show')
)


setUnitModule <- function(input, output, session) {
  reactive(input$unit)
}

setValueModule <- function(input, output, session, unitGetter) {
  output$dynamicSlider <- renderUI({
    ns <- session$ns
    unit <- unitGetter()
    if (unit == 'km') {
      sliderInput(ns('pickValue'), paste('Pick value in', unit), 
                  min=0, max=150, value=0)
    } else {
      sliderInput(ns('pickValue'), paste('Pick value in', unit), 
                  min=0, max=100, value=0)
    }
  })

  reactive(input$pickValue)
}

showValueModule <- function(input, output, session, unitGetter, valueGetter) {
  output$value <- renderText(paste('You chose', valueGetter(), unitGetter()))
}

server <- function(input, output, session) {
  unitGetter <- callModule(setUnitModule, 'unit')
  valueGetter <- callModule(setValueModule, 'value', unitGetter)
  callModule(showValueModule, 'show', unitGetter, valueGetter)
}


shinyApp(ui, server, options=list(launch.browser=TRUE))

【讨论】:

  • 这个例子很棒。经过几个小时的尝试,这终于帮助我理解了这个问题并且我可以解决。谢谢!
  • @kota 是否必须在主应用程序 ui/server 中调用服务器模块和 UI 模块才能跨不同模块传递值?我从主应用服务器和 UI 调用了Navar moduleNavbar module 调用不同的tab modules。例如。 tab1 moduleinputs module 和 &different plot modules 有单独的调用。当我在tab1UI 模块中使用InputServer 中的renderUI 调用InputUI 时,它不会在应用程序中呈现UI。但是,如果我直接在InputUI 中列出输入,我会看到输入(选择输入、复选框、按钮等)按预期呈现。
  • 如果你回答过类似的问题,请直接告诉我你的答案,否则我可以发一个 Q
  • @user5249203 我想我以前没有回答过这样的问题。如果您作为问题发布,我很乐意考虑您的情况。
猜你喜欢
  • 1970-01-01
  • 2017-08-19
  • 1970-01-01
  • 2018-04-25
  • 2015-04-01
  • 2022-12-03
  • 2020-05-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多