Reputation: 93
x <- y <- 1:5
df = data.frame(m=x,n=y)
myfun <- function(data, var) {
library(dplyr)
select(data, var)
}
myfun(df, m)
Error in eval(expr, envir, enclos) : object 'm' not found
Upvotes: 1
Views: 1344
Reputation: 3259
Richards answer makes it possible to bypass an arbitrary number of arguments. But to control each argument of such a select call separately you have to know:
In select(data, m)
, m is not a variable which has an assigned value at this point! It is just a symbol which gets some meaning in the context of the dataframe "data". myfun(df, m)
will fail as soon as the parameter m
is used (which is the case in the select-call), because m
has no value (or the value from the global environment, which you surely do not want!) Internally, dplyr will use the substitute
function to convert it to a symbol (instead of evaluating it). After var is converted to a symbol (or a call, for e.g. selections like m:n
), you can compose and evaluate a new select-call with do.call
.
For your example code this implies:
x <- y <- 1:5
df = data.frame(m=x,n=y)
myfun <- function(data, var) {
library(dplyr)
var <- substitute(var)
do.call('select', list(data, var))
}
myfun(df, m)
The generalization to more arguments is straight forward.
For an arbitrary number of arguments which you want to convert to symbols or calls you can use
myfun <- function(...) {
args <- substitute(list(...))
# Now args[i] is a symbol/call representing the i-th argument
}
Upvotes: 2
Reputation: 99371
select
uses select.data.frame
, a data frame method. The second argument to select
is a ...
list so that arguments can be passed to other methods. Your function uses the name var
in its second argument, and because of dplyr
's .()
function, the base R variance function var
is being passed to other functions inside select
.
Long story short, change your argument names. I would go with
myfun <- function(z, ...) select(z, ...)
myfun(df, x)
myfun(df, y)
You can also use the select
methods
> select.myfun <- function(.data, ...) UseMethod("select")
> myfun(df, exclude = "x")
> methods(select)[6]
[1] "select.myfun"
As a shameless plug, I'll refer you to a question I asked about ...
arguments. There are two very good explanations in the answers.
Edit As requested, a look at .()
> `.`
function (..., .env = parent.frame())
{
structure(as.list(match.call()[-1]), env = .env, class = "quoted")
}
<environment: namespace:plyr>
> .(x)
List of 1
$ x: symbol x
- attr(*, "env")=<environment: R_GlobalEnv>
- attr(*, "class")= chr "quoted"
Upvotes: 0