Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

R namespace access and match.fun

I'm working on an R package where one of the functions contains a match.fun call to a function in a package that's imported to the package namespace. But on loading the package, the match.fun call can't find the function name. From Hadley Wickham's description I think I'm doing everything right, but this is clearly not the case.

Example:

# in the package file header, for creation of the NAMESPACE via roxygen2:
##` @import topicmodels

# The function declaration in the package
ModelTopics <- function(doc.term.mat, num.topics, topic.method="LDA"){
  topic.fun <- match.fun(topic.method)
  output <- topic.fun(doc.term.mat, k=num.topics)
  return(output)

}    

And then in R:

> library(mypackage)
> sample.output <- ModelTopics(my.dtm, topic.method="LDA", num.topics=5)
Error in get(as.character(FUN), mode = "function", envir = envir) : 
  object 'LDA' of mode 'function' was not found

From my understanding of namespaces, the match.fun call should have access to the package namespace, which should include the topicmodels functions. But that doesn't appear to be the case here. If I import topicmodels directly to the global namespace for the R session, then this works.

Any help is much appreciated. This is R64 2.14.1 running on OSX.

UPDATE: The package is here

Re the DESCRIPTION file, perhaps that's the problem: roxygen2 doesn't update the DESCRIPTION file with Imports: statements. But none of the other packages are listed there, either; only the match.fun calls appear to be affected.

Re the NAMESPACE extract, here's the import section:

import(catspec)
import(foreach)
import(gdata)
import(Hmisc)
import(igraph)
import(lsa)
import(Matrix)
import(plyr)
import(RecordLinkage)
import(reshape)
import(RWeka)
import(stringr)
import(tm)
import(topicmodels)
like image 530
markhuberty Avatar asked Aug 16 '12 15:08

markhuberty


1 Answers

I believe this an issue of scope. Although you have imported topicmodels and thus LDA, you haven't exported these functions, so they aren't available in the search path.

From ?match.fun:

match.fun is not intended to be used at the top level since it will perform matching in the parent of the caller.

Thus, since you are using ModelTopics in the global environment, and LDA isn't available in the global environment, the match.fun call fails.


It seems to me you have two options:

Option 1: use get

An alternative would be to use get where you can specify the environment. Consider this: try to use match.fun to find print.ggplot in the package ggplot2:

match.fun("print.ggplot")
Error in get(as.character(FUN), mode = "function", envir = envir) : 
  object 'print.ggplot' of mode 'function' was not found

Since print.ggplot isn't exported, match.fun can't find it.

However, get does find it:

get("print.ggplot", envir=environment(ggplot))
function (x, newpage = is.null(vp), vp = NULL, ...) 
{
    set_last_plot(x)
    if (newpage) 
        grid.newpage()
    data <- ggplot_build(x)
    gtable <- ggplot_gtable(data)
    if (is.null(vp)) {
        grid.draw(gtable)
    }
    else {
        if (is.character(vp)) 
            seekViewport(vp)
        else pushViewport(vp)
        grid.draw(gtable)
        upViewport()
    }
    invisible(data)
}
<environment: namespace:ggplot2>

Option 2: Export the functions from topicmodels that you need

If you make the necessary functions from topicmodels available in your NAMESPACE, your code should also work.

Do this by either:

  • Selective exporting LDA and other functions to the namespace using @export
  • Declare a dependency, using Depends: topicmodels - this is the same as calling library(topicmodels) in the global environment. This will work, but is possibly a bit of a brute force approach. It also means that any subsequent library call can mask your LDA function, thus leading to unexpected results.
like image 63
Andrie Avatar answered Nov 20 '22 15:11

Andrie