I have built a Shiny dashboard which is nearly complete.
I have multiple source files containing various functions, some which reference global variables which are defined in the main R code, without being passed them as arguments directly.
I have been building it and testing/debugging it by running segments of code, and manually running the shinyapp function to launch it. When I do this, the app works as expected. The functions from the source files can read the global variables.
However, when I clear the workspace and save the code and use the "Run App" feature to run the whole thing at once, it fails because the source file functions can no longer find the global variables, even though the code which creates these variables in the global environment comes before any code which calls these functions.
Note that if I've already run the section of code manually that creates the global variables and run the app without clearing the workspace, the functions are able to read them.
Does anyone know why this is, and how I can get around it?
In the reproducible example below, the global variable is given the value "Hello_World". The function test_function() simply returns the value of the global variable which is then used as a heading in the UI.
MAIN R CODE
# Import packages.
library(shiny)
library(shinydashboard)
library(DT)
library(data.table)
library(tidyverse)
library(dtplyr)
# Global Variables
global_var <- "Hello_World"
# Directory
directory <- ''
# Source function stored in separate file.
source(paste0(directory,"Test Function.R"))
# UI
ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(
sidebarMenu(
id = "tabs",
menuItem("Test", tabName="tab_data",icon=icon("table"))
)
),
dashboardBody(
tabItem("tab_data",
fluidPage(
fluidRow(column(width=12,
h4(test_function())
))
)
)
)
)
# Server
server <- function(input, output, session) {
}
shinyApp(ui, server)
"TEST FUNCTION.R"
test_function <- function(){
return(global_var)
}
You will need to create these as two files in the home directory. The code as it is fails and throws the error:
Error in test_function() : object 'global_var' not found
If I change the last line of the code to the following, it allows the code to be run manually in segments. If I highlight the whole code and run it, it works. "Hello_World" is shown as the heading.
if(1==1){shinyApp(ui, server)}
Now if I change that statement back, now that the global variable is already created by the previous run, and run it as an app, it works.
What I need to be able to get it to do is for the source functions to be able to read the global variables from the first run when the workspace is clear.
Up front: use source("...", local = TRUE).
source by default loads the file into the global environment, not the local environment. When you're working on your console, the two are the same. However, when you run the app, the app's environment is distinct, and not in the search-path for functions defined in the global environment.
Example:
main file:
global_var <- "Hello"
source("quux.R")
quux.R:
func <- function() {
return(global_var)
}
When sourced, I see
# Error in func() (from quux.R#2) : object 'global_var' not found
Namely,
environment(func)
# <environment: R_GlobalEnv>
When I change the main file to
global_var <- "Hello"
source("quux.R", local = TRUE)
then sourcing it works, as does func() by itself.
environment(func)
# <environment: 0x0000000054a995e0>
func()
# [1] "Hello"
Test Function.R does not have access to global_var because you are sourcing Test Function.R in your main file and not the other way around. (See answer by @r2evans using local = TRUE in source would solve the problem for you.)
Now to explain why it works when you have global_var in your workspace.
Consider this example -
#Remove everything from your global environment
rm(list = ls())
#define a function which returns d
fn <- function() return(d)
#Call the function
fn()
Error in fn() : object 'd' not found
#Now define d in global environment
d <- 12
fn()
#[1] 12 #This returns 12
So R by default looks for d in the functions environment, when it fails to find it it will go one level above which in this case is global environment and this time it gets the value of d so it returns that. The same thing happens in your case.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With