避免全局更改变量

时间:2017-10-28 21:03:15

标签: r shiny

我有一个简单的练习:x是一列data.frame dt。我想制作一个闪亮的应用程序,打印出x的平均值。如果复选框"乘以2"然后选择x乘以2.如果不是那么旧值。

library(shiny)
dt <- data.frame(x = 1:10, y = rep(c(2,3),5))

ui <- fluidPage(
  checkboxInput("myCheckbox", "multiple dt$x by 2"), 
  actionButton("myButton", "show result")
  )

server <- function(input, output) {
  i <- 0

  observeEvent(input$myCheckbox,{ # if this checkbox is true then dt$x should be muiltiplied by 2
    i <<- i + 1
    if(i > 1){ # first call should not change dt$x
      if(input$myCheckbox){
        dt$x <<- dt$x * 2
      }else{
        dt$x <<- dt$x / 2
      }
    } 
    })

  observeEvent(input$myButton,{
    showNotification(paste0("Mean of dt$x is equal ", mean(dt$x)), type="default")
  })
}

shinyApp(ui, server)

如何避免<<-?这是有风险的,在我使用300行代码的更大的Shiny应用程序中,我有时会得到一个错误,表示R无法选择范围。

2 个答案:

答案 0 :(得分:1)

在服务器函数中定义dt的被动版本。您可以使用多个输入值来定义反应式表达式。另一种选择是设置一个reactiveValues()对象并用观察者更新它,但我认为reactive()表达式更适合这种情况。如果您尝试定义的值完全由当前输入值确定。如果您想使用应用程序迭代操作它,那么reactiveValues()可能会更好。

library(shiny)
library(dplyr)
dt <- data.frame(x = 1:10, y = rep(c(2,3),5))


ui <- fluidPage(
  checkboxInput("myCheckbox", "multiple dt$x by 2"), 
  checkboxInput("myOtherCheckbox", "set dt$x to 0"),
  actionButton("myButton", "show result")
)


server <- function(input, output){
  dt2 <- reactive({
    mutate(dt, x = if(input$myCheckbox==TRUE){2*x} else{x}) %>%
    mutate(x = if(input$myOtherCheckbox==TRUE){0}else{x}
  })

  observeEvent(input$myButton,{
    showNotification(paste0("Mean of dt$x is equal ", mean(dt2()$x)), type="default")
  })
}


shinyApp(ui, server)

答案 1 :(得分:1)

您可以使用reactiveValues函数进行反应式编程:

library(shiny)
dt <- data.frame(x = 1:10, y = rep(c(2, 3), 5))

ui <- fluidPage(
  checkboxInput("myCheckbox", "multiple dt$x by 2"),
  actionButton("myButton", "show result")
)

server <- function(input, output) {
  values <- reactiveValues(x = dt$x)
  observeEvent(input$myCheckbox, {
    if (input$myCheckbox) {
      values$x <- values$x * 2
    } else {
      values$x <- values$x / 2
    }
  })
  observeEvent(input$myButton, {
    showNotification(paste0("Mean of dt$x is equal ", mean(values$x)), type = "default")
    print(dt$x)
  })
}

shinyApp(ui, server)

reactiveValues函数返回一个用于存储被动值的对象。它允许您避免全局更改变量,这是您想要的。