How to properly include dependencies in R-package? - r

I was trying now for several hours to build a package in R and getting a bit desperate about how slowly I progress. I managed quite fast to build a package with no dependencies, everything works fine. Due to recommendations in several posts, I'm using R Studio, devtools and Roxygen2 (being on Windows). With dependencies, I get problems when I CHECK (e.g. with devtools::check() ):
checking dependencies in R code ... NOTE Namespace in Imports field
not imported from: 'ggplot2' All declared Imports should be used.
See the information on DESCRIPTION files in the chapter 'Creating R
packages' of the 'Writing R Extensions' manual.
Furthermore, check() deletes the import(ggplot2) line in the NAMESPACE. If I do check(document=F), it gives an cryptic error about a digest package which is not loaded. I read 'Writing R Extensions' - 1.1.3 Package Dependencies and Hadley's Wiki concerning how to write packages, but couldn't solve my problem. DESCRIPTION and NAMESPACE files of other R packages from CRAN don't look different to mine (for my eyes)?
Question: What am I doing wrong? Sorry for such a basic question, but I am at a loss and most step-by-step tutorials I've seen so far stop before explaining dependencies.
So far, I have 3 files:
A DESCRIPTION:
Package: test
Type: Package
Title: Foo
Version: 1.0
Date: 2014-03-21
Author: Bar
Maintainer: Foo <bar#mail.com>
Description: Blubb
Imports:
ggplot2
License: GPL-3
A NAMESPACE:
export(is.equal.null)
import(ggplot2)
A R-File:
#' Extension of compare to include NULLs
#'
#' Works as an extension to usual compare
#' Compares two basic objects which in addition to usual compare can be NULL
#' Intuitive output: TRUE if both are equal or NULL resp., FALSE if both are unequal or only one is NULL
#'
#' #param obj1 Basic object like \code{numeric, char, boolean, NULL}
#' #param obj2 Basic object like \code{numeric, char, boolean, NULL}
#' #keywords compare
#' #export
#' #examples
#' is.equal.null(5,5) # TRUE
#' is.equal.null(5,NULL) # FALSE
#' is.equal.null(NULL,NULL) # TRUE
is.equal.null <- function(obj1, obj2) {
# Small helper function to generalize comparison to comparison of NULL
# returns TRUE if both are NULL, and FALSE if only one of the objects is NULL
bool <- obj1==obj2
#qplot(obj1)
if (length(bool)) return(bool)
if (is.null(obj1) & is.null(obj2)) return(TRUE)
return(FALSE)
}

You need to declare imports in two places:
The DESCRIPTION file. You should have a line similar to:
Imports: ggplot2, pkg1, pkg2
The NAMESPACE file. Here you declare the packages you need
import(ggplot2)
or to avoid namespace clashes
importFrom(ggplot2, geom_point)
You can get roxygen2 to maintain the NAMESPACE file using the #import and #importFrom tags.
In your example your DESCRIPTION file looks OK, but you haven't added the necessary functions to the NAMESPACE.

A standard workflow, as described by Hadley, is:
library(devtools)
# Add a dependency
use_package('tibble')
# (Re-)build NAMESPACE
document()
# Reload the package: CTRL-L or
load_all()

Related

devtools::document() won't include useDyLib in NAMESPACE

I am sure I am missing something stupid, but despite several hours looking online I have not been able to solve this problem.
I am trying to make a simple R package with Rcpp code. The two toy routines are
#' rtest
#'
#' This function does nothing
#' #param x a vector of numbers
#' #return a vector of number
#' #export
#' #examples
#' rtest(1:5)
rtest <- function(x) {
x^2-rtest_cpp(x)
}
and
#include <Rcpp.h>
using namespace Rcpp;
//' another routine that doesn't do much
//'
//' #param x a numeric vector
//' #return a numeric vector
// [[Rcpp::export]]
Rcpp::NumericVector rtest_cpp(Rcpp::NumericVector x) {
int k=x.size();
NumericVector y(k);
for(int i=0;i<k;++i) y[i]=x[i]*x[i];
return y;
}
Also the DESCRIPTION file is
Package: Rtest
Title: Test package
Version: 1.0.0
Authors#R:
person("Wolfgang", "Rolke", , "wolfgang.rolke#upr.edu", role = c("aut", "cre"),
comment = c(ORCID = "0000-0002-3514-726X"))
Description: Package to test various package problems.
License: GPL (>=2)
Encoding: UTF-8
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.2.1
LinkingTo: Rcpp
Imports: Rcpp
Suggests: rmarkdown, knitr
VignetteBuilder: knitr
Now when I run devtools::document() I get the NAMESPACE file with export(rtest) but not the a parts
useDynLib(“Rtest”)
importFrom(Rcpp, sourceCpp)
and so when I build the project and run rtest I get the error message that _Rtest_rtest_cpp is not available.
I can add the usedDynLib .. manually to NAMESPACE and build the project and then everything works fine, but I would much rather have the NAMESPACE file created by document().
What am I missing?
Thanks Limey. I had seen and tried this advice before, however only to add the #useDynLib part, but not to also add the #importFrom. Now it works!
I have a follow-up question, though. This is not the first package I have written with both R and Rcpp code, and I never had this problem before. I also never added those lines to the R file headers, either. And yet devtools::document() created the correct NAMESPACE file anyway. So what else tells devtools::document() to do the right thing? I once thought it was adding "LinkingTo: Rcpp;Imports: Rcpp" to DESCRIPTION , but apparently not.
Thanks Limey. I had seen and tried this advice before, however only to add the #useDynLib part, but not to also add the #importFrom. Now it works! In fact, from reading other things on the internet I created a separate file called extra.R in the R folder with the code
#' #useDynLib Rtestrolke
#' #importFrom Rcpp evalCpp
#' #exportPattern "^[[:alpha:]]+"
NULL
and that does the trick as well.
As I said in the part of the question added later, this just leaves the mystery why this is sometimes needed and sometimes not. Still don't know the answer to that.

R package - Transferring environment from imported package

Assume an R package (myPackage) that imports the R package RCircos via the DESCRIPTION file and the NAMESPACE file.
$ cat DESCRIPTION
Package: myPackage
Imports: RCircos (>= 1.2.0)
...
$ cat NAMESPACE
import(RCircos)
...
One of the perks of RCircos is that it defines a custom environment (called RCircos.Env) and reads/writes variables to this environment from various of its functions. For example, function RCircos.Initialize.Plot.Parameters reads and writes to this environment.
...
RCircosEnvironment <- NULL;
RCircosEnvironment <- get("RCircos.Env", envir = globalenv());
RCircosEnvironment[["RCircos.PlotPar"]] <- plot.param;
(This peculiar behavior has also been recognized by other R packages; see, for example, lines 247-249 of this package).
Unfortunately, it seems that the environment RCircos.Env is not recognized out of the box in myPackage when I simply import RCircos via the DESCRIPTION file and the NAMESPACE file.
So what can be done?
There seem to be two options of making the environment RCircos.Env accessible to functions like RCircos.Initialize.Plot.Parameters. However, both of these options cause the CRAN check (R CMD check myPackage --as-cran) to issue WARNINGs or NOTEs during the mandatory evaluation of myPackage prior to the submission to CRAN, thus preventing its acceptance on CRAN.
Option 1: I include the following line directly prior to the function demanding the object:
# my code here #
assign("RCircos.Env", RCircos::RCircos.Env, .GlobalEnv)
RCircos.Set.Core.Components(...)
# my code here #
However, the CRAN check highlights this line with a NOTE, thus preventing the acceptance of myPackage on CRAN.
* checking R code for possible problems ... NOTE
Found the following assignments to the global environment:
File ‘PACViR/R/visualizeWithRCircos.R’:
assign("RCircos.Env", RCircos::RCircos.Env, .GlobalEnv)
Option 2: I load the entire RCircos library prior to the function demanding the object:
# my code here #
library(RCircos)
RCircos.Set.Core.Components(...)
# my code here #
However, the CRAN check highlights this option with a WARNING, again preventing the acceptance of myPackage on CRAN.
* checking dependencies in R code ... WARNING
'library' or 'require' call not declared from: ‘RCircos’
'library' or 'require' call to ‘RCircos’ in package code.
Please use :: or requireNamespace() instead.
See section 'Suggested packages' in the 'Writing R Extensions' manual.
Surely, there must be an easy and CRAN-compatible way of making the environment RCircos.Env accessible to functions such as RCircos.Set.Core.Components within myPackage! Can someone name and explain such a way?
Apparently the normal re-export does not work with environments as it does with functions. But this does work:
RCircos.Env <- RCircos::RCircos.Env
#' test
#'
#' #param ... data
#'
#' #export
test_fun <- function(...) {
RCircos::RCircos.Set.Core.Components(...)
}
With DESCRIPTION:
Package: test
Type: Package
Title: test
Description: This is a description.
Version: 0.1.0
Authors#R: person("Wouter", "van der Bijl",
email = "redacted#redacted.com",
role = c("aut", "cre"))
Maintainer: Wouter van der Bijl <redacted#redacted.com>
License: GPL-3
Encoding: UTF-8
LazyData: true
Imports: RCircos
RoxygenNote: 6.1.1
And this NAMESPACE:
# Generated by roxygen2: do not edit by hand
export(test_fun)
Test with:
library(test)
data(UCSC.HG19.Human.CytoBandIdeogram, package = 'RCircos')
test_fun(UCSC.HG19.Human.CytoBandIdeogram)
Basically, when RCircos runs get("RCircos.Env", envir = globalenv()), it will traverse up the search path until it finds the RCircos.Env from your package instead.
When running R CMD Check I get 0 errors, 0 warnings, 0 notes.
Note that this strategy that RCircos uses, with an environment that gets looked up by using get(.., envir = globalenv()) is really unorthodox and generally not a good idea. R functions should generally not have side-effects, such as editing unseen environments. Setting default values etc. is typically done using options(). The whole package is probably not something you'd want to emulate, but at least now you can use it as a dependency.

Why does the #family tag add dots between words in roxygen2?

I am writing an R package and create documentation using roxygen2. I build the package and the documentation using the button Build & Reload in RStudio. According to RStudio's output, it uses devtools::document(roclets=c('rd', 'namespace')) to compile the documentation.
I want to use the #family tag to link together a number of functions in the documentation and this is where my problem occurs. This line
#' #family functions returning some object
is converted in the .Rd file to the following
\seealso{
Other functions.returning.some.object: \code{\link{test2}}
}
I don't want the dots between the words. I have an older package, where this does not happen, even if I recompile the documentation in the exact same setting as I compile the new package. I can see no fundamental difference between this older package and my new attempt.
I have written a very simple test package, where the problem also occurs. It contains a single R file (testpackage.R):
#' Test function 1
#'
#' #param x a number
#'
#' #family functions returning some object
#' #family aggregate functions
#'
#' #export
test1 <- function(x) {
x*x
}
#' Test function 2
#'
#' #param x a number
#'
#' #family functions returning some object
#' #family aggregate functions
#'
#' #export
test2 <- function(x) {
x*x*x
}
The DESCRIPTION file is
Package: testpackage
Type: Package
Title: Package for testing purposes
Version: 1.0
Date: 2015-05-21
Author: Me
Maintainer: Me <me#somewhere.com>
Description: Package for testing purposes
License: GPL-3
NAMESPACE is generated by roxygen. For the documentation test1.Rd, I get:
% Generated by roxygen2 (4.1.1): do not edit by hand
% Please edit documentation in R/testpackage.R
\name{test1}
\alias{test1}
\title{Test function 1}
\usage{
test1(x)
}
\arguments{
\item{x}{a number}
}
\description{
Test function 1
}
\seealso{
Other aggregate.functions: \code{\link{test2}}
Other functions.returning.some.object: \code{\link{test2}}
}
with the unwanted dots in the \seealso section. Clearly, the number of words in the #family tag seems not to matter. I have tried enclosing the text in quotation marks, various kinds of brackets, etc. with no positive effect. Of course, I could edit the Rd files, but this would miss the point of using roxygen2.
R CMD check runs without warnings or errors on testpackage.
Why do these dots appear? And how can I get rid of them?
This is a bug in roxygen2 -- I've logged an issue here. It effectively results from the use of unstack(), which performs some unwanted conversions.
I upgraded to Roxygen 5.0.0 (which is now the CRAN version) and found that the problem went away.

How to wrap data.table::fread in your own package, with bit64 capability?

I have a package containing a function that calls fread from data.table. data.table has the bit64 package in the Suggests field of its DESCRIPTION file, which gives fread the capability to import large integers as
integer64 rather than numeric. I need this capability by default in my package.
Here's a reproducible example, under R 3.1.3 (earlier versions don't have this issue).
Attempt 1
Vectorize(dir.create)(c("test", "test/R", "test/man"))
cat(
"Package: test
Title: Test pkg
Description: Investigate how to use suggested package
Version: 0.0-1
Date: 2015-03-10
Author: Richie Cotton
Maintainer: Richie Cotton <a#b.com>
Imports: data.table
Suggests: bit64
License: Unlimited
",
file = "test/DESCRIPTION"
)
cat(
"#' Read data
#'
#' Wrapper to \\code{fread} that loads bit64 first
#' #param ... Passed to fread.
#' #return A data frame of uniformly distributed random numbers and their index.
#' #importFrom data.table fread
#' #export
read_data <- function(...)
{
library(bit64)
fread(...)
}",
file = "test/R/read_data.R"
)
When I run R CMD check,
library(roxygen2)
library(devtools)
roxygenize("test")
check("test")
I get the following NOTE:
* checking dependencies in R code ... NOTE
'library' or 'require' call to 'bit64' in package code.
Please use :: or requireNamespace() instead.
See section 'Suggested packages' in the 'Writing R Extensions' manual.
Attempt 2
The documentation suggests replacing library with requireNamespace. This checks to see if the package exists, but doesn't load it onto R's search path.
If I update the definition of read_data to:
read_data <- function(...)
{
if(!requireNamespace('bit64'))
{
warning('bit64 not available.')
}
fread(...)
}
then R CMD check runs smoothly, but since bit64 is now not loaded, fread doesn't have the ability to read long integers.
Attempt 3
If I change the DESCRIPTION so that bit64 is in the Depends section (instead of Suggests, and keep read_data as in attempt 2, or simplify it to
read_data <- function(...)
{
fread(...)
}
then R CMD check gives the NOTE:
* checking dependencies in R code ... NOTE
Package in Depends field not imported from: 'bit64'
These packages need to be imported from (in the NAMESPACE file)
for when this namespace is loaded but not attached.
I'm not quite sure what I should be importing in this case.
Attempt 4
If I keep bit64 in the Depends section, and use the original definition of read_data,
read_data <- function(...)
{
library(bit64)
fread(...)
}
then R CMD check gives the NOTE:
* checking dependencies in R code ... NOTE
'library' or 'require' call to 'bit64' which was already attached by Depends.
Please remove these calls from your code.
Package in Depends field not imported from: 'bit64'
I feel like there should be some magic combination of DESCRIPTION and function definitions that gives me the bit64 functionality and passes R CMD check cleanly; I just can't see what I've missed.
How can I do this?
Attempt 3 was closest; I just needed an extra #import bit64 in the roxygen documentation.
Vectorize(dir.create)(c("test", "test/R", "test/man"))
cat(
"Package: test
Title: Test pkg
Description: Investigate how to use suggested package
Version: 0.0-1
Date: 2015-03-10
Author: Richie Cotton
Maintainer: Richie Cotton <a#b.com>
Depends: bit64
Imports: data.table
License: Unlimited
",
file = "test/DESCRIPTION"
)
cat(
"#' Read data
#'
#' Wrapper to \\code{fread} that loads bit64 first
#' #param ... Passed to fread.
#' #return A data frame of uniformly distributed random numbers and their index.
#' #import bit64
#' #importFrom data.table fread
#' #export
read_data <- function(...)
{
fread(...)
}",
file = "test/R/read_data.R"
)

devtools roxygen package creation and rd documentation

I am new to roxygen and am struggling to see how to be able to use it to quickly create a new/custom package.
I.e. I would like to know the minimum requirements are to make a package called package1 using devtools, roxygen2/3 so that I can run the commands
require(package1)
fun1(20)
fun2(20)
to generate 2000 and 4000 random normals respectively
So lets take the simplest example.
If I have two functions fun1 and fun2
fun1 <- function(x){
rnorm(100*x)
}
and
fun2 <- function(y){
rnorm(200*y)
}
the params are numeric, the return values are numeric. I'm pretty sure this isn't an S3 method, lets call the titles fun1 and fun2....im not too sure what other info i would need to provide. I can put fun1 and fun2 in separate .R files and add abit of #' but am unsure to include all relevant requirements for roxygen and also am unsure what to include as relevant requiremetns and how to use it to create the rd documentation to go with a package are. I presume the namespace would just have the names fun1 and fun2? and the package description would just be some generic information relating to me...and the function of the package?
any step by step guides would be gladly received.
EDIT: The below is how far I got to start with...
I can get as far as the following to create a pacakge...but cant use roxygen to make the documentation...
package.skeleton(list = c("fun1","fun2"), name = "package1")
and here is where I am not sure if I am missing a bunch of steps or not...
roxygenise("package1")
so when trying to install i get the following error message
system("R CMD INSTALL package1")
* installing to library ‘/Library/Frameworks/R.framework/Versions/2.15/Resources/library’
* installing *source* package ‘package1’ ...
** R
** preparing package for lazy loading
** help
Warning: /path.to.package/package1/man/package1-package.Rd:32: All text must be in a section
*** installing help indices
Error in Rd_info(db[[i]]) :
missing/empty \title field in '/path.to.package/package1/man/fun1.Rd'
Rd files must have a non-empty \title.
See chapter 'Writing R documentation' in manual 'Writing R Extensions'.
* removing ‘/Library/Frameworks/R.framework/Versions/2.15/Resources/library/package1’
I'm surprised #hadley says to not use package.skeleton in his comment. I would use package.skeleton, add roxygen comment blocks, then delete all the files in the "man" directory and run roxygenize. However, since Hadley says "Noooooooooo", here's the minimum you need to be able to build a package that passes R CMD check and exports your functions.
Create directory called "package1". Under that directory, create a file called DESCRIPTION and put this in it (edit it appropriately if you like):
DESCRIPTION
Package: package1
Type: Package
Title: What the package does (short line)
Version: 0.0.1
Date: 2012-11-12
Author: Who wrote it
Maintainer: Who to complain to <yourfault#somewhere.net>
Description: More about what it does (maybe more than one line)
License: GPL
Now create a directory called "R" and add a file for each function (or, you can put both of your functions in the same file if you want). I created 2 files: fun1.R and fun2.R
fun1.R
#' fun1
#' #param x numeric
#' #export
fun1 <- function(x){
rnorm(100*x)
}
fun2.R
#' fun2
#' #param y numeric
#' #export
fun2 <- function(y){
rnorm(200*y)
}
Now you can roxygenize your package
R> library(roxygen2)
Loading required package: digest
R> list.files()
[1] "package1"
R> roxygenize("package1")
Updating collate directive in /home/garrett/tmp/package1/DESCRIPTION
Updating namespace directives
Writing fun1.Rd
Writing fun2.Rd
Since you mentioned devtools in the title of your Q, you could use the build and install functions from devtools
build('package1')
install('package1')
Or you can exit R and use the tools that come with R to build/check/install.
$ R CMD build package1
$ R CMD check package1_0.0.1.tar.gz
$ R CMD INSTALL package1_0.0.1.tar.gz
Now, fire up R again to use your new package.
$ R --vanilla -q
library(package1)
fun1(20)
fun2(20)
But, figuring out the minimum requirements is unlikely to help you (or the users of your package) much. You'd be much better off studying one of the many, many packages that use roxgen2.
Here's a better version of the fun1.R file which still doesn't use all the roxygen tags that it could, but is much better than the bare minimum
Modified fun1.R
#' fun1
#'
#' This is the Description section
#'
#' This is the Details section
#'
#' #param x numeric. this is multiplied by 100 to determine the length of the returned vector
#' #return a numeric vector of random deviates of length \code{100 * x}
#' #author your name
#' #seealso \code{\link{fun2}}
#' #examples
#' fun1(2)
#' length(fun1(20))
#' #export
fun1 <- function(x){
rnorm(100*x)
}
Much later - You could let RoxygenReady prepare your functions with the minimal Roxygen annotation skeleton. It basically brings you from your 2 input functions to GSee's answer, which is the input of Roxygen2.

Resources