I've noticed that quite a few packages allow you to pass symbol names that may not even be valid in the context where the function is called. I'm wondering how this works and how I can use it in my own code?
Here is an example with ggplot2:
a <- data.frame(x=1:10,y=1:10) library(ggplot2) qplot(data=a,x=x,y=y)
x
and y
don't exist in my namespace, but ggplot understands that they are part of the data frame and postpones their evaluation to a context in which they are valid. I've tried doing the same thing:
b <- function(data,name) { within(data,print(name)) } b(a,x)
However, this fails miserably:
Error in print(name) : object 'x' not found
What am I doing wrong? How does this work?
Note: this is not a duplicate of Pass variable name to a function in r
In JavaScript, you cannot pass parameters by reference; that is, if you pass a variable to a function, its value is copied and handed to the function (pass by value). Therefore, the function can't change the variable. If you need to do so, you must wrap the value of the variable (e.g., in an array).
A parameter is a named variable passed into a function. Parameter variables are used to import arguments into functions. For example: function example(parameter) { console.
I've recently discovered what I think is a better approach to passing variable names.
a <- data.frame(x = 1:10, y = 1:10) b <- function(df, name){ eval(substitute(name), df) } b(a, x) [1] 1 2 3 4 5 6 7 8 9 10
Update The approach uses non standard evaluation. I began explaining but quickly realized that Hadley Wickham does it much better than I could. Read this http://adv-r.had.co.nz/Computing-on-the-language.html
You can do this using match.call
for example:
b <- function(data,name) { ## match.call return a call containing the specified arguments ## and the function name also ## I convert it to a list , from which I remove the first element(-1) ## which is the function name pars <- as.list(match.call()[-1]) data[,as.character(pars$name)] } b(mtcars,cyl) [1] 6 6 4 6 8 6 8 4 4 6 6 8 8 8 8 8 8 4 4 4 4 8 8 8 8 4 4 4 8 6 8 4
explanation:
match.call returns a call in which all of the specified arguments are specified by their full names.
So here the output of match.call
is 2 symbols:
b <- function(data,name) { str(as.list(match.call()[-1])) ## I am using str to get the type and name } b(mtcars,cyl) List of 2 $ data: symbol mtcars $ name: symbol cyl
So Then I use first symbol mtcars ansd convert the second to a string:
mtcars[,"cyl"]
or equivalent to :
eval(pars$data)[,as.character(pars$name)]
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