01/11/2021

Why should you make your own R packages?

  • Keep track of the miscellaneous R functions that you write and reuse.
  • Easiest way to distribute R code and associated data.
  • Assembling a few R functions within a package will make it way easier for you to use them regularly.

As Hillary Parker says in Writing an R package from scratch:

“Seriously, it doesn’t have to be about sharing your code (although that is an added benefit!). It is about saving yourself time.”

Anatomy of an R package

  • Metadata via the DESCRIPTION file, including the name of the package, description of the package, the version of the package, and any package dependencies.

  • Source code via .R files, that live in the R/ directory.

  • Special roxygen comments inside the .R files that describe how the function operates and its arguments, dependencies, and other metadata.

  • The NAMESPACE for the exported functions you have written, and the imported functions you bring in.

  • Tests that confirm your function “works as intended”.

  • Other things (installed files, compiled codem data, tutorials, vignettes).

From Building R packages with devtools and usethis by Tom Mock.

Making your first R package

Let’s turn these temperature conversion functions into an R package.

fahr_to_celsius <- function(temp_F) {
  # Converts Fahrenheit to Celsius
  temp_C <- (temp_F - 32) * 5 / 9
  return(temp_C)
}

celsius_to_kelvin <- function(temp_C) {
  # Converts Celsius to Kelvin
  temp_K <- temp_C + 273.15
  return(temp_K)
}
fahr_to_kelvin <- function(temp_F) {
  # Converts Fahrenheit to Kelvin using fahr_to_celsius() and celsius_to_kelvin()
  temp_C <- fahr_to_celsius(temp_F)
  temp_K <- celsius_to_kelvin(temp_C)
  return(temp_K)
}

Step 0: Packages you will need

We will use the devtools, usethis and roxygen2 packages, which make creating packages in R relatively simple.

library("usethis")
## Warning: package 'usethis' was built under R version 4.0.5
library("devtools")
## Warning: package 'devtools' was built under R version 4.0.5
library("roxygen2")
## Warning: package 'roxygen2' was built under R version 4.0.5

These can be installed from CRAN like this:

# installation can be combined
install.packages(c("usethis","devtools","roxygen2"))  

Step 1: Create your package directory

Set your working directory, and then use the create_package() to make a framework for your package.

# Keep the name simple and unique: 
usethis::create_package("tempConvert")

Alternatively,

Step 2: Add functions

Add your functions to the R directory. Place each function into a separate R script:

fahr_to_celsius <- function(temp_F) {
  temp_C <- (temp_F - 32) * 5 / 9
  return(temp_C)
}

Alternatively usethis::use_r("fahr_to_celsius.R"). This will create a minimal function .R file and open it for interactive editing. We can copy our fahr_to celsius function over and add it to this file.

Step 3: Add documentation

The way it works is that you add special comments to the beginning of each function, that will later be compiled into the correct format for package documentation. For example:

#' Converts Fahrenheit to Celsius
#'
#' This function converts input temperatures in Fahrenheit to Celsius.
#' @param temp_F The temperature in Fahrenheit.
#' @return The temperature in Celsius.
#' @export
#' @examples
#' fahr_to_celsius(32)

fahr_to_celsius <- function(temp_F) {
  temp_C <- (temp_F - 32) * 5 / 9
  return(temp_C)
}

Step 4: Process your documentation

Now you need to create the documentation from your annotations earlier.

The roxygen2 package reads lines that begin with #' as comments to create the documentation for your package. Descriptive tags are preceded with the @ symbol. For example, @param has information about the input parameters for the function. Now, we will use roxygen2 to convert our documentation to the standard R format.

devtools::document()

This automatically adds in the .Rd files to the man directory, and adds a NAMESPACE file to the main directory.

Package directory

Take a look at the package directory now. The /man directory has a .Rd file for each .R file with properly formatted documentation.

Overall, your package directory should look something like this:

Step 5: Install package

Run this from the parent working directory that contains the tempConvert folder.

devtools::install("tempConvert")

Load package

Let’s load the package and take a look at the documentation.

library(tempConvert)

Notice there is now a tempConvert environment that is the parent environment to the global environment.

Now that our package is loaded, let’s try out some of the functions.

fahr_to_celsius(32)
## [1] 0

Try typing ?fahr_to_celsius

Exercises

Why a package instead of source()?

source()-ing:

  • can be tied to a specific package version
  • testing not included
  • documentation not included
  • requires .R file to be copied in every project that can be modified or deleted (accidentally) by the end-user.

Further reading