Global Variables in R

Global variables in R

As Christian's answer with assign() shows, there is a way to assign in the global environment. A simpler, shorter (but not better ... stick with assign) way is to use the <<- operator, ie

    a <<- "new" 

inside the function.

How to assign global variables that can be accessed by other output$function in R shiny?

If you really want to assign something to global, you can use the <<- operator. Or assign("x", value = data, envir = .GlobalEnv).

But, you really don't want to. It's almost never, ever a good idea. Especially since you need to make use of reactive inputs.

If sample_d <- data() is too many keystrokes, just ignore assigning within the local environment (the output object) and use data().

output$plot <- renderPlot({
plot(density(data()[,1]), main = input$title)
})

If you want an object with multiple values, a list of objects, make your reactive object into a list and reference with $

Be sure to note however, your reactive object is a function call. So if the reactive object is data and we want the list item normalized_df we would call the reactive object data() with () and then index into the list that function returns with $. So all together we would have data()$normalized_df.

  data <- reactive({
req(input$filedata)
d <- read.csv(input$filedata$datapath, header = T)
list(data = d,
normalized_df = d + 1.5,
advanced_normalized = df + 1.5 * 45.454)
})

output$normalized_plot <- renderPlot({ #Does not work
plot(density(data()$normalizd_df[,1]), main = input$title)
})

output$advanced_normalized_plot <- renderPlot({
plot(density(data()$advanced_normalized[,1]), main = input$title)
})

Below is a minimal example that shows this in action:

library(shiny)

ui <- fluidPage(
titlePanel("Old Faithful Geyser Data"),
sidebarLayout(
sidebarPanel(
sliderInput("bins",
"Number of bins:",
min = 1,
max = 10,
value = 2)
),
mainPanel(
column(6, verbatimTextOutput("console1")),
column(6, verbatimTextOutput("console2"))
)
)
)

server <- function(input, output) {

data1 <- reactive({
datum <- mtcars
d1 <- mtcars[1:input$bins]
d2 <- d1 + 1
d3 <- d1 * 1.5
list(d1, d2, d3)
})

data2 <- reactive({
datum <- mtcars
list(d1 = mtcars[1:input$bins],
d2 = mtcars[1:input$bins] + 1,
d3 = mtcars[1:input$bins] * 1.5)
})

output$console1 <- renderPrint({
data1()
})

output$console2 <- renderPrint({
data2()
})
}

# Run the application
shinyApp(ui = ui, server = server)

Global and local variables in R

Variables declared inside a function are local to that function. For instance:

foo <- function() {
bar <- 1
}
foo()
bar

gives the following error: Error: object 'bar' not found.

If you want to make bar a global variable, you should do:

foo <- function() {
bar <<- 1
}
foo()
bar

In this case bar is accessible from outside the function.

However, unlike C, C++ or many other languages, brackets do not determine the scope of variables. For instance, in the following code snippet:

if (x > 10) {
y <- 0
}
else {
y <- 1
}

y remains accessible after the if-else statement.

As you well say, you can also create nested environments. You can have a look at these two links for understanding how to use them:

  1. http://stat.ethz.ch/R-manual/R-devel/library/base/html/environment.html
  2. http://stat.ethz.ch/R-manual/R-devel/library/base/html/get.html

Here you have a small example:

test.env <- new.env()

assign('var', 100, envir=test.env)
# or simply
test.env$var <- 100

get('var') # var cannot be found since it is not defined in this environment
get('var', envir=test.env) # now it can be found

Output selected variables to global environment R function

It is not recommended to write to global environment from inside the function. If you want to create multiple objects in the global environment return a named list from the function and use list2env.

mediansFunction <- function(x){
labmedians <- sapply(x[-1], median)
median_of_median <- median(labmedians)
grand_median <- median(as.matrix(x[-1]))
labMscore <- as.vector(round(abs(scores_na(labmedians, "mad")), digits = 2)) #calculate mscore by lab
labMscoreIndex <- which(labMscore > MscoreMax) #get the position in the vector that exceeds Mscoremax
x[-1][labMscoreIndex] <- NA # discharge values above threshold by making NA
dplyr::lst(data = x, labmedians, grand_median, labMscore)
}

result <- mediansFunction(df)
list2env(result, .GlobalEnv)

Now you have variables data, labmedians, grand_median and labMscore in the global environment.

Unit testing functions with global variables in R

I think you misunderstand what utils::globalVariables("COUNTS") does. It just declares that COUNTS is a global variable, so when the code analysis sees

addx <- function(x) {
COUNTS + x
}

it won't complain about the use of an undefined variable. However, it is up to you to actually create the variable, for example by an explicit

COUNTS <- 0

somewhere in your source. I think if you do that, you won't even need the utils::globalVariables("COUNTS") call, because the code analysis will see the global definition.

Where you would need it is when you're doing some nonstandard evaluation, so that it's not obvious where a variable comes from. Then you declare it as a global, and the code analysis won't worry about it. For example, you might get a warning about

subset(df, Col1 < 0)

because it appears to use a global variable named Col1, but of course that's fine, because the subset() function evaluates in a non-standard way, letting you include column names without writing df$Col.

Using global variable in function

Both <<- and assign will work:

myfunction <- function(var1, var2) {
# Modification of global mydata
mydata <<- ...
# Alternatively:
#assign('mydata', ..., globalenv())

# Assign locally as well
mydata <- mydata

# Definition of another variable with the new mydata
var3 <- ...

# Recursive function
mydata = myfunction(var2, var3)
}

That said, it’s almost always a bad idea to want to modify global data from a function, and there’s almost certainly a more elegant solution to this.

Furthermore, note that <<- is actually not the same as assigning to a variable in globalenv(), rather, it assigns to a variable in the parent scope, whatever that may be. For functions defined in the global environment, it’s the global environment. For functions defined elsewhere, it’s not the global environment.

store variables from a function in the global environment

You could use assign:

assign("v","hi",envir = globalenv())

This requires that you have the name of the target global variable as a string, but it can be easy to do this even with a vector of dozens of such things.

This question discusses the differences between assign and <<-. The chief difference is that assign lets you specify the environment -- so it is easy to use it to store data in a non-global but persistent environment so that you could e.g. emulate static variables in R. While it is possible to use assign to modify the global environment, you should be aware that it is seldom a good thing to do so. There is too much of a danger of accidentally overwriting data that you don't want to have overwritten. Code which makes heavy use of global variables can almost always be refactored into cleaner code which doesn't. If you need to get a lot of heterogeneous data from a function to the calling environment, the cleanest solution would be to return the needed data in a list.

The accepted answer ends its discussion of <<- and assign with a good quote:

The Evil and Wrong use is to modify variables in the global
environment.



Related Topics



Leave a reply



Submit