do.call error “second argument must be a list” with S4Vectors when the code is in a library

我的梦境 提交于 2019-12-11 07:12:43

问题


This is a question raised in the context of this other one: Extract and paste together multiple columns of a data frame like object using a vector of column names

I received an answer based on the usage of do.call which happens to not work when the code is part of a library, but worked well when implemented as part of the main script.

Here is my attempt at making a simplified example:

File example.do.call.R:

library(S4Vectors)
library(test.package)
data <- DataFrame(A=letters[1:6], B=LETTERS[1:6])

test_do_paste <- function(data) {
    groups <- c("A", "B")
    combined_letters <- do.call(paste, data[groups])
    print(combined_letters)
}

test_do_paste(data)
#test.package::test_do_paste(data)

The same test_do_paste function is present as a single function in a package I organize and install according to https://hilaryparker.com/2014/04/29/writing-an-r-package-from-scratch/.

When running Rscript example.do.call.R as above, I obtain the expected result:

[1] "a A" "b B" "c C" "d D" "e E" "f F"

However, if I switch to the commented version (using the function from the library), I get the following error:

Error in do.call(paste, data[groups]) : second argument must be a list
Calls: <Anonymous> -> do.call
Execution halted

My questions are:

  1. Why is that?

  2. How can I avoid the error?


Some investigation

I used a normal data.frame instead of the DataFrame

In this case, the error doesn't happen.

Note that in my real application, I'm actually using some more complicated object than a DataFrame, but there is a colData function that extracts a DataFrame from this object.

Maybe there would be a way to circumvent the problem if I was able to convert this further into a normal data.frame.

as.data.frame actually does this, so question 2 has at least this solution in my case.

I inserted a print(class(data[groups])) in the function

In both cases I get the following:

[1] "DataFrame"
attr(,"package")
[1] "S4Vectors"

So, apparently, even in the case that works, the object I give as second argument to do.call is not a list.

I inserted a print(do.call) in the function.

When run from the library, I obtain just a few lines:

function (what, args, quote = FALSE, envir = parent.frame())
{
    if (!is.list(args)) 
        stop("second argument must be a list")
    if (quote) 
        args <- lapply(args, enquote)
    .Internal(do.call(what, args, envir))
}
<bytecode: 0x1b7cdd8>
<environment: namespace:base>

But when run in the script, there is much more output:

function (what, args, quote = FALSE, envir = parent.frame()) 
standardGeneric("do.call")
<environment: 0x1d8c568>
attr(,"generic")
[1] "do.call"
attr(,"generic")attr(,"package")
[1] "BiocGenerics"
attr(,"package")
[1] "BiocGenerics"
attr(,"group")
list()
attr(,"valueClass")
character(0)
attr(,"signature")
[1] "what" "args"
attr(,"default")
Method Definition (Class "derivedDefaultMethod"):

function (what, args, quote = FALSE, envir = parent.frame()) 
{
    if (!is.list(args)) 
        stop("second argument must be a list")
    if (quote) 
        args <- lapply(args, enquote)
    .Internal(do.call(what, args, envir))
}
<bytecode: 0x1d8e660>
<environment: namespace:base>

Signatures:
        what 
target  "ANY"
defined "ANY"
attr(,"skeleton")
(function (what, args, quote = FALSE, envir = parent.frame()) 
{
    if (!is.list(args)) 
        stop("second argument must be a list")
    if (quote) 
        args <- lapply(args, enquote)
    .Internal(do.call(what, args, envir))
})(what, args, quote, envir)
attr(,"class")
[1] "standardGeneric"
attr(,"class")attr(,"package")
[1] "methods"

This raises more questions:

  1. Why this difference?

  2. Could it explain the error in the "library" case?

来源:https://stackoverflow.com/questions/40807266/do-call-error-second-argument-must-be-a-list-with-s4vectors-when-the-code-is-i

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!