17

I am developing a package with roxygen2, that includes a number of lattice based visualizations. These are nice but not necessary for using the package, and therefore lattice is listed in the Suggests: section of the DESCRIPTION file rather than the Depends: section.

However, I have not yet figured out how to load lattice upon request from the user in a way that pass both roxygenize() and R CMD check. The following two ways both makes lattice look like an unstated dependency and will return the error below.

##' @import lattice
{}

##' Visualization
##'
##' @param x Data.
##' @param y More data.
##' @export
vizz <- function(x, y){
    xyplot(y ~ x)
}

and

##' Visualization
##'
##' @param x Data.
##' @param y More data.
##' @export
vizz <- function(x, y){
    library(lattice)
    xyplot(y ~ x)
}

both gives the same error

$ R CMD check dummy.roxygen

* using log directory ‘/###/dummy.roxygen.Rcheck’
* using R version 3.0.2 (2013-09-25)
* using platform: x86_64-pc-linux-gnu (64-bit)
* using session charset: UTF-8
* checking for file ‘dummy.roxygen/DESCRIPTION’ ... OK
* checking extension type ... Package
* this is package ‘dummy’ version ‘1.0-0’
* package encoding: UTF-8
* checking package namespace information ... OK
* checking package dependencies ... ERROR
Namespace dependencies not required: ‘lattice’

See the information on DESCRIPTION files in the chapter ‘Creating R
packages’ of the ‘Writing R Extensions’ manual.

Since searches on the term "roxygen" combined with "suggests", "depends" and "imports" return a flood of irrelevant hits, I have unsuccessfully been looking for an answer to this for quite some time. Meanwhile I have just listed lattice and a number of other nice but non-vital-packages as dependencies instead, but now when I am about to publish the package I would like to solve it the proper way.

Backlin
  • 14,612
  • 2
  • 49
  • 81
  • Did you try adding `#' @importFrom lattice xyplot` in your function roxygen section ? – juba Oct 18 '13 at 09:52
  • I did now, but it gives me the same error. – Backlin Oct 18 '13 at 09:56
  • But did roxygen add lattice to your `Imports` section in `DESCRIPTION` ? – juba Oct 18 '13 at 09:57
  • In roxygenization of the package, `lattice` remains in the `Suggests` section of the `DESCRIPTION` file, but it is listed as `import(lattice)` in the `NAMESPACE` file. So the problem lies in `roxygenize()` rather than `R CMD check` I conclude. – Backlin Oct 18 '13 at 10:01
  • Try manually moving lattice from `Suggests` to `Imports`, maybe? – juba Oct 18 '13 at 10:03
  • I think you might be onto something here! Just give me a little time to confirm that it works the way I hope it does. Btw, if I list `lattice` under `Imports`, do you know if it is automatically installed when someone installs my package? – Backlin Oct 18 '13 at 10:29
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/39484/discussion-between-backlin-and-juba) – Backlin Oct 18 '13 at 10:32
  • @Backlin Rather than just update your question with the solution, you can submit and answer and even accept that answer. That way it is more obvious that you have found a solution and what the solution was. – Brian Diggs Oct 18 '13 at 15:51

2 Answers2

13

The recommendation used (in 2013 when I first wrote this answer) to be to require in a conditional statement. Now in 2016 the official recommendation is to use :: and let R print the there is no package called X error:

##' Visualization
##'
##' @description Visualize the data. \pkg{\link{lattice}} package required.
##' @param x Data.
##' @param y More data.
##' @seealso \pkg{\link{lattice}}
##' @export
vizz <- function(x, y){
    lattice::xyplot(y ~ x)
}

And only keep Suggests: lattice in your DESCRIPTION (no import in the NAMESPACE).

If you want to customize the error message you can now use requireNamespace(lattice) in a conditional statement, such as:

vizz <- function(x, y){
    if (! requireNamespace("lattice", quietly = TRUE)) {
        stop("Please install lattice: install.packages('lattice')")
    lattice::xyplot(y ~ x)
}
Calimo
  • 7,510
  • 4
  • 39
  • 61
  • 1
    Other than being the conventional way to do it, do you know if there is any particular reason for using `if(require(pkg)) stop(msg)` rather than `library(pkg)` which will automatically throw the error you specified manually? – Backlin Dec 02 '13 at 17:16
  • I don't think there is a reason as both functions apparently do the exact same thing. – Calimo Dec 02 '13 at 18:11
  • Then I'll probably stick with my own answer, since me and @while already had a discussion about this. But thanks for adding it for completeness sake! – Backlin Dec 03 '13 at 09:16
  • 1
    Note that the recommendations changed, and now call for the use of `::` instead. See https://cran.r-project.org/doc/manuals/r-release/R-exts.html#Suggested-packages. I'll update my answer – Calimo Apr 12 '16 at 14:46
0

I am not sure what has been causing my problems, but after some debugging with the help of @juba it turns out I had already suggested the correct solution in the question. The proper way to deal with nice-but-not-vital packages is to list them in the Suggests: section of the DESCRIPTION file, and tag them the following way using roxygen.

##' Visualization
##'
##' See \code{\link[lattice]{xyplot}} for details.
##'
##' @param x Data.
##' @param y More data.
##' @export
vizz <- function(x, y){
    library(lattice)
    xyplot(y ~ x)
}

This will not automatically install nor attach lattice upon installing/attaching my package, but simply throw an error if lattice cannot be attached when the function is executed.

Backlin
  • 14,612
  • 2
  • 49
  • 81
  • According to the documentation you should use `require` instead of `library` within functions as it will warn instead of throwing an error if the package is missing. – while Nov 01 '13 at 13:53
  • 1
    I have seen that too. However, in my case I *want* to throw an error if the package is missing. If not, an error about not finding the `xyplot` function would be thrown on the next line anyway, which is probably more ambiguous to the end user. – Backlin Nov 01 '13 at 14:03
  • Ok, sorry. In that case you should probably use `library`. Just wanted to share in case you missed it as the library should be loaded automatically if you use require as well. You can also handle the result more flexible if you use `require` as it will return a boolean. – while Nov 02 '13 at 09:56
  • Yes, you got a point. The best solution might even be to test if the package can be loaded with `require`, and if it's not found ask the user if it should be installed automatically. – Backlin Nov 03 '13 at 16:13
  • 1
    Way late to the discussion, but more food-for-thought: many (most?) functions are written to minimize side-effect, but any package code that calls either `library` or `require` changes the search path for the rest of the R session, even after the function exits. This is often not a huge problem, but with increasing namespace collisions (e.g., `filter()` in `stats` and `dplyr`), it *does* have an effect. I find it is generally best to use either `::` as already mentioned, or if a return is required then `requireNamespace` followed by the `::`-function call. Search path not altered. – r2evans May 12 '21 at 18:55