πŸ“¦
You can make an R package too!

Emma Rand

Summary

  • Why make a package?
  • Where packages come from and where do they live?
  • Package States
  • How to make a minimal documented package and check it using the devtools(Wickham et al. 2022) approach
  • Components of a minimal package

Prerequisites

You should have

  • R and RStudio
  • R build toolchain: Rtools(windows) or XCode (mac) or r-base-dev
  • devtools and assertthat

Learning Objectives

By the end of this session you will able to:

Why make a package?

Why make a package?

Conventionally:

  • Package developers
  • Generalisable analytical methods
  • For use on other data
  • Public release

Why make a package?

But you can also make a package just for your own use! Or just for a data analysis project!

  • You don’t need to have a collection of highly generalisable functions
  • You don’t need to share it with anyone else
  • If you are already trying to work reproducibly you are almost doing it anyway!
  • But it will help you do it better

Why make a package?

If you are already trying to work reproducibly you are almost doing it anyway!

/stem-cell-proteomic
   /data-raw
   /data-processed
   /figures
   /R
   README.md
   report.Rmd
   stem-cell-proteomic.RProj

… making a package is just a short step beyond that

Be nice to future you

Person working at a computer with an offstage person asking "How is the analysis going?" The person at the computer replies "Can't understand the data...and the data collector does not answer my emails or calls" Person offstage: "That's terrible! So cruel! Who did collect the data? I will sack them!" Person at the computer: "um...I did, 3 years ago"

Future self: CC-BY-NC, by Julen Colomb, derived from Randall Munroe cartoon

To avoid

via GIPHY

Where packages come from and live?

Where do R packages come from?

CRAN:

install.packages("praise")

GitHub:

remotes::install_github("rladies/praise")

Bioconductor

BiocManager::install("celaref")

Where do packages live?

In a library! In

.libPaths()
[1] "C:/Users/er13/AppData/Local/R/win-library/4.5"
[2] "C:/Program Files/R/R-4.5.2/library"           
  • A library is a folder

  • Base packages live in C:/Program Files/R/R-4.5.2/library

Package states

Package states

There are five states a package can be in:

  • source

  • bundled

  • binary

  • installed

  • in-memory

Package states

  • source

  • bundled

  • binary

  • installed

  • in-memory

What you write.

Specific directory structure and components e.g., DESCRIPTION, an R/ directory.

Package states

  • source

  • bundled

  • binary

  • installed

  • in-memory

Package files compressed to single file.

Conventionally .tar.gz

Package states

  • source

  • bundled

  • binary

  • installed

  • in-memory

Standard package distribution

Platform specific: .tgz (Mac) .zip (Windows)

Package developers submit a bundle to CRAN; CRAN makes and distributes binaries

install.packages()

Package states

  • source

  • bundled

  • binary

  • installed

  • in-memory

A binary package that’s been decompressed into a package library

Package states

  • source

  • bundled

  • binary

  • installed

  • in-memory

If a package is installed, library() makes its functions available by loading the package into memory and attaching it to the search path.

Not used when making a package; devtools::load_all() instead.

Create a package!

Create a package

Be deliberate about where you create your package

Do not nest inside another RStudio project, R package or git repo.

🎬 Create a package:

usethis::create_package("mypackage")

√ Creating 'C:/Users/er13/Desktop/mypackage/'
√ Setting active project to 'C:/Users/er13/Desktop/mypackage'
√ Creating 'R/'
√ Writing 'DESCRIPTION'
Package: mypackage
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\] (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
√ Writing 'NAMESPACE'
√ Writing 'mypackage.Rproj'
√ Adding '.Rproj.user' to '.gitignore'
√ Adding '\^mypackage\\\\.Rproj\$', '\^\\\\.Rproj\\\\.user\$' to '.Rbuildignore'
√ Opening 'C:/Users/er13/Desktop/mypackage/' in new RStudio session
√ Setting active project to '\<no active project\>'

create_package()

What happens when we run create_package()?

  • R will create a folder called mypackage which is a package and an RStudio project

  • restart R in the new project

  • create some infrastructure for your package

  • start the RStudio Build pane

create_package()

What happens when we run create_package()?

  • mypackage.Rproj makes this directory an RStudio Project.

  • DESCRIPTION provides metadata about your package.

  • The R/ directory for .R files with function definitions.

  • NAMESPACE declares the functions your package exports and the functions it imports from other packages.

create_package()

What happens when we run create_package()?

  • .Rbuildignore lists files that we need but that should not be included when building the R package from source.

  • .gitignore anticipates Git usage and ignores some standard, behind-the-scenes files created by R and RStudio.

Add a function

Functions will go in an .R file.

There’s a usethis helper for adding .R files!

usethis::use_r("file_name")

usethis::use_r() adds the file extension and saves in R/ folder

usethis::use_r()

🎬 Create a new R file in your package called animal_sounds.R

usethis::use_r("animal_sounds")
√ Setting active project to 'C:/Users/er13/Desktop/mypackage'
β€’ Modify 'R/animal_sounds.R'

Add the function

🎬 Put the following code into your script:

animal_sounds <- function(animal, sound) {
  assertthat::assert_that(
    assertthat::is.string(animal),
    assertthat::is.string(sound)
  )
  paste0("The ", animal, " goes ", sound, "!")
}

Test your function

Development workflow

In a normal script you might use:

source("R/animal_sounds.R")

but when building packages we use a devtools approach

Development workflow

there are three boxes with arrow joining them clockwise. The boxes are (clockwise from 3' oclock) 'devtools::load_all() Cmd/Ctrl + Shift +L', 'Explore in console' and 'Modify code'

Development workflow

Load your package

devtools::load_all()

🎬 Load package with devtools::load_all().

devtools::load_all()
Loading mypackage

Test

Test the animal_sounds() function in the console.

animal_sounds("dog", "woof")
[1] "The dog goes woof!"

devtools::load_all()

🎬 Change some tiny thing about your function - maybe the animal β€œsays” instead of β€œgoes”?

🎬 Load with devtools::load_all() and test the updated function.

Check your package

Check your package

R CMD check is the gold standard for checking that an R package is in full working order.

It is a programme that is executed in the shell.

However, devtools has the check() function to allow you to run this without leaving your R session.

devtools::check()

🎬 Check your package

devtools::check()

devtools::check()

You will get lots of output ending with:

── R CMD check results ───────────────────────────────────── mypackage 0.0.0.9000 ────
Duration: 19.5s

❯ checking dependencies in R code ... WARNING
  '::' or ':::' import not declared from: 'assertthat'

❯ checking DESCRIPTION meta-information ... NOTE
  Invalid licence file pointers: LICENSE

0 errors βœ” | 1 warning βœ– | 1 note βœ–

License

Add a license

usethis helps out again! use_mit_license(), use_agpl_license(), use_ccby_license() etc

🎬 Add a MIT license1 - use your own name!

usethis::use_mit_license("Emma Rand") 

🎬 What files have appeared?

🎬 How has the DESCRIPTION file changed?

🎬 Run devtools::check() again. Has one of the warnings disappeared?

Document your package

Levels of package documentation

  • Metadata: The DESCRIPTION file – an overview of β€œwhat’s in this package?”

  • Object documentation: Documentation for each of the exported functions and datasets in the package, along with examples of usage

  • Vignettes: Long form documentation, generally discussing how to use a number of functions from the - package together and/or how a package fits into a larger ecosystem of packages

  • pkgdown sites: Websites for your package!

Metadata in DESCRIPTION

  • Title: One line, title case, with no period. Fewer than 65 characters.

  • Version

    • for release: MAJOR.MINOR.PATCH version.
    • for development version building on version MAJOR.MINOR.PATCH, use: MAJOR.MINOR.PATCH.9000
  • Authors@R: β€œaut” means author, β€œcre” means creator, β€œctb” means contributor.

  • Description: One paragraph describing what the package does. Keep the width of the paragraph to 80 characters; indent subsequent lines with 4 spaces.

  • License

  • Encoding: How to encode text, use UTF-8 encoding.

  • LazyData: Use true to lazy-load data sets in the package.

Update DESCRIPTION

🎬 Add a title and description.

🎬 Add yourself as an author and creator.

Object documentation

Object documentation is what you see when you use ? or help() to find out more about a function or a dataset in a package.

Created by adding β€œRoxygen comments” to the function (\#')

Much of the work is done by the roxygen2 package called by β€˜devtools’

Object documentation workflow

  • Add roxygen comments to your .R files.

  • Run devtools::document() to convert roxygen comments to .Rd files.

  • Load the current version of the package with devtools::load_all()

  • Preview documentation with ?

  • Rinse and repeat until the documentation looks the way you want.

Document your function

🎬 Open animal_sounds.R

🎬 Go to Code > Insert Roxygen Documentation

🎬 Fill in the documentation: Title, a brief description, define the two parameters, and finally, describe what the function returns

🎬 Save animal_sounds.R, run devtools::document() followed by devtools::load_all()

🎬 Preview the documentation with ?animal_sounds and edit your documentation if anything needs to be changed

Add examples

🎬 Under @examples, add one example for using your function

🎬 Save animal_sounds.R, run devtools::document() followed by devtools::load_all()

🎬 Preview the documentation with ?animal_sounds and edit your documentation if anything needs to be changed

Package dependencies

Remember this?

-- R CMD check results -------------------- mypackage 0.0.0.9000 ----
  Duration: 12.5s

> checking dependencies in R code ... WARNING
  '::' or ':::' import not declared from: 'assertthat'
0 errors √ | 1 warnings x | 0 notes √
  • We have used a function from the assertthat package in a function in our package

  • But we haven’t declared that officially, we need to do that

Types of dependency

  • Imports: must be installed for your package to work.
  • Suggests: used but not required for your package. e.g., datasets, for tests or vignettes, or limited use.
  • Depends: Avoid where possible, but you might use it to require a specific version of R, e.g. Depends: R (>= 3.4.0).

Package Imports

usethis::use_package() is there for us again! It defaults to imports1

🎬 Use usethis::use_package() to add the assertthat package to Imports

usethis::use_package("assertthat") # Defaults to imports
#> βœ“ Adding 'assertthat' to Imports field in DESCRIPTION
#> β€’ Refer to functions with `assertthat::fun()`

Package Imports

🎬 How your DESCRIPTION file changed?

🎬 Run devtools::check() again. Has the warning disappeared?

πŸ“¦ Woo hooπŸ“¦
You made a package!

Licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License. Creative Commons License

Summary

  • It is useful to make a package
    • it is fairly easy with devtools
    • it will help you work more reproducibly
    • you don’t have to share
  • Packages can be in one of 5 states:
    • source - what you write
    • bundled - source compressed to single file, submitted to CRAN
    • binary - distribution for users w/o devtools
    • installed - a binary that’s been decompressed
    • in-memory - installed package that has been loaded

Summary continued

References

Rand, Emma. 2021. β€œData Science for Modern and Open Research: You Can Make an r Package Too!” November. https://doi.org/10.5281/zenodo.5714290.
Rand, Emma, and Mine Cetinkaya-Rundel. 2021. β€œWorkshops/Package-Dev-Modules at Master Β· Forwards/Workshops.” https://github.com/forwards/workshops.
Wickham, Hadley, and Jenny Bryan. 2022. R Packages. 2nd edition. Online. https://r-pkgs.org/index.html.
Wickham, Hadley, Jim Hester, Winston Chang, and Jennifer Bryan. 2022. Devtools: Tools to Make Developing r Packages Easier. https://CRAN.R-project.org/package=devtools.