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)
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
Dplyr::First() to Choose First Non Na Value
Remove Geom(S) from an Existing Ggplot Chart
Get Execution Time in Milliseconds in R
Installing a Package Offline from Github
R: How Does a Foreach Loop Find a Function That Should Be Invoked
Shiny R Application That Allows Users to Modify Data
How to Combine Aes() and Aes_String() Options
How to Write Dplyr Groups to Separate Files
Specifying Xlim and Ylim When Using Log-Scale in R
Randomly Sample a Percentage of Rows Within a Data Frame
Find and Break on Repeated Runs
Recode Categorical Factor with N Categories into N Binary Columns
Rstudio Empty on Startup - No Windows, No Menus, No Rendering
R: Filling Missing Dates in a Time Series
Add New Columns to a Data.Table Containing Many Variables
Reshape Wide Format, to Multi-Column Long Format