Notes for Creating an R package

Reference

  1. http://vimeo.com/45939855#

  2. http://cos.name/2011/05/write-r-packages-like-a-ninja/

  3. http://mages.github.io/R_package_development/

  4. http://www.stat.ufl.edu/system/r-pkg-tut/

  5. http://cran.r-project.org/doc/contrib/Leisch-CreatingPackages.pdf

  6. http://www.stat.berkeley.edu/classes/s243/Rpackage.pdf

Basic Structure

pkg (包的名字,请使用一个有意义的名字,不要照抄这里的pkg三个字母)
|
|--DESCRIPTION (描述文件,包括包名、版本号、标题、描述、依赖关系等)
|--R (函数源文件)
	|--function1.R
	|--function2.R
	|--...
|--man (帮助文档)
	|--function1.Rd
	|--function2.Rd
	|--...
|--demo
|--data
	|--data1.rda (saved by save())
|--src
|--inst
	|--doc
		|--*.Rnw (Vignette)
|--...

DESCRIPTION

 Package: pkgname
 Version: 0.5-1
 Date: 2004-01-01
 Title: My First Collection of Functions
 Authors@R: c(person("Joe", "Developer", role = c("aut", "cre"),
					  email = "Joe.Developer@some.domain.net"),
			   person("Pat", "Developer", role = "aut"),
			   person("A.", "User", role = "ctb",
 				 email = "A.User@whereever.net"))
 Author: Joe Developer and Pat Developer, with contributions from A. User
 Maintainer: Joe Developer <Joe.Developer@some.domain.net>
 Depends: R (>= 1.8.0), nlme
 Imports: utils
 Suggests: MASS
 Description: A short (one paragraph) description of what
   the package does and why it may be useful.
 License: GPL (>= 2)
 URL: http://www.r-project.org, http://www.another.url
 BugReports: http://pkgname.bugtracker.url
 Keyword: quantile
  1. The ‘Package’, ‘Version’, ‘License’, ‘Description’, ‘Title’, ‘Author’, and ‘Maintainer’ fields are mandatory.
  2. Fields ‘Author’ and ‘Maintainer’ can be auto-generated from ‘Authors@R’, and may be omitted if the latter is provided: however if they are not ASCII we recommend that they are provided.
  3. version: 0.1.9
  4. Depends和Imports有细微差别:前者将导致加载你的包时,依赖包也被明确加载进来,用户可以直接使用这些包中的函数;后者不会导致那些包被明确加载,只有你的包在调用那些函数,但那些函数对用户是不可见的(除非用户明确加载之)。

Install

cd ~/dev/
R CMD INSTALL myfirstpkg
library(myfirstpkg)
myfun()

Rd file

 % File src/library/base/man/load.Rd
 \name{load}
 \alias{load}
 \title{Reload Saved Datasets}
 \description{
   Reload the datasets written to a file with the function
   \code{save}.
 }
 \usage{
 load(file, envir = parent.frame())
 }
 \arguments{
   \item{file}{a connection or a character string giving the
	 name of the file to load.}
   \item{envir}{the environment where the data should be
	 loaded.}
 }
 \seealso{
   \code{\link{save}}.
 }
 \examples{
 ## save all data
 save(list = ls(), file= "all.RData")

 ## restore the saved values to the current environment
 load("all.RData")

 ## restore the saved values to the workspace
 load("all.RData", .GlobalEnv)
 }
 \keyword{file}

can be generated by package.skeleton()

\emph{}
\strong{}
\code{} : for R code
\eqn{} : $$ latex
\deqn{} : displaymath
\kbd{} : keyboard
\pkg{package}
\file{}
\email{}
\cite{}
\itemize{\item[ad] }
\enumerate{\item}

roxygen2 and emacs

##' My fun
##'
##' do something
##'
##' more detail
##'
##' @author Minzhao Liu
##' @source \url{http://www.google.com}
##' @examples
##'  x <- 1

They are directly above the R function.

C-c C-o

Use:

library(roxygen2)
roxygenize('myfirstpkg')

After that, can R CMD install myfirstpkg again and now, we can use

?myfun

To use shared library:

@useDynLib qrmissing

To define method:

##' @rdname QRMissingBi
##' @method summary QRMissingBi
##' @S3method summary QRMissingBi

roxyPackage

#' Hello World function
#'
#' Say Hello
#'
#' This function is a basic Hello World function in R. It uses the
#' \code{\link{paste}} function to say hello to someone.
#'
#' @param name. Default is set to 'World'.
#' @author Markus Gesmann
#' @keywords print
#' @seealso \code{\link{paste}}
#' @export
#' @examples
#'  hello()
#'  hello(c("Alice", "Bob")

hello <- function(name="World"){
	paste("Hello", name)
}

Define DESCRIPTION in data

myDescription <- data.frame(
	Package="HelloWorld",
	Type="Package",
	Title="Hello World",
	Author="Markus Gesmann <markus.gesmann@gmail.com>",
	Maintainer="Markus Gesmann <markus.gesmann@gmail.com>",
	Depends="R (>= 2.10.0)",
	Description="Hello World package",
	License="GPL (>= 3)"
)

create package with roxy.package:

library(roxyPackage)
roxy.package(
	pck.source.dir="~/Desktop/HelloWorld/",
	R.libs="/Library/Frameworks/R.framework/Resources/library/",
	repo.root="~/Desktop/repo",
	pck.version="0.1",
	pck.description=myDescription,
	actions=c("roxy", "doc", "html", "package", "check")
	ChangeLog=list(
		added=c("new extra NULL feature", "new oblivion matrix"),
		fixed=c("finally resolved the reandom results bug")
	)
)

Just execute above script. Further we only need to update above script for DESCRIPTION infomation.

NAMESPACE

写R包时,有时候可能会遇到某些函数只是为了另外的函数的代码更短而从中抽象、独立出来的,这些小函数仅仅供你自己使用,对用户没什么帮助,他们不需要看见这些函数,这样你就可以在包的根目录下创建一个NAMESPACE文件,里面写上export(函数名)来导出那些需要对用户可见的函数

前面我们也提到DESCRIPTION文件中有Imports一栏,这里设置的包通常是你只需要其部分功能的包,例如我只想在我的包中使用foo包中的bar()函数,那么Imports中就需要填foo,而NAMESPACE中则需要写importFrom(foo, bar),在自己的包的源代码中则可以直接调用bar()函数,R会从NAMESPACE看出这个bar()对象是从哪里来的

roxygen注释对这一类命名空间有一系列标签,如一个函数的文档中若标记了##’ @export,那么这个函数将来就会出现在命名空间文件中(被导出),若写了##’ @importFrom foo bar,那么foo包的bar对象也会被写在命名空间中。这些内容参见R-exts的1.6节和roxygen2的?export帮助

fortran

useDynLib(myfirstpkg)
S3method(plot, mixdir)
S3method(summary, mixdir)
export(gibbs1,
	ritcen,
	sis1,
	sis2)

useDynLib should follow same name for the package name

If you are using any C or Fortran code in your package, you need to copy the necessary files into the src directory. The package will run R CMD SHLIB on these files to create a shared object file of the same name as your package. To insure that the library is properly loaded, you should modify the file which has been placed in the R directory to include a .First.lib() function, which will be called whenever your library is loaded. A function like this one is usually sufficient:

".First.lib" <-
function(libname,pkgname)
library.dynam("package",pkgname,libname)

where the first argument to library.dynam() is your package name in quotes without any suffix

The useDynLib line declares the connection between the FORTRAN source code and R. Within R, the FORTRAN subroutines are called with .Fortran.

The export line declares, to some extent, the visibility of your R functions to the package user. You should only list functions you want the user to call themselves, not any of the internal functions that implement your algorithms.

Create an R manual page for each of the functions you listed in the export section of NAMESPACE, and also all of the data objects you put in the data directory

Dynamically loading the shared object into a running version of R. This is done with dyn.load() for a non-packaged function, and with library.dynam (via .First.lib()) for a function in a package.

Vignette

in inst/doc/*.Rnw. Now may support *.Rmd file (after R 3.0.0)?

src

Publish

R CMD check myfirstpkg
R CMD build myfirstpkg

Notes from Jeff Leak

https://github.com/jtleek/rpackages

R functions

  1. class: classname-class.R, leek-class.R
  2. method: newclass-methodname-method.R, leek-plot-method.R

Vignettes

files should be in packagename/vignettes, during package building, the y are moved to packagename/inst/doc. For HTML, the file should be vignette.Rmd, for PDF, vignette.Rnw

Unit Tests

Use testthat package. File name : test-area-packagename.R in the inst/tests. Then make a run-all.R in a separate directory called tests, in which:

library(testthat)
library(mypackage)
test_package("mypackage")

Then when running R CMD check, there will be errors if any tests fail. See https://github.com/jtleek/rpackages for examples.



Published

19 July 2012

Modified

1 January 2014

Tags