Writing R Function with If Enviornment

R output of function to environment within function

As one commenter said, you can "assign" the value to a variable within the global environment. Here's a minimal example:

 functiontest <- function(value, name) {
x <- value
assign(name, x)
}

Or, using your revised example, this should give you the functionality you need.

functiontest <- function() {
object <<- c("2","3")
object
}

functiontest()

How can I reference the local environment within a function, in R?

To get the current environment, just call environment().

In general, sys.frame returns any of the environments currently on the call stack, and sys.nframe returns the current depth of the call stack. sys.frames returns a list of all environments on the call stack.

environment(f) returns the closure environment for a function f (where it will look for functions and global variables).

parent.env(e) returns the parent environment where it will look if a symbol is not found in e.

f <- function() {
function() list(curEnv=environment(), parent=parent.env(environment()),
grandParent=parent.env(parent.env(environment())), callStack=sys.frames(),
callStackDepth=sys.nframe())
}
g <- function(f, n=2) if (n>2) g(f, n-1) else f()

floc <- f() # generate a local function
g(floc, 3) # call it

This will call the local function floc with a stack depth of 3. It returns a list with the current environment, it's parent (the local environment in f), and it's grand parent (where f was defined, so globalenv). It also returns the list of stack frames (environments). These are the environments for the recursive calls in g (except the last one which is the current environment of floc).

R get object from global environment from function if object exists in global but use different default if not

You can modify your function to check if x exists in the .GlobalEnv and get it from there if it does, otherwise return the default value.

myfunc <- function(x = 30) {

if ("x" %in% ls(envir = .GlobalEnv)) {
get("x", envir = .GlobalEnv)
} else {
x
}

}

So if "x" %in% ls(envir = .GlobalEnv) is FALSE it would return

myfunc()
[1] 30

If x is found it would return it. if x <- 100:

myfunc()
[1] 100

Edit after comment

If you want to make sure to only return x from the global environment if x is not specified as an argument to myfunc, you can use missing(). It returns TRUE if x was not passed and FALSE if it was:

myfunc <- function(x = 30) {

if ("x" %in% ls(envir = .GlobalEnv) & missing(x)) {
get("x", envir = .GlobalEnv)
} else {
x
}

}

So for your example:

x <- 100
myfunc(x=300)
[1] 300

Writing to the global environment from a function in R

You don't need to assign the plot to a gloabl variable. All plots can be saved in one list.

For this example, I use the iris data set.

library(gridExtra)
library(ggplot2)
library(dplyr)

str(iris)
# 'data.frame': 150 obs. of 5 variables:
# $ Sepal.Length: num 5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
# $ Sepal.Width : num 3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
# $ Petal.Length: num 1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
# $ Petal.Width : num 0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
# $ Species : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...

The modified function without assignment:

PlottingFunction <- function(type) {
iris %>%
filter(Species == type) %>%
qplot(Sepal.Length, Sepal.Width, data = .)
}

One figure per Species is created

species <- unique(iris$Species)
# [1] setosa versicolor virginica
# Levels: setosa versicolor virginica

l <- lapply(species, PlottingFunction)

Now, the function do.call can be used to call grid.arrange with the plot objects in the list l.

do.call(grid.arrange, l)

Sample Image

substitute within a function with list as environment

This is because the two parameters that substitute takes are

substitute(expr, env)
expr - any syntactically valid R expression
env - an environment or a list object. Defaults to the current evaluation environment.

So the when you call substitute(x), that's the same as substitute(x, environment()). substitute works by pull the value of the promise from the local function environment to get the symbol used to call the function. If you use substitute(x, list(y = 'z')), it no longer will use the local environment so it can't see the x value that was passed as parameter.

How to use the R environment and the globalenv() function

Your card deck is stored in a vector deck in your Global Environment.

deal <- function(){
card <- deck[1,]
assign("deck", deck[-1,], envir = globalenv())
card
}

Each function call creates it's own environment, an object assigned inside a function "lives" just inside of it. That's why you don't "see" a vector named card in your Global Environment (unless you created one before, but this vector is uneffected by deal functions card <- deck[1,] statement).

So assign("deck", deck[-1]) (without the envir argument) would be the same as

deal <- function(){
card <- deck[1,]
deck <- deck[-1,]
card
}

but this won't change your deck outside the function. The vector deck inside the function just exists inside the function. To change the deck outside the function, you have to tell R where to change it. So that's why assign("deck", deck[-1,], envir = globalenv()) is used.

So let's start over with your function deal:

card <- deck[1,]

assigns the first element of deck to card. But wait! deck doesn't exists inside the function? So how is this possible? If the object isn't found inside the function, R looks one level up, in your case most likely the Global Environment. So there R finds an object/vector named deck and does the assignment. Now we have an object/vector named card that exists inside the function.

For further understanding, take a look at Chapter 6: Functions in Advanced R.

R Programming - creates variable in in the environment it was called

Try this:

createVariable <- function(var.name, var.value) {
assign(var.name,var.value,envir=parent.env(environment()))
}

Edit:
Some more details here and here.
With the initial solution, the variable is created in the global env because parent.env is the environment in which the function is defined and the createVariable function is defined in the global environment.

You might also want to try assign(var.name,var.value,envir=as.environment(sys.frames()[[1]])), which will create it in the highest test function calling createVariable in your example (first one on the call stack), in that case however, you will need to remove print(testVar) from testFunc when you call testFunc2 because the variable only be created in the environment of testFunc2, not testFunc. I don't know if that's what you mean by at the level at which it's called.

If you run this:

createVariable <- function(var.name, var.value) {
assign(var.name,var.value,envir=as.environment(sys.frames()[[1]]))
print("creating")
}

testFunc <- function() {
createVariable("testVar","test")
print("func1")
print(exists("testVar"))
}

testFunc2 <- function() {
testFunc()
print("func2")
print(exists("testVar"))
}

testFunc()
testFunc2()

You get

> testFunc()
[1] "creating"
[1] "func1"
[1] TRUE
> testFunc2()
[1] "creating"
[1] "func1"
[1] FALSE
[1] "func2"
[1] TRUE

Which means testVar is in testFun2's environment, not in testFunc's. Creating a new environment as others say might be safer.

How to capture a function's environment instead of its return value

Use trace to inject a statement that captures the environment as a side effect:

trace(myFun, quote(assign(".Env", environment(), .GlobalEnv)), print = FALSE)

myFun()
## [1] "hey bye hey again!"

ls(.Env)
## [1] "arg1" "arg2" "x" "y" "z"


Related Topics



Leave a reply



Submit