library(tidyverse)
library(ggplot2)
library(dplyr)
library(plotly)
library(shiny)
library(naniar)
library(purrr)R Package Development Workflow
R-Ladies Without Borders by R-Ladies Lagos and R-Ladies Paris
Thanks to Mouna Belaid (R-Ladies Paris) and Eyitayo Alimi (R-Ladies Lagos) for inviting me and organising!
This note will be available at https://rpubs.com/emitanaka/rladies-lagos-paris-2023.
What are some of your favorite packages?
What is an R-package?
A container:
- for a set of R functions,
- to share data,
- to share an app,
- and more, e.g. Rmd templates,
Motivation
What’s the goal?
- What does your package (and functions) do?
- Who is it for?
- Why use it?
- Where do we find and install it?
- How do we use it?
💡 Idea
- Let’s make my own pipable functions to do some matrix operations.
\[M = \begin{bmatrix}1 & 2 \\3 & 4\end{bmatrix}\]
- The user interface would look like:
matrix(1:4, nrow = 2, ncol = 2, byrow = TRUE) %>%
entry_add(e(1, 1), 2) %>%
entry_subtract(e(2, 2), 3) %>%
entry_multiply_by(e(1, 2), 4) %>%
entry_divide_by(e(2, 1), 5)\[\begin{bmatrix}1 + 2 & 2 \times 4 \\3/5 & 4 - 3\end{bmatrix} = \begin{bmatrix}3 & 8 \\0.6 & 1\end{bmatrix}\]
Functions
entry_add <- function(M, entry, x) {
M[entry[1], entry[2]] <- M[entry[1], entry[2]] + x
M
}
entry_subtract <- function(M, entry, x) {
M[entry[1], entry[2]] <- M[entry[1], entry[2]] - x
M
}
entry_multiply_by <- function(M, entry, x) {
M[entry[1], entry[2]] <- M[entry[1], entry[2]] * x
M
}
entry_divide_by <- function(M, entry, x) {
M[entry[1], entry[2]] <- M[entry[1], entry[2]] / x
M
}
e <- function(i, j) {
if(i < 0) stop("Row entry is not a positive integer.")
if(j < 0) stop("Column entry is not a positive integer.")
c(i, j)
}R-package development helper packages
devtoolsusethisroxygen2pkgdowntestthat
install.packages(c("devtools", "usethis", "roxygen2", "pkgdown", "testthat"))Anatomy of an R-package
DESCRIPTIONfileR/directory for R files that contain your functionsNAMESPACEfile (you don’t need to manually create this)
Optionally,
data/for binary data available to the userdata-raw/for raw datainst/for arbitrary additional files that you want include in your package- and so on.
DESCRIPTION file
- Metadata for the package
- Package name
- Title and description
- Authors
- Dependencies (depends, imports, suggests)
- Licensing
- Version number
- Bug report location, and so on.
Creating an R-package
available::available("matrixops") # check if package is available
usethis::create_package("matrixops")
usethis::use_r("new-r-file") # creating new R file in the R/ directory
# add R functions to the R file
devtools::load_all()Documenting R functions with roxygen2
use
#'above a function to write documentation for that functionroxygen2uses@tags to structure documentation, e.g.- any text after
@descriptionis the description - any text after
@paramdescribes the arguments of the function @exportsignals that it is an exported function- any text after
@returndescribes the return object
- any text after
The full list of Rd tags are found at https://roxygen2.r-lib.org/articles/rd.html
Then
devtools::document()converts the Rd tags to appropriate sections of.Rdfiles written in theman/folder
devtools::document()Unit testing with testthat
usethis::use_test()- This creates a file
test-active-filename.Rintests/testthat/directory
test_that("operations works", {
M <- matrix(1:4, nrow = 2, ncol = 2, byrow = TRUE)
expect_equal(entry_add(M, e(1, 1), 2),
matrix(c(3, 2, 3, 4), 2, 2, byrow = TRUE))
})devtools::test_active_file()
devtools::test()Master the keyboard shortcuts
- Cmd/Ctrl + Shift + L: Load all
- Cmd/Ctrl + Shift + D: Document
- Cmd/Ctrl + Shift + T: Test
- Cmd/Ctrl + Shift + B: Build and Reload
- plus more… see RStudio IDE > Tools > Keyboard Shortcuts Help
Whole R package development workflow
available::available("pkgname") # check if package name is available (if planning to publish publicly)
usethis::create_package("pkgname")
usethis::use_git() # set up version control
usethis::use_github() # optional
usethis::use_r("myfile")
# write some functions in a script
usethis::use_data_raw() # if adding data
devtools::load_all() # try it out in the console
usethis::use_package("import-pkgname") # add package to import (or depends or suggests)
usethis::use_package_doc() # add package documentation
usethis::use_pipe() # if you want to add %>% from `magrittr`
usethis::use_vignette("vignette-name") # add vignette
usethis::use_test() # make test file for active R file
# write some test
devtools::test_active_file() # test active file
devtools::test() # test whole package
devtools::build() # build vignettes
devtools::install() # to install package
devtools::check() # to build and check a package
usethis::use_readme_rmd() # to add a README Rmd file
styler::style_pkg() # optional (commit first, then review changes carefully)
usethis::use_pkgdown_github_pages() # for setting up pkgdown website on github
# `usethis::use_pkgdown()` if not using github pagesUseful reference
- R Packages book (2e) https://r-pkgs.org/