在Shiny的多个反应环境中进行更改,以避免代码冗余

时间:2014-12-25 21:28:48

标签: r shiny reactive-programming

假设我有一个非常基本的Shiny设置:

    shinyServer(function(input, output) {

    output$plot_1 <- renderPlot({ 
    DF <- DF[which(DF$column==input$num), ]
    p <- ggplot()
      ...
    plot(p))}

一切都很棒。所以,在此之后我创建了另一个ggplot,基于相同的输入,除了一行额外的代码:
        输出$ plot_2&lt; - renderPlot({

    DF <- DF[which(DF$column==input$num), ]
    DF <- *doing something different here*
    p <- ggplot()
      ...
    plot(p))}

所以我已经开始创造了10个这样的情节,彼此之间都有微小的变化。基本上,它们都有一两行不同,但都是独一无二的。 (请放心,我已经使用grid包将它们全部压缩到一页上,看起来并不坏一半。

没问题!但我开始得到一些哲学问题。

对于每一个情节,Shiny都被迫重新发明(大部分)车轮。我是:

1)获得boated代码
2)为每个绘图重新运行相同的操作 - 例如,数据框由input$num等子集化的所有工作,这在图中是一致的。

为什么和我这样?因为,据我所知,每个renderPlot内的范围是本地的。我不能在任何单独的反应函数之外全局修改我的数据帧。为了证明这一点,如果我试图将代码拉到被动呼叫之外:

    shinyServer(function(input, output) {

    DF <- DF[which(DF$column==input$num), ] #no longer within the renderPlot call

    output$plot_1 <- renderPlot({
    p <- ggplot()
      ...
    plot(p))}

我收到错误

Error in .getReactiveEnvironment()$currentContext() : 
  Operation not allowed without an active reactive context. (You tried to do something that can only be done from inside a reactive expression or observer.)  

我的情节缓慢而笨拙地出现。有大量的代码(超过90%)被运行十次,我觉得应该运行一次!

我的问题是:如何在反应环境中最好地重复修改?如何使一个输入(例如,input$num)影响我的数据帧一次,并将更改提供给我的所有10个输出?

1 个答案:

答案 0 :(得分:1)

关于使用makeReactiveBinding()的单个文件应用。

library(shiny)
    server <- function(input, output) {
      DF <- data.frame(c(2,3,5), c("aa", "bb", "cc"), c(TRUE, FALSE, TRUE))
      makeReactiveBinding("DF")

      modifData <- reactive({
        DF <- DF[,input$num, drop=FALSE]
      })


      output$dataTable <- renderDataTable({
        # Data modification is now done in reactive expression which caches the value, which means 
        # that calculation is done again only when input$num changes
        DF <- modifData()
        # Unique modifications here
        return(DF)
      })
    }

    ui <- shinyUI(fluidPage(
      sidebarLayout(
        sidebarPanel(
          sliderInput("num", "Column:", min = 1, max = 3, value = 1)
        ),
        mainPanel(dataTableOutput("dataTable"))
      )
    ))

    shinyApp(ui = ui, server = server)