Tutorial Source Code: github.com/fabarca/r-package-tutorial

Main Reference (Online Book): R Packages - by Hadley Wickham

Cheat Sheet (PDF): Package Development


Index

  1. Basic Commands
  2. Introduction
  3. Requirements
  4. Package Creation
  5. Adding Functions
  6. Documentation
  7. Installation
  8. Usage Example
  9. Testing
  10. Vignettes

Basic Commands

Return to index ↑

This is a cheat sheet for creating packages in R. These commands will be explained along this tutorial.

# The first argument of usethis::create_package() must be the path to the new package

# Create package structure
usethis::create_package("PackageName")
# Add some functions inside R/ folder, 
# then create documentation and NAMESPACE file
devtools::document()
# Now you can install your packages
devtools::install()

# Create test folder
usethis::use_testthat()
# Add some tests inside tests/testthat/,
# then perform your tests
devtools::test()

# Add a vignette template and dependencies
usethis::use_vignette("vignette-name")
# Install including vignettes
devtools::install(build_vignettes = TRUE)

Introduction

Return to index ↑

The aim of this tutorial is to provide a quick start guide to R users interested in creating packages by learning only the essentials. The user is expected to already know how to code in R.

For more details about package creation, please refer to the main reference link.

This Tutorial was written using Rmarkdown, and while it is compiled, it actually creates the R package called ‘firstPkg’. Both, the Rmarkdown file ‘index.Rmd’ and the R package ‘firstPkg’, are available in github.com/fabarca/r-package-tutorial.


Requirements

Return to index ↑

These are the packages that you need to install to get started:

install.packages(c("devtools", "roxygen2", "testthat", "knitr", "rmarkdown"))

To have the last version of devtools you may use:

devtools::install_github("hadley/devtools")

Package Creation

Return to index ↑

First, create a new package folder named firstPkg by using:

usethis::create_package("firstPkg")
## Package: firstPkg
## Title: What the Package Does (One Line, Title Case)
## Version: 0.0.0.9000
## Authors@R (parsed):
##     * First Last <first.last@example.com> [aut, cre] (<https://orcid.org/YOUR-ORCID-ID>)
## Description: What the package does (one paragraph).
## License: `use_mit_license()`, `use_gpl3_license()` or friends to pick a
##     license
## Encoding: UTF-8
## LazyData: true
## Roxygen: list(markdown = TRUE)
## RoxygenNote: 7.1.1

If you are using Rstudio, the new package project should be opened automatically. Among the files created, will be the DESCRIPTION file, that you can edit with your own information.


Adding Functions

Return to index ↑

This is the basic R package structure:

## DESCRIPTION
## NAMESPACE
## R/

The folder R/ is empty at this moment, all your functions should be placed there.
For example, you can create a script file called groupByDate.R with following code inside:

#' Group Dataframe By Date
#'
#' Return the mean value grouped by date.
#' @param data_frame A data.frame object with two columns: date and value.
#' @return Return a tibble data.frame.
#' @seealso \code{\link{group_by}}, \code{\link{summarise}}
#' @export
#' @importFrom dplyr group_by summarise n %>%
groupByDate <- function(data_frame){
  dplyr::group_by(data_frame, date) %>% dplyr::summarise(mean = mean(value), count = dplyr::n())
}

Documentation

Return to index ↑

All comments starting by #' are the metadata used by roxygen2 package to automatically create the documentation files (inside the folder man/) and fill the NAMESPACE file.
Before the function definition, you need to add #' @export , in order to make the function available in the NAMESPACE file. This will make the function publicly available, otherwise it would be only accesible from functions within the package.
In this example, you will need to use some functions from a external package. To do that, add a comment like this #' @importFrom other_package function1 function2.

To create documentation based on roxygen2 comments, run the following command:

devtools::document()

## Updating firstPkg documentation
## Loading firstPkg
## Writing NAMESPACE
## Writing groupByDate.Rd
## Documentation completed

Now your package folder should look like this:

## DESCRIPTION
## man/
## man/groupByDate.Rd
## NAMESPACE
## R/
## R/groupByDate.R

Remember to add the external libraries that you need to import in the DESCRIPTION file. In this case you should add this line: Imports: dplyr


Installation

Return to index ↑

To install this package run:

devtools::install()

Now you can check the documentation page of your function using:

?groupByDate

Usage Example

Return to index ↑

Here is an example code to try the new function:

library(firstPkg)
set.seed(1)

# Create a dataframe
date_vec = rep(as.Date('2017-01-01') + 0:8, 4)
value_vec = sample(1:36 * 4, 36)
example_df = data.frame(date = date_vec, value = value_vec)

# Group the dataframe using the new function
firstPkg::groupByDate(example_df)
## # A tibble: 9 x 3
##   date        mean count
##   <date>     <dbl> <int>
## 1 2017-01-01    84     4
## 2 2017-01-02    63     4
## 3 2017-01-03   108     4
## 4 2017-01-04    78     4
## 5 2017-01-05    74     4
## 6 2017-01-06    65     4
## 7 2017-01-07    87     4
## 8 2017-01-08    48     4
## 9 2017-01-09    59     4

Testing

Return to index ↑

To create a test folder using testthat package run:

usethis::use_testthat()

Here you can see the new folders:

## DESCRIPTION
## man/
## man/groupByDate.Rd
## NAMESPACE
## R/
## R/groupByDate.R
## tests/
## tests/testthat.R
## tests/testthat/

Tests must go inside tests/testthat/ folder with the prefix test. For example, you can create a new test script called test_groupByDate.R, with the following code inside:

library(firstPkg)

date_vec = rep(as.Date('2017-01-01') + 0:8, 4)
value_vec = sample(1:36*4, 36)
example_df = data.frame(date = date_vec, value = value_vec)

test_that("Date is well grouped", {
  result_df = firstPkg::groupByDate(example_df)
  
  expect_equal(result_df$date, as.Date('2017-01-01') + 0:8)
  expect_equal(sum(result_df$count), length(date_vec))
})

test_that("Mean is well calculated", {
  result_df = firstPkg::groupByDate(example_df)
  
  expect_equal(mean(result_df$mean), mean(value_vec))
})

To perform the tests run:

devtools::test()
## ✓ |  OK F W S | Context
## 
⠏ |   0       | groupByDate                                                     
✓ |   3       | groupByDate
## 
## ══ Results ═════════════════════════════════════════════════════════════════════
## [ FAIL 0 | WARN 0 | SKIP 0 | PASS 3 ]

This is the current directory structure, where almost everything was created automatically. You only had to manually add the R/groupByDate.R and tests/testthat/test_groupByDate.R files, and edit the DESCRIPTION file.

## DESCRIPTION
## man/
## man/groupByDate.Rd
## NAMESPACE
## R/
## R/groupByDate.R
## tests/
## tests/testthat.R
## tests/testthat/
## tests/testthat/test_groupByDate.R

Vignettes

Return to index ↑

You may also wish to include a vignette in your package. But first, you should have installed “pandoc” software: How to Install Pandoc

If you are using Ubuntu you can try: sudo apt-get install pandoc

Once the requirements are met. You can create a new vignette called firstPkg_intro running:

usethis::use_vignette("firstPkg_intro")

This command creates a template file called firstPkg_intro.Rmd inside vignettes/ folder. It also automatically adds the dependencies in the DESCRIPTION file.

## DESCRIPTION
## man/
## man/groupByDate.Rd
## NAMESPACE
## R/
## R/groupByDate.R
## tests/
## tests/testthat.R
## tests/testthat/
## tests/testthat/test_groupByDate.R
## vignettes/
## vignettes/firstPkg_intro.Rmd

Now you can edit this template with your own code, for example:

---
title: "firstPkg_intro"
author: "Vignette Author"
date: "`r Sys.Date()`"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{firstPkg_intro}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)
```

Here there is an example code for the function groupByDate:

```{r example}
library(firstPkg)
set.seed(1)

date_vec = sample(as.Date('2017-01-01') + 0:6, size = 36, replace = TRUE)
value_vec = as.integer(rnorm(36, mean = 20, sd = 5))

example_df = data.frame(date = date_vec, value = value_vec)

head(example_df)

firstPkg::groupByDate(example_df)
```

To install the package including vignettes run:

devtools::install(build_vignettes = TRUE)

To open the vignette use:

vignette('firstPkg_intro')

Additional references:

Rmarkdown Cheat Sheet: rmarkdown-2.0.pdf

Rmarkdown Reference: rmarkdown-reference.pdf