Develop your own professional R package
Marquette University
SCoRT - Summer 2025
In R, the fundamental unit of shareable code is the package.
A package bundles together:
β‘οΈ All in one place, easy to share with others.
If youβre here, you already know how to work with packages:
This workshop is about moving from using packages β‘οΈ to developing your own.
Why?
Make sure you have:
devtools: Simplifies package development by wrapping complex workflows into easy commands
roxygen2: Generates documentation from special comments in your function code
testthat: Provides a framework for unit testing and ensures your functions work correctly and safely over time
knitr: Powers dynamic report generation and vignette building that integrates code, results, and text using R Markdown
π‘ These tools help automate, test, document, and share your package like a pro.
mypkg/
βββ DESCRIPTION # Package metadata
βββ NAMESPACE # Exported functions & imports
βββ R/ # Your R functions
βββ man/ # Auto-generated documentationπ‘ Tip: Many folders in an R package are optional and included as needed.
mypkg/
βββ DESCRIPTION # Package metadata
βββ NAMESPACE # Exported functions & imports
βββ R/ # Your R functions
βββ man/ # Auto-generated documentation
βββ tests/ # Unit tests with testthat
βββ vignettes/ # Long-form documentation (Rmd)
βββ data/ # Data sets (.rda files)
βββ inst/ # Installed files (e.g., app/, extdata/)R packages transition through five development states:
Understanding these states helps you manage installation, sharing, and usage workflows.
A source package is just a folder with a specific structure:
DESCRIPTION fileR/ folder with .R filesman/, tests/, vignettes/Itβs editable and human-readable β your starting point for development.
A bundled package is a compressed .tar.gz file created from a source package.
devtools::build()It acts as a transportable unit β not directly usable until installed.
A binary package is a platform-specific compiled package:
.zip.tgzdevtools::build(binary = TRUE)Ideal for users without development tools β typically distributed by CRAN.
An installed package is one thatβs been unpacked and placed into a library folder.
install.packages()ordevtools::install_*()bring packages into this state.
An in-memory package is an installed package thatβs been loaded into the R session.
library(pkgname) to loadUse
library()to see loaded packages.
π Think of a library as a bookshelf full of packages.
Itβs common to hear people say:
βI loaded the dplyr library.β
But actually:
library(dplyr)π A library is just where packages live (a directory)
library() Inside PackagesDo not use library() or require() inside your package code
library() is for scripts and interactive sessions, not for packagesInstead, use:
@import or @importFrom in Roxygen2 commentsβ This is one of the biggest mental shifts when moving from scripts to package development
Before creating your R package, you need to choose a name.
π§ This can be the hardest part of the process!
A valid R package name must:
.)β You cannot use:
-_If you plan to share your package:
RGTK2 vs RGtk2Evocative Names:
lubridate β makes dates easierr2d3 β tools for D3 visualizationsforcats β tools for working with categorical variablesAbbreviations
Rcpp β R + C++brms β Bayesian Regression Models using StanOnce you have a name, create the package using either:
usethis::create_package("mypkg")π Both options run the same function under the hood.
R/ folder β for your function codeDESCRIPTION file β metadataNAMESPACE file β exports/importsmypkg.Rproj β RStudio project file.Rbuildignore, .gitignore β build and Git helpers
The DESCRIPTION file provides overall metadata about your package:
Imports, Suggests)Package: Rfssa
Title: Functional Singular Spectrum Analysis
Version: 3.1.0
Authors@R: c(
person("Hossein", "Haghbin", email = "haghbin@pgu.ac.ir", role = c("aut", "cre"), comment = c(ORCID = "0000-0001-8416-2354")),
person("Mehdi", "Maadooliat", email = "mehdi.maadooliat@mu.edu", role = "aut", comment = c(ORCID = "0000-0002-5408-2676"))
)
Maintainer: Hossein Haghbin <haghbin@pgu.ac.ir>
Description: Methods and tools for implementing functional singular spectrum analysis and related techniques.
License: GPL-3
Encoding: UTF-8
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.2.3
Depends: R (>= 4.0.0)Package: Rfssa
Title: Functional Singular Spectrum Analysis
Version: 3.1.0
Authors@R: c(
person("Hossein", "Haghbin", email = "haghbin@pgu.ac.ir", role = c("aut", "cre"), comment = c(ORCID = "0000-0001-8416-2354")),
person("Mehdi", "Maadooliat", email = "mehdi.maadooliat@mu.edu", role = "aut", comment = c(ORCID = "0000-0002-5408-2676"))
)
Maintainer: Hossein Haghbin <haghbin@pgu.ac.ir>
Description: Methods and tools for implementing functional singular spectrum analysis and related techniques.
License: GPL-3
Encoding: UTF-8
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.2.3
URL: https://github.com/haghbinh/Rfssa
LazyLoad: true
Imports: Rcpp,fda,lattice,plotly
LinkingTo: Rcpp, RcppArmadillo, RcppEigen,
Suggests:
knitr
Depends: R (>= 4.0.0)Title
Description
ggplot2:Title: Create Elegant Data Visualisations Using the Grammar of Graphics
Description: A system for 'declaratively' creating graphics,
based on "The Grammar of Graphics". You provide the data,
tell 'ggplot2' how to map variables to aesthetics, what
graphical primitives to use, and it takes care of the details.Imports
Suggests
Use
usethis::use_package("pkg", type = "Imports")to manage these easily.
The NAMESPACE file defines the interface of your package.
It controls:
This file is auto-generated by roxygen2, so you typically donβt edit it by hand.
# Generated by roxygen2: do not edit by hand
S3method("*", funts)
export(as.funts)
import(shiny)
importFrom(ggplot2, ggplot)export() β makes a function available to users
import() β brings in all exported objects from a package
importFrom() β imports specific functions
S3method() β registers an S3 method
In .R files:
To add functionality to your package, youβll write:
.R scripts in the R/ folderLetβs walk through the process.
All your functions go in the R/ folder.
Each .R file can contain one or more functions.
Use special comments starting with #' to write function documentation:
#' Sum of Square Function
#'
#' This function computes the Sum of Squares of a numeric vector
#'
#' @param x Numeric vector
#' @return Numeric sum of x
#'
#' @examples
#' x <- 1:5
#' y <- my_function(x)
#' print(y)
#'
my_function <- function(x) sum(x^2)This will generate help files in the man/ folder.
After writing your function and roxygen2 comments, run:
This will:
Update the NAMESPACE file
Create .Rd help files in the man/ folder
π‘ You can also press Ctrl+Shift+D in RStudio.
Use usethis to create a new package directory:
This creates:
R/, DESCRIPTION, NAMESPACE
.Rproj, .gitignore, .Rbuildignore
Opens new RStudio project for your package
Letβs include a built-in dataset (mtcars) for simplicity:
Create a new file: R/summary_stats.R
#' Compute Summary Statistics
#'
#' Returns mean and standard deviation for each numeric column.
#'
#' @param data A data frame with numeric columns
#' @return A data frame with `mean` and `sd` per column
#'
#' @examples
#' summary_stats(mtcars)
#'
#' @export
summary_stats <- function(data) {
numeric_data <- data[sapply(data, is.numeric)]
data.frame(
mean = sapply(numeric_data, mean),
sd = sapply(numeric_data, sd)
)
}Run the following command to generate docs:
This will:
Add export(summary_stats) to your NAMESPACE
Create man/summary_stats.Rd
In the console:
Build the package locally:
help("summary_stats")Questions & Discussion