如何在R Shiny中围绕反应式表达式包装函数?

时间:2014-04-30 18:25:16

标签: r shiny

最小工作示例

假设我想拥有renderDataTable的自定义版本,我将其命名为myRenderDataTable,并绕着renderDataTable进行工作:

library(shiny)
runApp(list(
    ui = basicPage(
        actionButton("button", "Increase input"),
        tabsetPanel(
            tabPanel("table1", shiny::dataTableOutput("table1")),
            tabPanel("table2", shiny::dataTableOutput("table2")),
            tabPanel("table3", shiny::dataTableOutput("table3"))
        )
    ),
    server = function(input, output) {
        myRenderDataTable <- function(a) {
            renderDataTable(
                data.frame(x = a, y = a^2, z = a^3),
                options = list(bPaginate = as.logical(a %% 2))
            )
        }
        output$table1 <- myRenderDataTable(input$button)
        output$table2 <- myRenderDataTable(input$button + 1)
        output$table3 <- myRenderDataTable(input$button + 2)
    }
))

问题

不幸的是,myRenderDataTable似乎不像renderDataTable那样被动。单击Increase input按钮应该会更改表值,但不会。

那么出了什么问题?

尝试:将呼叫转接到reactive

执行output$table1 <- reactive(myRenderDataTable(input$button)))会导致:

Error during wrapup: evaluation nested too deeply: infinite recursion / options(expressions=)?
Error : evaluation nested too deeply: infinite recursion / options(expressions=)?

尝试:将呼叫转接到observe

执行observe(output$table1 <- myRenderDataTable(input$button))对问题没有影响

2 个答案:

答案 0 :(得分:3)

问题在于input$button被“急切地”评估 - 即input$button + 1在第一次运行时评估为2,然后再也不会改变。您可以通过明确地将其input$button更改为library(shiny) runApp(list( ui = basicPage( actionButton("button", "Increase input"), tabsetPanel( tabPanel("table1", shiny::dataTableOutput("table1")), tabPanel("table2", shiny::dataTableOutput("table2")), tabPanel("table3", shiny::dataTableOutput("table3")) ) ), server = function(input, output) { myRenderDataTable <- function(a) { renderDataTable( data.frame(x = a(), y = a()^2, z = a()^3), options = list(bPaginate = as.logical(a() %% 2)) ) } output$table1 <- myRenderDataTable(reactive(input$button)) output$table2 <- myRenderDataTable(reactive(input$button + 1)) output$table3 <- myRenderDataTable(reactive(input$button + 2)) } )) 来进行评估:

{{1}}

答案 1 :(得分:1)

我认为你低估了渲染*功能中有多少魔法。通过查看此示例,我认为您不想要自定义renderDataTable函数,我认为您需要一个自定义函数来构建表格,然后您可以将其传递给内置renderDataTable 。我认为这样做你想要的,包装只是在相反的顺序(即,反应式表达式中的自定义函数):

library(shiny)
runApp(list(
    ui = basicPage(
        actionButton("button", "Increase input"),
        tabsetPanel(
            tabPanel("table1", dataTableOutput("table1")),
            tabPanel("table2", dataTableOutput("table2")),
            tabPanel("table3", dataTableOutput("table3"))
        )
    ),
    server = function(input, output) {
        myDataTable <- function(a) {
            data.frame(x = a, y = a^2, z = a^3)
        }
        output$table1 <- renderDataTable(myDataTable(input$button))
        output$table2 <- renderDataTable(myDataTable(input$button + 1))
        output$table3 <- renderDataTable(myDataTable(input$button + 2))
    }
))