42
votes

How do you declare global variables in with R Shiny so that you do not need to run the same pieces of code multiple times? As a very simple example I have 2 plots that use the same exact data but I only want to calculate the data ONCE.

Here is the ui.R file:

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")
 )
))

Here is the server.R file:

library(shiny)

shinyServer(function(input, output) {

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

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

})

Notice that both output$distPlot1 and output$distPlot2 do dist <- rnorm(input$obs) which is re-running the same code twice. How do you make the "dist" vector run once and make it available to all the renderplot functions? I have tried to put the dist outside the functions like:

library(shiny)

shinyServer(function(input, output) {

  dist <- rnorm(input$obs)

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

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

})

But I get an error saying the "dist" object is not found. This is a toy example in my real code I have 50 lines of code that I am pasting into multiple "Render..." function. Any help?

Oh yea if you want to run this code just create a file and run this: library(shiny) getwd() runApp("C:/Desktop/R Projects/testShiny")

where "testShiny" is the name of my R studio project.

2
Just do dist <- reactive(rnorm(input$obs)). Now you can use it as dist() in your functions.Ramnath
Yes that works but what do you do when you have 50 lines of code that is needed to calcualte dist?user3022875
Just put the 50 lines inside reactive({...}) returning the value of dist in the last line. reactive is just a wrapper that makes its contents reactive.Ramnath
its better practice to put the bulk of the function in global and call it from reactive(), so you can test your functions without having to halt execution while running the apphedgedandlevered

2 Answers

27
votes

This page on the Shiny webpage explains scoping of Shiny variables.

Global variables can either be put in server.R (as per Ricardo's answer) or in global.R.

Objects defined in global.R are similar to those defined in server.R outside shinyServer(), with one important difference: they are also visible to the code in ui.R. This is because they are loaded into the global environment of the R session; all R code in a Shiny app is run in the global environment or a child of it.

In practice, there aren’t many times where it’s necessary to share variables between server.R and ui.R. The code in ui.R is run once, when the Shiny app is started and it generates an HTML file which is cached and sent to each web browser that connects. This may be useful for setting some shared configuration options.

19
votes

As mentioned in the link that @nico lists above, you can also use the <<- classifier inside your functions to make variables accessible outside of the function.

foo <<- runif(10)

instead of

foo <- runif(10)

The link says "If the objects change, then the changed objects will be visible in every user session. But note that you would need to use the <<- assignment operator to change bigDataSet, because the <- operator only assigns values in the local environment."

I have used this to varying levels of success in shiny. As always, be careful with global variables.