R Intermediate Course 2026

R is a Lego Construction Set

Bioinformatics Core Facility CECAD

2026-09-11

Slides & Code

  • [f] Full screen
  • [o] Slide Overview
  • [c] Notes
  • [h] help

git repo

R-Basic


Clone repo

git clone https://github.com/CECADBioinformaticsCoreFacility/Intermediate_R_Course_2026.git


Slides Directly

https://cecadbioinformaticscorefacility.github.io/Intermediate_R_Course_2025/

Session 1 :: R is a Lego Construction Set

R is a Lego Construction Set

R is a Lego Construction Set

R is a Lego Construction Set

R is a Lego Construction Set

R is a Lego Construction Set

R is a Lego Construction Set

R is a Lego Construction Set

R is a Lego Construction Set

R is a Lego Construction Set

One Time Code – Experimenting With Message Encryption

msg <- "This is a top-secret message!"

pool <- LETTERS

msg_chars <- strsplit(msg,"")[[1]]

u <- unique(msg_chars)

encrypt_chars <- 
  sample(pool,
         size = length(u),
                        
         # no two message characters must map
         # to the same encryption character
         replace = FALSE 
                                         
  )

encrypt_chars <- 
  setNames(encrypt_chars, # vector to name
           u              # vector of names
  )
# print the set of characters used for encryption
encrypt_chars
  T   h   i   s       a   t   o   p   -   e   c   r   m   g   ! 
"W" "V" "X" "J" "H" "C" "S" "G" "O" "T" "E" "L" "B" "M" "K" "D" 
# print the encrypted message characters 
encrypt_chars[msg_chars] 
  T   h   i   s       i   s       a       t   o   p   -   s   e   c   r   e   t 
"W" "V" "X" "J" "H" "X" "J" "H" "C" "H" "S" "G" "O" "T" "J" "E" "L" "B" "E" "S" 
      m   e   s   s   a   g   e   ! 
"H" "M" "E" "J" "J" "C" "K" "E" "D" 
# collapse the encrypted message characters
# back into a string
encrypted_msg <- 
  paste(encrypt_chars[msg_chars], collapse="")

# print it:
encrypted_msg
[1] "WVXJHXJHCHSGOTJELBESHMEJJCKED"

One Time Code – Experimenting With Message Encryption

 

This code contains fixed values:  
What if we want to change them?

Copy and edit? Sounds messy …

Functions – Making Code Generic

encrypt <- 
  function(msg, 
           pool = LETTERS, 
           do_replace = FALSE, 
           cheat = FALSE
          ) {
    
    msg_chars <- strsplit(msg,"")[[1]]

    u <- unique(msg_chars)

    encrypt_chars <- 
      sample(pool,
             size = length(u),
             replace = do_replace 
                                         
      )
    
    encrypt_chars <- 
      setNames(encrypt_chars, # vector to name
               u              # vector of names
      )

    if (cheat)
      # return the full map ..
      result <- encrypt_chars[msg_chars]
    else 
      # .. or just the encrypted message  
      result <- paste(encrypt_chars[msg_chars], 
                      collapse="")
      
    
    return(result)
  }

Functions – Making Code Generic

encrypt <- 
  function(msg, 
           pool = LETTERS, 
           do_replace = FALSE, 
           cheat = FALSE
          ) {
    
    msg_chars <- strsplit(msg,"")[[1]]

    u <- unique(msg_chars)

    encrypt_chars <- 
      sample(pool,
             size = length(u),
             replace = do_replace 
                                         
      )
    
    encrypt_chars <- 
      setNames(encrypt_chars, # vector to name
               u              # vector of names
      )

    if (cheat)
      # return the full map ..
      result <- encrypt_chars[msg_chars]
    else 
      # .. or just the encrypted message  
      result <- paste(encrypt_chars[msg_chars], 
                      collapse="")
      
    
    return(result)
  }
encrypt
function (msg, pool = LETTERS, do_replace = FALSE, cheat = FALSE) 
{
    msg_chars <- strsplit(msg, "")[[1]]
    u <- unique(msg_chars)
    encrypt_chars <- sample(pool, size = length(u), replace = do_replace)
    encrypt_chars <- setNames(encrypt_chars, u)
    if (cheat) 
        result <- encrypt_chars[msg_chars]
    else result <- paste(encrypt_chars[msg_chars], collapse = "")
    return(result)
}

Functions – Making Code Generic

encrypt <- 
  function(msg, 
           pool = LETTERS, 
           do_replace = FALSE, 
           cheat = FALSE
          ) {
    
    msg_chars <- strsplit(msg,"")[[1]]

    u <- unique(msg_chars)

    encrypt_chars <- 
      sample(pool,
             size = length(u),
             replace = do_replace 
                                         
      )
    
    encrypt_chars <- 
      setNames(encrypt_chars, # vector to name
               u              # vector of names
      )

    if (cheat)
      # return the full map ..
      result <- encrypt_chars[msg_chars]
    else 
      # .. or just the encrypted message  
      result <- paste(encrypt_chars[msg_chars], 
                      collapse="")
      
    
    return(result)
  }
encrypt(msg =  "This is a top-secret message!")
[1] "MFHWCHWCLCSJYKWZRGZSCBZWWLIZV"
encrypt(msg  =  "Something Else", 
        pool = c(LETTERS, letters))
[1] "TVMcxZNuPEfnqc"
encrypt(pool = c(LETTERS, letters))
Error in encrypt(pool = c(LETTERS, letters)): argument "msg" is missing, with no default

 

encrypt(msg = "Let's Cheat!",
        do_replace = TRUE, cheat=TRUE)
  L   e   t   '   s       C   h   e   a   t   ! 
"G" "P" "S" "I" "B" "A" "L" "Q" "P" "M" "S" "N" 

 

encrypt(msg = "This code is really hard to break: ^&^CF_)MNU!HX????",
        pool = LETTERS)
Error in sample.int(length(x), size, replace, prob): cannot take a sample larger than the population when 'replace = FALSE'

Functions – Making Code Generic

[?introduce internal return(), and stop()?]

R is a Lego Construction Set – Source Files

R/functions.R is a typical name for a file with small local functions:

# Compute the mean of a numeric vector:
compute_mean <-
    function(x) x / length(x)

# Compute the standard deviation
# of a numeric vector:
compute_sd <-
    function(x, is_sample=FALSE) {
        n <- length(x)

        sum((x - mean(x))^2) /
        (if(is_sample) (n-1) else n)
}

More complex local functions should have their own source file: 
Keep the encrypt() function in R/encrypt.R

How to Load Local Functions:  

source("R/functions.R")
source("R/encrypt.R")

Use this to make the functions available

  • in an interactive R session
  • in an R script

R is a Lego Construction Set – Packages

R is a Lego Construction Set – Packages

  • The structure of an R package is best seen in its raw form, as source package: it is simply a folder with strictly defined content in plain text
  • This includes functions and possibly data, but notably also the DESCRIPTION and NAMESPACE files, which describe how the package depends on other packages  
  • the post-installation structure is operation system dependent and no longer plain text

R is a Lego Construction Set – Package Dependencies

The base R function package_dependencies queries information on the CRAN repository. Therefore we need to set a valid CRAN mirror, if we have not already done so:

options(repos = findCRANmirror("web"))
getOption("repos")
[1] "https://CRAN.R-project.org"

 

List the strong dependencies of the plotting package ggplot2, i.e. those packages which need to be installed for ggplot2 to work:

tools::package_dependencies("ggplot2", which="strong")
$ggplot2
 [1] "cli"       "grDevices" "grid"      "gtable"    "isoband"   "lifecycle"
 [7] "rlang"     "S7"        "scales"    "stats"     "vctrs"     "withr"    

R is a Lego Construction Set – the CRAN repository

R is a Lego Construction Set – the CRAN repository

R is a Lego Construction Set – Libraries

 

While repositories are package sources, a destination folder for packages on our local system is called a library.
 

There may be more than a single library folder. 
Function .libPaths() can be used to list them :

.libPaths() 
[1] "/home/ugoebel/R-4.4.3/lib/R/library"

R is a Lego Construction Set – Install a Package (via R)

 

Bioi is a small and barebones package related to bioimaging . Let’s install it from CRAN:

install.packages("Bioi",
                 lib = .libPaths()[1],
                 repos = getOption("repos")
                 )

 

Note that parameters "lib" and "repos" are superfluous in this case, because

  • packages are by default installed to .libPaths()[1] (the user library)
  • we have already set the CRAN mirror URL above.

R is a Lego Construction Set – Install a Package (in rstudio)

 

First remove it again …

remove.packages("Bioi")

 

Restart the R session for rstudio's Packages pane to realize the change!

R is a Lego Construction Set – Install a Package (in rstudio)

Then do it rstudio-compliant:

R is a Lego Construction Set – Install a Package (in rstudio)

 

Have an eye on what happens in the console:

It uses a different CRAN mirror from the one we had set above!  
This happens because R had been restarted in between.

If you want a permanent value for an option,  

set it in your .Rprofile file!

R is a Lego Construction Set – Load a Package (in rstudio)

Checking an entry in the Packages list invokes the library() function:

R is a Lego Construction Set – Load a Package

library(PKG) without further arguments scans .libPath().  

The first entry found with name “PKG”

  • is attached to the search path
  • its namespace is loaded  
    (code can now refer to PKS’s functions by name, without specifying the package)

A shortcut to access one of PKG’s functions without library(PKG) is this: 
PKG::function_I_want_to_run().  

PKG would then be in the state loaded via namespace (and not attached).

R is a Lego Construction Set – Package Dependencies

Package A may “depend” on another package B because

  • A uses a functionality of B in its core computations. Whenever A is installed, B is automatically also installed, and if installation of B fails, then the installation of A fails, too.  
    This scenario comes in two flavors:  
    • A "Imports:" B:    A loads B’s functions via namespace
    • A "Depends:" on B:    A attaches B to the search path
  • A can optionally use a functionality of B, in case B is available  
    This "Suggests:" dependency allows A to be installed even if B cannot.

Dependencies are declared in the DESCRIPTION and NAMESPACE files of a package.  
(They should be readable in the package’s sub-folder of your library folder).

R is a Lego Construction Set – Package Dependencies

The risk of installation failure which comes with an Imports: or Depends: directive is not immediately obvious from the DESCRIPTION file!

Assume Package P depends on or imports four packages A, B, P1, and P2.

 

P's dependencies on A and B are much more risky  
than those on P1 and P2:

  • A and B have more total (direct and indirect) dependencies than P1 and P2
  • A and B share dependencies: both will fail if one of these fails

https://www.sciencedirect.com/science/article/pii/S0164121223000055

R is a Lego Construction Set – Package Dependencies

The ballgown package provides tools for statistical analysis of assembled transcriptomes, including flexible differential expression analysis, visualization of transcript structures, and matching of assembled transcripts to annotation.

R is a Lego Construction Set – Package Dependencies

follow this link to create a dependency plot for a Bioconductor package

R is a Lego Construction Set – Package Ecosystems

The easystats package orchestrates a small set of dependent packages,

An exemplary example of a package ecosystem in a nutshell!

R is a Lego Construction Set – Package Ecosystems

Going Large: Bioconductor

R is a Lego Construction Set – Bioconductor

 

Bioconductor has its own repository and installer,

  • because the R and Bioconductor release schedules do not match
  • and the package interdependencies require version compatibility
## if not installed, install via install.packages()
if (!require("BiocManager", quietly = TRUE))
    install.packages("BiocManager")

## once installed, use it to install an entire Bioconductor version (here)  or individual packages
BiocManager::install(version=3.21)

R is a Lego Construction Set – Bioconductor

The official Bioconductor website is very comprehensive, but can be overwhelming!

This site provides a more gentle, but still comprehensive walk-through.  

 

Bioconductor also provides workflow packages, e.g. the rnaseqGene workflow.
Let’s look at its documentation.

 

# Don't actually install it now -- it co-installs half of Bioconductor!
BiocManager::install("rnaseqGene")
browseVignettes("rnaseqGene")

R is a Lego Construction Set – Bioconductor

R is a Lego Construction Set – The Tidyverse

And then there is the Tidyverse, a large and growing ecosystem of cross-compatible packages, with focus on workflows on 2D tables and graphical objects: