First of all, sorry that I do not provide a fully reproducible example, but I'm using the devel version of a BioConductor package and the installation is a bit of a pain in the butt.
I am trying to use do.call to invoke functions based on a string I paste together. Like so:
testfunction <- function(){
print("do.call is working")
}
do.call(paste("test", "function", sep = ""), args = list())
This prints:
"do.call is working"
When I am trying to invoke my function of interest, like so:
for (dataset in unique(metadata[, 1])){
replace_idx <- which(metadata[,1 ] == dataset)
do.call(paste('curatedMetagenomicData::', dataset, ".genefamilies_relab.stool", sep = ""), args = list())
if (length(replace_idx) > 0){
# Do further stuff.
}
}
I get this error:
Error in
curatedMetagenomicData::ZellerG_2014.genefamilies_relab.stool() :
could not find function
"curatedMetagenomicData::ZellerG_2014.genefamilies_relab.stool"
Invoking the function outside of the loop, without do.call, works.
Could this be an environment problem of some sort? Any help is greatly appreciated.
Related
I use the following code in a function that is part of an R package I am writing:
x = "a"
y = "b"
rlang::expr(`=`(!!rlang::ensym(x), !!rlang::as_name(y)))
It automatically creates arguments for a function further down the line that look like this:
a = "b"
Which can then be plugged into a function like this:
foo(a = "b")
The problem is that when I run the devtools::check() function I get a note due to this part of the code.
my_function : <anonymous>: no visible global function definition for '!<-'
I assume the problem is the bang-bang (!!) together with the = function but I could not really figure out how to solve this.
Would be great if someone has an idea of what to do to prevent this note from occurring! Thanks a lot!
Edit: Based on MrFlick answer I am now using the following:
x = c("a", "b")
y = c("y", "z")
args <- purrr::map2(.x = x,
.y = y,
.f = function(x, y){
rlang::exprs(!!rlang::as_name(x) := !!y)
})
rlang::expr(foo(!!!unlist(args)))
The CRAN checks don't really like non-standard evaluation so when it sees you calling the = function which it interprets as the <- function, it doesn't like it.
The rlang package gets around this by defining the := operator when you are trying to dynamically build named parameters. So instead you can build your arguments with
args <- rlang::exprs(!!rlang::as_name(x) := !!y)
And then inject them into the call with
rlang::expr(foo(!!!args))
# foo(a = "b")
That should prevent CRAN from trying to find the special assignment operator and is generally how one should use rlang for such a purpose.
This is expected. Use utils::globalVariables("!<-") to silence this NOTE.
I am trying to write a function to load several libraries at once. Through other forums and threads I have found that this works:
read_library <- function(...) {
x <- c(...)
invisible(lapply(x, library, character.only = TRUE))
}
However, this forces me to write my libraries between "", i.e.:
read_library("tidyverse",
"readr",
"infer",
"modelr",
"statip",
"knitr",
"rmdformats")
Which I would like to avoid. Is there anything I could add to my function that would eliminate this first world problem?
Another way could be using alist with eval and substitute like below:
read_library <- function(...) {
obj <- eval(substitute(alist(...)))
#print(obj)
return(invisible(lapply(obj, function(x)library(toString(x), character.only=TRUE))))
}
read_library(gtools, ggplot2, tidyverse)
alist handles its arguments as if they described function arguments. So the values are not evaluated together with substitute it returns un-evaluated expression. Once we have the expression, we use eval to get a list of objects of class name, so that we can parse it as string in lapply.
You could use substitute with list like :
read_library <- function(...) {
invisible(lapply(substitute(list(...))[-1], function(x)
library(deparse(x), character.only = TRUE)))
}
read_library(tidyverse,
readr,
infer,
modelr,
knitr,
scales)
I know how partial function works. However, when I look at the source code of partial(), I don't quite understand how it works. Could anyone tell me how each line works?
> partial
function (`_f`, ..., .env = parent.frame(), .lazy = TRUE)
{
stopifnot(is.function(`_f`))
if (.lazy) {
fcall <- substitute(`_f`(...))
}
else {
fcall <- make_call(substitute(`_f`), .args = list(...))
}
fcall[[length(fcall) + 1]] <- quote(...)
args <- list(... = quote(expr = ))
make_function(args, fcall, .env)
}
<environment: namespace:pryr>
What is `_f`? Why using substitute() in this way
substitute(`_f`(...))
What is this?
quote(expr = )
Why is the following line necessary?
fcall[[length(fcall) + 1]] <- quote(...)
Some operations in R don't look like function calls, but they are. For example, 3+4 can also be written as `+`(3,4). In this case, since the partial function works by pre-filling in arguments, the "substitute" here works by substituting any variables found in the environment into "...".
quote() works by capturing the action
Seems like the fcall line is used to maintain what was originally placed into the partial call
This question already has an answer here:
In R, getting the following error: "attempt to replicate an object of type 'closure'"
(1 answer)
Closed 9 years ago.
I'm trying to write a function that can apply another function to a number of data.frames at one time. The data.frames are named DATA_1, DATA_2, etc. and the variable 'actioncol' is to indicate the column that has to be changed. This is my code so far:
gsubFUN <- function(name, actioncol, ...){
df.vec <- ls(pattern = paste("name", "*", sep="_"), envir=.GlobalEnv)
for(ii in 1:length(df.vec)){
DATA <- get(df.vec[ii])
DATA[,actioncol] <- gsub(pattern.vec[ii], replace.vec[ii], DATA[,actioncol])
assign(paste(name, ii, sep = "_"),DATA, envir = .GlobalEnv)
}
}
I am aware that my code may be quite messed up, but it does work. Since I would like the outer function to apply other functions (not just gsub) on the data.frames, too, I tried to replace it with a variable:
multiDfFUN <- function(name, actioncol, FUN, ...){
df.vec <- ls(pattern = paste(name, "*", sep="_"), envir=.GlobalEnv)
for(ii in 1:length(df.vec)){
DATA <- get(df.vec[ii])
DATA[,actioncol] <- match.fun(FUN)
assign(paste(name, ii, sep = "_"),DATA, envir = .GlobalEnv)
}
}
multiDfFUN(name="audi", actioncol="color", FUN=gsub, pattern=pattern.vec[ii],
replacement=replace.vec[ii], x=DATA[,actioncol])
However, this now returns an error message:
error in rep(value, length.out = n) :
attempt to replicate an object of type 'closure'
I don't even understand the meaning of this. Searching the web wouldn't help it either. Could the arguments pattern, replacement & x when calling the function be the reason for this? I would be really glad if somebody could enlighten me on this issue or even point me to a simple solution (if there is any).
Many thanks in advance.
This line:
DATA[,actioncol] <- match.fun(FUN)
... is attempting to assign functions (not function names) to items in a dataframe. That's not going to succeed. And then you write:
assign(paste(name, ii, sep = "_"),DATA, envir = .GlobalEnv)
That effort is very contrary to the preferred programing style of R. Assigning to the GlobalEnv from within the function body should only be attempted by people who know what that error message meant. match.fun returns a functions so I image you would wnat to do something like this:
DATA[,actioncol] <- match.fun(FUN)( DATA[,actioncol] )
return(DATA)
And then call it like:
DATAnew <- multiDfFUN(name="audi", actioncol="color", FUN=gsub,
pattern=pattern.vec[ii],
replacement=replace.vec[ii], x=DATA[,actioncol])
Since we have no example data to work with, I will leave this as an untested guess.
Note added in proof:
fortunes::fortune("understand why")
The only people who should use the assign function are those who fully understand
why you should never use the assign function.
-- Greg Snow
R-help (July 2009)
Examns kept me quite busy, that's why I'm just answering now. DWin's suggestions actually helped me get the function to work as intended.
I also took all your warnings about attachin consideration. But as mentioned before, I did this code for an assignment where I was explicitly asked to use it. So this is what I ended up with:
MultiDfFUN <- function(df.vec, col.name, col.new="new", df.name,
FUN, overwrite=F, ...){
df.list <- list(NULL)
for(ii in 1:length(df.vec)){
DATA <- get(df.vec[ii])
DATA[,col.new] <- FUN(DATA[,col.name],...)
if(overwrite == TRUE){
assign(paste(df.name, ii, sep = "_"),DATA, envir = .GlobalEnv)
}else{
df.list[[ii]] <- DATA[,col.new]
}
}
if(overwrite == FALSE) return(df.list)
}
I was trying to write a function to parse and merge some data. But R throws an unexpected symbol error exception. I have tried different ways to solve this issue, still doesn't work. Please help.
see code
$aggall = function(df,grp){numcols = sapply(df,class) %in%
c('integer', 'numeric') result = aggregate(df[,numcols],df[grp],mean)
counts = as.data.frame(table(df[grp])) names(counts)[1] =
grp merge(counts, result, sort=FALSE)}
Error: unexpected symbol in "aggall = function(go,grp){numcols = sapply(go,class) %in% c('integer','numeric') results"
you have your whole function in one physical line.
Therefore, when R tries to parse it, it has no way of knowing when one line ends and the next one begins.
To fix this, either use separate lines or add a semicolon between them.
Alternatively, you can have the formatR package do it for you!
(pretty awesome package):
install.packages("formatR")
library(formatR)
tidy.source("mySource.R", reindent.space=5)
aggall = function(df, grp) {
numcols = sapply(df, class) %in% c("integer", "numeric")
result = aggregate(df[, numcols], df[grp], mean)
counts = as.data.frame(table(df[grp]))
names(counts)[1] = grp
merge(counts, result, sort = FALSE)
}