Making the CuteCats package
Sean Davis
2023-07-04
create_the_package.Rmd
Why an R package?
Organizing code, data, and thoughts (via documentation and vignettes) for your own analysis does not necessarily require an R package. However, you may want to share your materials, analysis, data, and functions with your future self or others. Hadley Wickham envisions an R package as the easiest way to do so.
R packages contain provenance (who wrote it, when, etc.), data, R code, documentation, tests, and really almost any other files important to the functionality of the package. Packages are installable, reusable, shareable, versioned, and extensible.
It is not about making a beautiful, perfect R package. The idea is about creating a bare-minimum R package so that you don’t have to keep thinking to yourself, “I really should just make an R package with these functions so I don’t have to keep copy/pasting them.” It isn’t all about sharing sharing your code, although it is easy to do once you have an R package. It is about saving yourself time and serving as an external brain for your code and analysis.
What is an R package?
The simplest R package is a directory with a file called
DESCRIPTION
(all caps, no suffix). In addition, a package
usually has an R
directory that contains R functions in
files. Additional, optional folders and files serve other purposes. A
data
folder allows for data of specific types of files
(csv, rda). The inst
directory will be added to the package
when it is installed; this is a good place to add supplementary files
that are needed for a package but that don’t fit in the
data
folder.
The files in a cute little PANDA package might look like:
├── DESCRIPTION
├── NAMESPACE
├── R
│ ├── cute_panda.R
│ └── eucalyptus.R
├── abc.Rproj
├── data
│ └── panda.csv
└── inst
└── ext_images
├── baby_panda.png
└── mommy_panda.png
How do I create an R package?
Step 1: Create a skeleton R package
The devtools
package contains lots of helpers for R
package development. The first function from that package we use is the
create
function:
devtools::create("CuteCats")
After executing, the CuteCats
directory will contain a
few files new files:
├── CuteCats.Rproj
├── DESCRIPTION
├── NAMESPACE
└── R
Step 2: Edit the DESCRIPTION file
The DESCRIPTION
file looks something like:
Package: CuteCats
Title: What the Package Does (One Line, Title Case)
Version: 0.0.0.9000
Authors@R:
person("First", "Last", , "first.last@example.com", role = c("aut", "cre"),
comment = c(ORCID = "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
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.2.0
Edit this file according to the short documentation. It is just a text file, so edit it in RStudio works just fine.
Step 3: Add functions
We can include functions in our package by writing them and then
saving them in the R
directory. A file can contain one or
more functions. The names of the files don’t matter much, but the file
must end with .R
.
For example, open a new R script in RStudio and create the
love_cats()
.
love_cats <- function(love = TRUE) {
if (love == TRUE) {
print("I love cats!")
return(TRUE)
} else {
print("I am not a cool person.")
return(FALSE)
}
}
For our second function, let’s take advantage of the presence of the
cute kitten that graced us with its presence during the CSHL course in
2022. This function is going to display a photo of the Hooper House
kitten. Create a new R script file in RStudio and add the
hooper_kitten
to it.
hooper_kitten <- function() {
file_loc <- system.file("images/hooper_kitten.png", package = "CuteCats")
pic <- png::readPNG(file_loc)
grid::grid.raster(pic)
}
Save the function as hooper.R
in the R
directory.
Note that this function requires two new packages, the
png
package and the grid
package. We tell R
that our package needs these two packages by adding the following to our
DESCRIPTION
file below the License
line (see
above).
Imports: png, grid
By doing so, when people install our R package, the png
and grid
packages will also be installed if needed.
Step 4: Add data and other files
Lets add our cat picture to our package. We will create a new
directory in our package called inst/images
and put our cat
picture in there, calling it hooper_kitten.png
.
dir.create("inst/images", recursive = TRUE)
And to add our cat picture:
download.file("https://github.com/seandavi/CuteCats/raw/main/inst/images/hooper_kitten.png", destfile = "inst/images/hooper_kitten.png")
Step 5: Document functions
Adding documentation to functions is really important for you, your future self, and anyone you share your functions and package with. Doing so looks intimidating at first, but once you do it a couple of times, it is pretty straightforward. The approach most people use these days is to document functions using the roxygen package.
Edit your love_cats
function file to look like:
#' Do you love cats?
#'
#' This function allows you to express your love of cats.
#'
#' @param love Do you love cats? Defaults to TRUE.
#' @keywords cats
#' @examples
#' love_cats()
#' @export
love_cats <- function(love = TRUE) {
if (love == TRUE) {
print("I love cats!")
return(TRUE)
} else {
print("I am not a cool person.")
return(FALSE)
}
}
Save this file again. Now, to get the documentation from the comments in the code above to an actual R documentation file, run:
devtools::document()
Do the same for the hooper_kitten
function:
#' Hooper Kitten picture
#'
#' Displays the cutest kitten at Cold Spring Harbor
#' @examples
#' hooper_kitten()
#' @export
hooper_kitten <- function() {
file_loc <- system.file("images/hooper_kitten.png", package = "CuteCats")
pic <- png::readPNG(file_loc)
grid::grid.raster(img)
}
Step 6: Try it out
The devtools
package includes a nice function to quickly
“load” the package without having to install it, making it convenient
and fast to make changes to the package and test them out.
devtools::load_all()
And try out the functions.
Step 8: Build a pkgdown site
BiocManager::install("pkgdown")
Then, build the site:
pkgdown::build_site()
The site will end up in the docs
directory. We will use
that information to tell GitHub where the website material is
located.
Step 9: Add everything to git
If you’ve cloned the package from git, no need to do this step. However, if you created the package from scratch, you’ll want to do this to add version control to your package.
On the terminal command line, switch into your package directory and then do:
git init
git add .
git commit -m 'Working package'