- Code (
R/
) - Package metadata (
DESCRIPTION
) - Object documentation (
man/
) - Vignetters (
vignettes/
) - Namespaces (
NAMESPACE
) - Data (
data/
) - Compiled code (
src/
)
R/
)DESCRIPTION
)man/
)vignettes/
)NAMESPACE
)data/
)src/
)devtools::load_all()
, or in RStudio press Ctrl/Cmd + Shift + L, which also saves all open files, saving you a keystroke.# Good fit_models.R utility_functions.R # Bad foo.r stuff.r
# Good day_one day_1 # Bad first_day_of_the_month DayOne dayone djm1 # Bad T <- FALSE c <- 10 mean <- function(x) sum(x)
=
, +
, -
, <-
, etc.). The same rule applies when using =
in function calls.# Good average <- mean(feet / 12 + inches, na.rm = TRUE) # Bad average<-mean(feet/12+inches,na.rm=TRUE)
:
and ::
don't need spaces around them.# Good x <- 1:10 base::get # Bad x <- 1 : 10 base :: get
<-
).list( total = a + b + c, mean = (a + b + c) / n )
# Good if (debug) do(x) diamonds[5, ] # Bad if ( debug ) do(x) # No spaces around debug x[1,] # Needs a space after the comma x[1 ,] # Space goes after comma not before
# Good if (y < 0 && debug) { message("Y is negative") } if (y == 0) { log(x) } else { y ^ x }
# Bad if (y < 0 && debug) message("Y is negative") if (y == 0) { log(x) } else { y ^ x }
if (y < 0 && debug) message("Y is negative")
long_function_name <- function(a = "a long argument", b = "another argument", c = "another long argument") { # As usual code is indented by two spaces. }
#
.-
and =
to break up your file into easily readable chunks.# Load data --------------------------- # Plot data ---------------------------
source()
. So what is the difference between code in scripts and packages:
# It is ok in your script file and source it. library(ggplot2) show_mtcars <- function() { qplot(mpg, wt, data = mtcars) } # It won't work if you include the above code in you package foo library(foo) show_mtcars()
ggplot2
's qplot()
function won't be available: library(foo)
doesn't re-execute library(ggplot2)
.Package metadata
DESCRIPTION
Package: pkgA Type: Package Title: What the Package Does (Title Case) Version: 0.1.0 Author: Who wrote it Maintainer: The package maintainer <yourself@somewhere.net> Description: More about what it does (maybe more than one line) Use four spaces when indenting paragraphs within the Description. License: What license is it under? Encoding: UTF-8 LazyData: true
Package: pkgB Type: Package Title: What the Package Does in One 'Title Case' Line Version: 1.0 Date: 2019-11-21 Author: Your Name Maintainer: Your Name <your@email.com> Description: One paragraph description of what the package does as one or more full sentences. License: GPL (>= 2) Imports: Rcpp (>= 1.0.2) LinkingTo: Rcpp
Package: BeSS Type: Package Title: Best Subset Selection in Linear, Logistic and CoxPH Models Version: 1.0.6 Date: 2019-02-19 Author: Canhong Wen, Aijun Zhang, Shijie Quan, Xueqin Wang Maintainer: Canhong Wen <wencanhong@gmail.com> Description: An implementation of best subset selection in generalized linear model and Cox proportional hazard model via the primal dual active set algorithm proposed by Wen, C., Zhang, A., Quan, S. and Wang, X. (2017) <arXiv:1709.06254>. The algorithm formulates coefficient parameters and residuals as primal and dual variables and utilizes efficient active set selection strategies based on the complementarity of the primal and dual variables. License: GPL-3 Depends: R (>= 3.2.0) Imports: Rcpp(>= 0.12.8), Matrix(>= 1.2-6), glmnet, survival LinkingTo: Rcpp, RcppEigen NeedsCompilation: yes Packaged: 2019-02-19 15:49:51 UTC; quanshijief Repository: CRAN Date/Publication: 2019-02-21 07:20:07 UTC Built: R 3.6.1; x86_64-w64-mingw32; 2019-10-26 03:39:29 UTC; windows Archs: i386, x64
Package: ggplot2 Version: 3.2.1 Title: Create Elegant Data Visualisations Using the Grammar of Graphics Description: A system for 'declaratively' creating graphics, based on "The Grammar of Graphics". You provide the data, tell 'ggplot2' how to map variables to aesthetics, what graphical primitives to use, and it takes care of the details. Authors@R: c( person("Hadley", "Wickham", , "hadley@rstudio.com", c("aut", "cre")), person("Winston", "Chang", , role = "aut"), person("Lionel", "Henry", , role = "aut"), person("Thomas Lin", "Pedersen", role = "aut"), person("Kohske", "Takahashi", role = "aut"), person("Claus", "Wilke", role = "aut"), person("Kara", "Woo", role = "aut"), person("Hiroaki", "Yutani", role = "aut"), person("RStudio", role = c("cph")) ) Depends: R (>= 3.2) Imports: digest, grDevices, grid, gtable (>= 0.1.1), lazyeval, MASS, mgcv, reshape2, rlang (>= 0.3.0), scales (>= 0.5.0), stats, tibble, viridisLite, withr (>= 2.0.0) Suggests: covr, dplyr, ggplot2movies, hexbin, Hmisc, knitr, lattice, mapproj, maps, maptools, multcomp, munsell, nlme, profvis, quantreg, rgeos, rmarkdown, rpart, sf (>= 0.7-3), svglite (>= 1.2.0.9001), testthat (>= 0.11.0), vdiffr (>= 0.3.0) Enhances: sp License: GPL-2 | file LICENSE
URL: http://ggplot2.tidyverse.org, https://github.com/tidyverse/ggplot2 BugReports: https://github.com/tidyverse/ggplot2/issues LazyData: true Collate: 'ggproto.r' ... VignetteBuilder: knitr RoxygenNote: 6.1.1 Encoding: UTF-8 NeedsCompilation: no Packaged: 2019-08-09 20:11:46 UTC; thomas Author: Hadley Wickham [aut, cre], Winston Chang [aut], Lionel Henry [aut], Thomas Lin Pedersen [aut], Kohske Takahashi [aut], Claus Wilke [aut], Kara Woo [aut], Hiroaki Yutani [aut], RStudio [cph] Maintainer: Hadley Wickham <hadley@rstudio.com> Repository: CRAN Date/Publication: 2019-08-10 22:30:13 UTC Built: R 3.6.1; ; 2019-10-26 06:08:11 UTC; windows
Title
is a one line description of the package, and is often shown in package listing.
Description
is more detailed than the title.
The Title
and Description
for BeSS
are:
Title: Best Subset Selection in Linear, Logistic and CoxPH Models Description: An implementation of best subset selection in generalized linear model and Cox proportional hazard model via the primal dual active set algorithm proposed by Wen, C., Zhang, A., Quan, S. and Wang, X. (2017) <arXiv:1709.06254>. The algorithm formulates coefficient parameters and residuals as primal and dual variables and utilizes efficient active set selection strategies based on the complementarity of the primal and dual variables.
Maintainer
and Author
fields.Author: Canhong Wen, Aijun Zhang, Shijie Quan, Xueqin Wang Maintainer: Canhong Wen <wencanhong@gmail.com>
Authors@R: c( person("Hadley", "Wickham", email = "hadley@rstudio.com", role = "cre"), person("Winston", "Chang", email = "winston@rstudio.com", role = "aut"))
+ A three letter code specifying the `role`. There are four important roles: + `cre`: the creator or maintainer, the person you should bother if you have problems. + `aut`: authors, those who have made significant contributions to the package. + `ctb`: contributors, those who have made smaller contributions, like patches. + `cph`: copyright holder. This is used if the copyright is held by someone other than the author, typically a company (i.e. the author’s employer).
It’s the job of the DESCRIPTION
to list the packages that your package needs to work. R has a rich set of ways of describing potential dependencies.
Imports: Rcpp, Matrix
Suggests: Rcpp, Matrix
If you need a specific version of a package, specify it in parentheses after the package name:
Imports: Rcpp(>= 0.12.8), Matrix(>= 1.2-6) Suggests: Rcpp(>= 0.12.8), Matrix(>= 1.2-6)
There are three other fields that allow you to express more specialised dependencies:
Depends
: You can also use Depends to require a specific version of R, e.g. Depends: R (>= 3.0.1)
.LinkingTo
: packages listed here rely on C or C++ code in another package.Enhances
: packages listed here are “enhanced” by your package. Typically, this means you provide methods for classes defined in another package (a sort of reverse Suggests
).Object documentation
.Rd
files in the man/
directory.
roxygen2
roxygen2
Roxygen2
dynamically inspects the objects that it documents, so you can skip some boilerplate that you’d otherwise need to write by hand..R
files.devtools::document()
or press Ctrl/Cmd + Shift + D
to convert roxygen comments to .Rd
files. (devtools::document()
calls roxygen2::roxygenise()
to do the hard work.)?
or The R code in .R
file
#' Add together two numbers. #' #' @param x A number. #' @param y A number. #' @return The sum of \code{x} and \code{y}. #' @examples #' add(1, 1) #' add(10, 1) add <- function(x, y) { x + y }
The .Rd
file looks like:
% Generated by roxygen2: do not edit by hand % Please edit documentation in R/add.R \name{add} \alias{add} \title{Add together two numbers.} \usage{ add(x, y) } \arguments{ \item{x}{A number.} \item{y}{A number.} } \value{ The sum of \code{x} and \code{y}. } \description{ Add together two numbers. } \examples{ add(1, 1) add(10, 1) }
The first documentation workflow is very fast, but it has one limitation: the preview documentation pages will not show any links between pages. If you’d like to also see links, use this workflow:
Ctrl/Cmd + Shift + B
. This completely rebuilds the package, including updating all the documentation, installs it in your regular library, then restarts R and reloads your package. This is slow but thorough.?
or help()
.@tagName details
. The content of a tag extends from the end of the tag name to the start of the next tag (or the end of the block).#' Sum of vector elements. #' #' \code{sum} returns the sum of all the values present in its arguments. #' #' This is a generic function: methods can be defined for it directly or via the #' \code{\link{Summary}} group generic. For this to work properly, the arguments #' \code{...} should be unnamed, and dispatch is on the first argument. sum <- function(..., na.rm = TRUE) {}
There are two tags that make it easier for people to navigate between help files:
\url{http://www.r-project.org}
, in your package \code{\link{functioname}}
, or another package \code{\link[packagename]{functioname}}
.For sum, these components might look like:
#' @family aggregate functions #' @seealso \code{\link{prod}} for products, \code{\link{cumsum}} for cumulative #' sums, and \code{\link{colSums}}/\code{\link{rowSums}} marginal sums over #' high-dimensional arrays.
Most functions have three tags: @param, @examples and @return.
R CMD check
.\dontrun{}
allows you to include code in the example that is not run.#' Sum of vector elements. #' #' \code{sum} returns the sum of all the values present in its arguments. #' #' This is a generic function: methods can be defined for it directly #' or via the \code{\link{Summary}} group generic. For this to work properly, #' the arguments \code{...} should be unnamed, and dispatch is on the #' first argument. #' #' @param ... Numeric, complex, or logical vectors. #' @param na.rm A logical scalar. Should missing values (including NaN) #' be removed? #' @return If all inputs are integer and logical, then the output #' will be an integer. If integer overflow #' \url{http://en.wikipedia.org/wiki/Integer_overflow} occurs, the output #' will be NA with a warning. Otherwise it will be a length-one numeric or #' complex vector. #' #' Zero-length vectors have sum 0 by definition. See #' \url{http://en.wikipedia.org/wiki/Empty_sum} for more details. #' @examples #' sum(1:10) #' sum(1:5, 6:10) #' sum(F, F, F, T, T) #' sum(.Machine$integer.max, 1L) #' #' \dontrun{ #' sum("a") #' } sum <- function(..., na.rm = TRUE) {}
<package-name>.R
.#' foo: A package for computating the notorious bar statistic. #' #' The foo package provides three categories of important functions: #' foo, bar and baz. #' #' @section Foo functions: #' The foo functions ... #' #' @docType package #' @name foo NULL
## NULL
Vignetters
browseVignettes("packagename")
rmarkdown
to write your own vignette.--- title: "Vignette Title" author: "Vignette Author" date: "`r Sys.Date()`" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Vignette Title} %\VignetteEngine{knitr::rmarkdown} \usepackage[utf8]{inputenc} ---
Namespaces
?flights
summarize()
plyr
and Hmisc
provide a summarize()
function.
plyr
, then Hmisc
, summarize()
will refer to the Hmisc
version.summarize()
will refer to the plyr
version.Hmisc::summarize()
and plyr::summarize()
.Namespaces make your packages self-contained in two ways: the imports and the exports.
nrow
## function (x) ## dim(x)[1L] ## <bytecode: 0x000000000998b898> ## <environment: namespace:base>
dim(mtcars)
## [1] 32 11
dim <- function(x) c(1, 1) dim(mtcars)
## [1] 1 1
nrow(mtcars)
## [1] 32
exportPattern("^[[:alpha:]]+")
NAMESPACE
file with roxygen2
# Generated by roxygen2: do not edit by hand importFrom(tibble,tibble)
useDynLib(BeSS, .registration = TRUE) importFrom(Rcpp, evalCpp) importFrom("survival", "coxph") importFrom("survival", "Surv") importFrom("glmnet", "glmnet") importFrom("Matrix", "Matrix") importFrom("stats", "binomial", "lm","deviance", "logLik") importFrom("graphics","abline","axis","box","grid","layout","lines","mtext","par", "plot","plot.new","plot.window","text","title") importFrom("stats","glm","rbinom","rnorm","runif","model.matrix") export(bess, bess.one, gen.data, aic, bic, gic) S3method(plot,bess) S3method(coef,bess) S3method(print,bess) S3method(summary,bess) S3method(predict,bess) S3method(logLik,bess) S3method(deviance,bess) S3method(coef,bess.one) S3method(print,bess.one) S3method(summary,bess.one) S3method(predict,bess.one) S3method(logLik,bess.one) S3method(deviance,bess.one)
S3method()
, export()
, exportClasses()
, and so on.export()
: export functions (including S3 and S4 generics).exportPattern()
: export all functions that match a pattern.exportClasses()
, exportMethods()
: export S4 classes and methods.S3method()
: export S3 methods.import()
: import all functions from a package.importFrom()
: import selected functions (including S4 generics).importClassesFrom()
, importMethodsFrom()
: import S4 classes and methods.useDynLib()
: import a function from C. This is described in more detail in compiled code.Data
There are three main ways to include data in your package, depending on what you want to do with it and who should be able to use it:
data/
. This is the best place to put example datasets.R/sysdata.rda
. This is the best place to put data that your functions need.inst/extdata
.data/
..RData
file created by save()
containing a single object (with the same name as the file).data(YourDataName)
bzip2
.?data
.d <- data(package = "pkgA") ## names of data sets in the package d$results[, "Item"]
## [1] "flights" "prostate"
DESCRIPTION
contains LazyData: true
, then datasets will be lazily loaded. This means that they won’t occupy any memory until you use them.pryr::mem_used()
## Registered S3 method overwritten by 'pryr': ## method from ## print.bytes Rcpp
## 39.4 MB
library(pkgA) pryr::mem_used()
## 42.7 MB
data("flights") invisible(flights) pryr::mem_used()
## 83.4 MB
#' Flights data #' #' On-time data for all flights that departed NYC (i.e. JFK, LGA or EWR) in 2013. #' #' @source RITA, Bureau of transportation statistics, #' <https://www.transtats.bts.gov/DL_SelectFields.asp?Table_ID=236> #' @format Data frame with columns #' \describe{ #' \item{year, month, day}{Date of departure.} #' \item{dep_time, arr_time}{Actual departure and arrival times (format HHMM or HMM)} #' ... #' } "flights" #' @importFrom tibble tibble NULL
There are two additional tags that are important for documenting datasets:
\url{}
.Compiled code
NAMESPACE
by documenting them with Ctrl/Cmd + Shift + D
.Build & Reload
in the build pane, or press Ctrl/Cmd + Shift + B
.#include <Rcpp.h> using namespace Rcpp; // This is a simple example of exporting a C++ function to R. You can // source this function into an R session using the Rcpp::sourceCpp // function (or via the Source button on the editor toolbar). Learn // more about Rcpp at: // // http://www.rcpp.org/ // http://adv-r.had.co.nz/Rcpp.html // http://gallery.rcpp.org/ // // [[Rcpp::export]] NumericVector timesTwo(NumericVector x) { return x * 2; } // You can include R code blocks in C++ files processed with sourceCpp // (useful for testing and development). The R code will be automatically // run after the compilation. // /*** R timesTwo(42) */
The two most important parts are the header #include
, and the special attribute // [[Rcpp::export]]
.
Each exported C++ function automatically gets a wrapper function (it will be located in R/RcppExports.R
). For example, the R timesTwo()
function looks like:
timesTwo <- function(x) { .Call(`_pkgB_timesTwo`, x) } timesTwo(1) timesTwo(10)
You can use roxygen2 to document this like a regular R function. But instead of using #'
for comments use //'
//' Multiply a number by two //' //' @param x A single interger. //' @export // [[Rcpp::export]] NumericVector timesTwo(NumericVector x) { return x * 2; }
That generates roxygen comments in R/RcppExports.R
:
#' Multiply a number by two #' #' @param x A single interger. #' @export timesTwo <- function(x) { .Call(`_pkgB_timesTwo`, x) }
And genenrate .Rd
like this
% Generated by roxygen2: do not edit by hand % Please edit documentation in R/RcppExports.R \name{timesTwo} \alias{timesTwo} \title{Multiply a number by two} \usage{ timesTwo(x) } \arguments{ \item{x}{A single interger.} } \description{ Multiply a number by two }
To use C++ code from another package:
DESCRIPTION
, add LinkingTo: otherPackage
. It adds otherPackage/include to the include path, allowing you to dynamically “link to??? other code via the headers.C++
file, add:#include <otherPackage.h>
C++
functions from otherPackage will be included in the otherPackage
namespace. Use otherPackage::foo()
to access functions, or make them available globally with using namespace otherPackage
.The first time you add @useDynLib
, you’ll also need to run devtools::document() (Ctrl/Cmd + Shift + D)
and reload the package.
.C()
To use it, you first write a void C function, using in-place modification of function parameters to return values:
void add_(double* x, double* y, double* out) { out[0] = x[0] + y[0]; }
Then create an R wrapper:
#' @useDynLib mypackage add_ add <- function(x, y) { .C(add_, x, y, numeric(1))[[3]] }
(Here we extract the 3rd element of the result because that corresponds to the out parameter.)
.C()
automatically converts back and forth between R vectors and their C equivalents:R type | C type |
---|---|
logical | int* |
integer | int* |
double | double* |
character | char* |
raw | unsigned char* |
.C()
assumes your function doesn’t know how to deal with missing values and will throw an error if any arguments contain an NA. If it can correctly handle missing values, set NAOK = TRUE in the call to .C()
.Using C code from another package varies based on how the package is implemented:
LinkingTo: otherPackage
in the DESCRIPTION
, and #include otherPackageAPI.h
in the C file.Imports
and not LinkingTo
. You also need to make sure the package is loaded. You can do this by importing any function with @importFrom mypackage foo
, or by adding requireNamespace("mypackage", quietly = TRUE)
to .onLoad()
.It is possible to connect R to other languages, but the interfaces are not as nice as the one for C++:
.Fortran()
, or via C or C++ with .Call()
. See ?.Fortran
rJava
package makes it possible to call Java code from within R.