Skip to content

Get Ready

Installing R packages and structuring your scripts before you start analysing.

Up to this point, you were dealing with a large dataset, millions of reads, and needed real computing power to process them. From here on, that's done: you're handling a single table. For this stage, we recommend R together with RStudio, plus a handful of packages from a few different repositories. So, let's get ready to Rrrrrr.

Installing and Loading R Packages

Repositories

  • CRAN, the official R repository
  • Bioconductor, a topic-specific repository for genomics and bioinformatics packages
  • GitHub, the most popular repository for open-source projects generally, not R-specific

Bioconductor Packages Are Versioned Together

Bioconductor releases its packages in coordinated batches tied to a specific Bioconductor (and R) version. Installing through BiocManager ensures compatible versions of packages such as phyloseq, Biostrings, ShortRead, and DESeq2.

A package only needs to be installed once per R installation, but it must be loaded with library() every time you start a new R session. Installing and loading are separate steps, and forgetting the second one is one of the most common reasons newcomers see "could not find function...".

Package Installation

The installation command depends on the repository:

### CRAN
install.packages("package")
install.packages(c("packageA", "packageB"))

### Bioconductor
if (!requireNamespace("BiocManager", quietly = TRUE))
    install.packages("BiocManager")
BiocManager::install("package")

### GitHub
install.packages("devtools")
devtools::install_github("link/to/package")

biocLite() Is Gone

Older tutorials mention source("https://bioconductor.org/biocLite.R") and biocLite("package"). Don't use this. Bioconductor retired biocLite() in 2019 in favour of BiocManager, shown above, and the old install script no longer does anything useful. If you see biocLite() in a script, including an old one of your own, replace it with BiocManager::install().

pak as a Faster Alternative to devtools

devtools::install_github() above works fine and is still widely used, but pak (pak::pak("link/to/package")) is a newer alternative that's generally faster and more reliable about resolving dependencies, and increasingly the default recommendation for installing from GitHub. Either is a reasonable choice; if you're starting fresh, we'd lean towards pak.

Package Info

It's always a good idea to look at the basic information about a package, ideally before installing it, and certainly after:

packageDescription("package")
help(package = "package")

The package::function() Notation

You'll often see code written as dplyr::filter(...) instead of library(dplyr) followed by plain filter(...). The :: explicitly tells R which package a function comes from, without loading (attaching) the whole package first. It's especially useful when two loaded packages both have a function with the same name, and it makes a script more self-documenting, since you can tell where every function comes from without checking the top of the file for library() calls.

Manage Packages

# List all installed packages
installed.packages()
# Get a package's version
packageVersion("fun")
# Update one specific package (the first argument is a library path, not a package name!)
update.packages(oldPkgs = "fun")
# Update everything that's outdated
update.packages()
# Load a package
library("fun")
# Unload a package
detach("package:fun", unload = TRUE)
# Remove a package
remove.packages("fun")

update.packages() Doesn't Take a Package Name as Its First Argument

update.packages("fun") doesn't do what it looks like: the first positional argument is lib.loc, a library path, not a package name. Use the named argument oldPkgs = "fun" to target one package, or just update.packages() on its own to update everything that's out of date.

Example(s)

## Alternative ways to get the same package
# Install dplyr by installing the whole tidyverse (a collection of data science tools):
install.packages("tidyverse")
library(tidyverse)
# Or install just dplyr:
install.packages("dplyr")
# Or the development version from GitHub:
install.packages("pak")
pak::pak("tidyverse/dplyr")

## Load multiple CRAN packages, installing any that are missing
package.list <- c("ggplot2", "RColorBrewer", "ggpubr")
invisible(lapply(
  package.list,
  FUN = function(x) {
    if (!requireNamespace(x, quietly = TRUE)) {
      install.packages(x, dependencies = TRUE)
    }
    library(x, character.only = TRUE)
  }
))

There's a Package for This Pattern Too

The install-if-missing-then-load pattern above is common enough that a couple of packages exist just to do it in one line: pacman::p_load(ggplot2, RColorBrewer, ggpubr) or librarian::shelf(ggplot2, RColorBrewer, ggpubr) both install whatever's missing and load the rest, with less code to get wrong. Worth it if you find yourself writing this loop often; not essential if you're happy with the explicit version above.

Writing Reproducible Scripts

A few habits, at the start, throughout, and at the end of a script, make it much more likely that the script still works next month, or on someone else's machine.

Use an RStudio Project

Before creating any scripts, create an RStudio Project for your analysis (File > New Project). This keeps all your files together, sets your working directory automatically whenever you open the project, and avoids most of the "cannot open file" errors that come from hardcoded or inconsistent file paths. It's a small step that prevents more beginner problems than almost anything else on this page.

Start Clean

Before starting a new piece of work, make sure your workspace (environment) is clean. There should be no leftovers from a previous session that could interfere with your current work. RStudio has a broom icon in the Environment pane for this, and in a script you can use rm():

## Clear objects from the environment
rm(list = ls())

This Isn't a Full Reset

rm(list = ls()) clears your objects, but it doesn't detach loaded packages, reset options(), or change your working directory. Anything your script accidentally depends on from those, a package loaded earlier in the session, an option changed somewhere else, will still be there and can make a script that secretly doesn't stand on its own look like it works. If you want a genuinely clean slate, actually restart the R session (in RStudio: Session > Restart R) rather than relying on rm(list = ls()) alone. Use rm(list = ls()) as a quick tidy-up during a working session, and a full restart before you do a final check that your script runs top to bottom on its own.

Log Your Session

Not all users work with the same package versions or extensions. This can lead to conflicts when exchanging R scripts. For this reason, summarise your settings in a log file at the end of your script and include it alongside the script. This information also matters for troubleshooting.

## Version 1: session log
writeLines(capture.output(sessionInfo()), "SessionInfo.txt")
## Version 2: session log
sink("SessionInfo.txt")
  print(sessionInfo())
sink()

sessionInfo() Needs print() Here

A bare sessionInfo() on its own line only auto-prints when typed directly at an interactive prompt. Inside a script run with source(), RStudio's "Source on Save", or Rscript, a top-level expression like that produces no visible output at all, so sink() captures nothing and you're left with an empty SessionInfo.txt, with no error to warn you. Wrapping it in print(), as above, makes the output explicit regardless of how the script is run. This is also, generally, a reason to prefer Version 1 (capture.output) over sink(): it doesn't depend on auto-print behaviour at all, and it's harder to leave a sink open by accident and silently redirect all your later console output into a file.

For longer-term reproducibility across an entire project, rather than a single script's session log, consider renv, which records the exact package versions your project depends on in a lockfile, so they can be restored later or on a different machine.

Code with Style

Save/Load Workspace

# Store your workspace
save.image(file = "myworkspace.RData")
# Restore or load a workspace
load("myworkspace.RData")

Prefer Rebuilding From Raw Data Over Loading a Saved Workspace

Saving and loading a workspace can be handy while you're actively exploring data interactively, picking up where you left off without rerunning everything. But an analysis you actually want to be reproducible should generally start from the raw input files and rerun the full script, not load a previously saved .RData workspace. A saved workspace can silently carry over objects, variables, or intermediate results that no longer match what your current script would actually produce, creating a hidden dependency on a specific saved state, rather than on your code. If you save a workspace, treat it as a convenience checkpoint during exploration, not as part of your final, shareable analysis.