R Shiny中是否存在全局变量?

43

如何在R Shiny中声明全局变量,以便您不需要多次运行相同的代码片段?作为一个非常简单的例子,我有两个图,它们使用完全相同的数据,但我只想计算一次数据。

这是ui.R文件:

library(shiny)

# Define UI for application that plots random distributions 
shinyUI(pageWithSidebar(

# Application title
headerPanel("Hello Shiny!"),

# Sidebar with a slider input for number of observations
sidebarPanel(
sliderInput("obs", 
            "Number of observations:", 
            min = 1,
            max = 1000, 
            value = 500)
  ),

# Show a plot of the generated distribution
 mainPanel(
   plotOutput("distPlot1"),
  plotOutput("distPlot2")
 )
))

这里是 server.R 文件:

library(shiny)

shinyServer(function(input, output) {

  output$distPlot1 <- renderPlot({ 
    dist <- rnorm(input$obs)
    hist(dist)
  })

  output$distPlot2 <- renderPlot({ 
    dist <- rnorm(input$obs)
    plot(dist)
  })

})

请注意,output$distPlot1output$distPlot2都执行了dist <- rnorm(input$obs),这意味着同样的代码被运行了两次。如何使"dist"向量只运行一次并且可以在所有renderplot函数中使用?我尝试将dist放在函数外面:

library(shiny)

shinyServer(function(input, output) {

  dist <- rnorm(input$obs)

  output$distPlot1 <- renderPlot({ 
    hist(dist)
  })

  output$distPlot2 <- renderPlot({ 
    plot(dist)
  })

})

但是我收到了一个错误,说找不到"dist"对象。这只是我的玩具示例,在我的真实代码中,我有50行代码要粘贴到多个“Render…”函数中。需要帮助吗?

哦,如果你想运行这段代码,只需创建一个文件并运行以下命令: library(shiny) getwd() runApp("C:/Desktop/R Projects/testShiny")

其中“testShiny”是我的R studio项目的名称。


1
只需执行 dist <- reactive(rnorm(input$obs))。现在您可以在函数中使用 dist() - Ramnath
是的,那个方法可行,但如果需要50行代码来计算距离,你该怎么办呢? - user3022875
5
只需将这50行代码放在reactive({...})内部,并在最后一行返回dist的值。 reactive只是一个包装器,使其内容具有反应性。 - Ramnath
最好的做法是将函数的大部分放在全局中,并从reactive()中调用它,这样您可以在运行应用程序时测试函数而无需停止执行。 - hedgedandlevered
2个回答

30

这个Shiny网页上的页面解释了Shiny变量的作用域。

全局变量可以放在server.R中(如Ricardo的回答所述)或者global.R中。

global.R中定义的对象类似于在shinyServer()之外的server.R中定义的对象,但有一个重要的区别:它们对ui.R中的代码也是可见的。这是因为它们被加载到R会话的全局环境中;所有Shiny应用程序中的R代码都在全局环境或其子环境中运行。

实际上,很少有必要在server.R和ui.R之间共享变量。ui.R中的代码只在启动Shiny应用程序并生成缓存的HTML文件后运行一次,并发送给每个连接的Web浏览器。这可能对于设置一些共享配置选项有用。


3
全局变量不是“响应式”的。因此,在global.R中,您不能执行类似于dist <- rnorm(input$dist)的操作。 - Ramnath
4
如果您想要全局反应变量,可以将它们定义为 reactiveValues。具体参考 reactiveValues - nico
1
但不是 input$...。这些必须在 shinyServer 中定义。 - Ramnath

25

如@nico在上面链接中提到的,你也可以在函数内部使用<<-分类器,使得函数内的变量可以在函数外部访问。

正如@nico所提到的链接中所述,您还可以在函数内部使用<<-分类器,以便将变量从函数作用域导出,使其能够在函数外部访问。

foo <<- runif(10)

而不是

foo <- runif(10)

该链接描述:“如果对象发生更改,则更改的对象将在每个用户会话中可见。但请注意,您需要使用<<-赋值运算符来更改bigDataSet,因为<<-运算符仅在本地环境中分配值。”

我在shiny中使用过这个方法,并取得了不同程度的成功。像往常一样,要小心全局变量。


谢谢!这个答案绝对救了我的一天,希望我能为此给你更多的声望点数! - lleiou

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接