Biostatistical Computing, PHC 6068

R package

Zhiguang Huo (Caleb)

Monday Sep 27, 2021

Install R packages

install.packages("mclust")
## try http:// if https:// URLs are not supported
if (!requireNamespace("BiocManager", quietly = TRUE))
    install.packages("BiocManager")

BiocManager::install("impute")
install.packages("mclust_5.4.7.tar",repos=NULL,type="source")
# in R: 
system("R CMD INSTALL mclust")
#command line: R CMD INSTALL mclust
library(devtools)
install_github("cran/mclust")

Why R package

Basic structure of an R Package

Play with survival package

library(survival)
help(package = 'survival')
?coxph
browseVignettes("survival")

Structure of R package

DESCRIPTION

The job of the DESCRIPTION file is to store important metadata about your package. Every package must have a DESCRIPTION. In fact, it’s the defining feature of a package.

DESCRIPTION License

DESCRIPTION Version

Formally, an R package version is a sequence of at least two integers separated by either . or -. For example, 1.0 and 0.9.1-10 are valid versions, but 1 or 1.0-devel are not.

The namespace file in R package

Namespace

base::dim
nrow
dim(mtcars)
dim <- function(x) c(1, 1)
dim(mtcars)
nrow(mtcars)

Man (for manual)

Devtools, starting from sketches.

Red color indicates essential steps

  1. usethis::create_package() create an new R package
  2. Copy your R code in inside R folder
  3. formatR::tidy_dir() clean up the code
  4. Add documentation in R code
  5. devtools::document() generate R documentation
  6. usethis::use_data() prepare external data
  7. usethis::use_testthat() prepare test functions
  8. devtools::test() preform test
  9. usethis::use_vignette() generate vignettes
  10. devtools::check() check the package
  11. devtools::build() build the package
  12. devtools::install() install the package
  13. others

1. devtools::create() create an new R package

## set working directory to be Desktop
WD <- '~/Desktop'
setwd(WD)

usethis::create_package("GatorPKG", open = FALSE) ## open = FALSE will prevent R open a new R studio session.
WD2 <- '~/Desktop/GatorPKG'
setwd(WD2)

2. Copy your R code in inside R folder

##' @export
f <- function(x, y) x + y
##' @export
g <- function(x, y) x - y
##' @export
h <- function(x, y) f(x,y) * g(x,y)
##' @export
all <- function(x, y){
  f0 <- f(x,y)
  g0 <- g(x,y)
  h0 <- h(x,y)
  list(f=f0, g=g0, h=h0)
}

3. formatR::tidy dir() clean up the code

setwd(WD2)
## make the code neat
formatR::tidy_dir("R")

4. Add documentation in R code

##' Add up two numbers (Description)
##'
##' We want to add up two numbers, blalala... (Details)
##' @title add two numbers
##' @param x first number
##' @param y second number
##' @return sum of two numbers
##' @author Caleb
##' @export
##' @examples
##' f(1,2)
f <- function(x, y) x + y
##' Subtract two numbers (Description)
##'
##' We want to Subtract two numbers, blalala... (Details)
##' @title Subtract two numbers
##' @param x first number
##' @param y second number
##' @return x - y
##' @author Caleb
##' @export
##' @examples
##' g(2,1)
g <- function(x, y) x - y
##' Complex operations on two numbers (Description)
##'
##' We want to do some complex operations on two numbers, blalala... (Details)
##' @title Very complex operation of two numbers
##' @param x first number
##' @param y second number
##' @return (x - y)(x + y)
##' @author Caleb
##' @export
##' @examples
##' h(3,2)
h <- function(x, y) f(x,y) * g(x,y)
##' Return f,g,h (Description)
##'
##' We want to return f,g,h , blalala... (Details)
##' @title return all
##' @param x first number
##' @param y second number
##' @return A list of f, g, and h.
##' \item{f}{Results for adding}
##' \item{g}{Results for subtracting}
##' \item{h}{Complex Result}
##' @author Caleb
##' @export
##' @examples
##' all(3,2)
all <- function(x, y){
  f0 <- f(x,y)
  g0 <- g(x,y)
  h0 <- h(x,y)
  list(f=f0, g=g0, h=h0)
}

5. devtools::document() generate R documentation

devtools::document() ## default argument is pkg = ".", current working directory

Change:

6. usethis::use_data() prepare external data

xxxx <- sample(1000)
usethis::use_data(xxxx)

Change:

data(xxxx)

6. documenting external data

xxxx.R

#' Prices of 50,000 round cut diamonds.
#'
#' A dataset containing the prices and other attributes of almost 54,000
#' diamonds.
#'
#' @format A data frame with 53940 rows and 10 variables:
#' \describe{
#'   \item{price}{price, in US dollars}
#'   \item{carat}{weight of the diamond, in carats}
#'   ...
#' }
#' @source \url{http://www.diamondse.info/}
"xxxx"

6. internal data

yyyy <- sample(1000)
usethis::use_data(yyyy, internal = TRUE)
##' @export
printY <- function(){
  print(yyyy)
}

7. usethis::use_testthat() prepare test functions

usethis::use_testthat() ## default argument is pkg = ".", current working directory
test_that("test if f function is correct", {
    expect_equal(f(1,1), 2)
  }
)

test_that("test if f function is correct", {
    expect_equal(f(1,4), 2)
  }
)

8. devtools::test() preform test

devtools::test() ## default argument is pkg = ".", current working directory

9. usethis::use_vignette() generate vignettes

browseVignettes()
setwd(WD2)
usethis::use_vignette("Gators")
devtools::install(build_vignettes = TRUE) 

10. devtools::check() check the package

setwd(WD2)
devtools::check() ## default argument is pkg = ".", current working directory

11. devtools::build() build the package

## build the package
devtools::build() ## default argument is pkg = ".", current working directory

12. devtools::install() install the package

devtools::install() ## default argument is pkg = ".", current working directory
devtools::install(build_vignettes = TRUE) ## also build the vignettes
remove.packages("GatorPKG")
install.packages(file.path("~/Desktop","GatorPKG_0.0.0.9000.tar.gz"),repos=NULL,type="source") ## directly with vignettes

13, Package checks

system("R CMD check ~/Desktop/GatorPKG_0.0.0.9000.tar.gz")

This is equivalent to running the following in linux.

R CMD check ~/Desktop/GatorPKG_0.0.0.9000.tar.gz

14, others (internal function)

15a, others (depend on other packages)

Package: GatorPKG
Title: What the Package Does (one line, title case)
Version: 0.0.0.9000
Authors@R: person("First", "Last", email = "first.last@example.com", role = c("aut", "cre"))
Description: What the package does (one paragraph).
Depends: R (>= 3.6.0), survival
License: What license is it under?
Encoding: UTF-8
LazyData: true
RoxygenNote: 6.1.1
##' Add up two numbers (Description)
##'
##' We want to add up two numbers, blalala... (Details)
##' @title add two numbers
##' @param x first number
##' @param y second number
##' @return sum of two numbers
##' @author Caleb
##' @export
##' @examples
##' f(1,2)
f <- function(x, y){
  print(head(coxph))    
  x + y 
} 

15b, others (depend on other packages)

What if you do not want to load the entire dependent package, but only certain functions

##' Add up two numbers (Description)
##'
##' We want to add up two numbers, blalala... (Details)
##' @title add two numbers
##' @param x first number
##' @param y second number
##' @return sum of two numbers
##' @author Caleb
##' @import survival
##' @export
##' @examples
##' f(1,2)
f <- function(x, y){
  print(head(coxph))    
  x + y 
} 
devtools::document()

Your function depends on the external package, but the external package is not loaded.

16, others (R package and GitHub)

References