install.packages() vs library()|>read_csv / write_csvTip
Everything in this workshop — QC, clustering, DE, enrichment — is R code you can read, adapt, and re-run.
The comfortable default for R work:
Write code in the Source pane so it’s saved; use the Console for quick experiments.
A general coding alternative, especially good for SSH (remote) work:
RBoth IDEs run the same R — pick the one you prefer for local work.
<-; R is case-sensitive (x ≠ X)#counts <- c(8, 3, 0, 12, 5, 1, 0, 9) # c() = concatenate
counts * 2 # every element doubled — no loop needed
counts + counts # element-wise addition
sum(counts); mean(counts); median(counts)
sd(counts); max(counts); min(counts)
length(counts) # how many elements
seq(0, 10, by = 2) # 0 2 4 6 8 10
1:10 # shorthand integer sequencedbl, int, chr, lgl, or fctrNA marks a missing value; most summary functions accept na.rm = TRUETRUE/FALSE mask, then use it to filtercounts > 4 returns a logical vector; counts[counts > 4] keeps the hitscells <- data.frame(
barcode = c("AAAC", "AAAG", "AAAT", "AACA"),
sample = c("CTRL", "CTRL", "STIM", "STIM"),
nCount_RNA = c(8500, 12000, 6400, 9100),
nFeature = c(2300, 3100, 1900, 2500)
)
str(cells) # structure: columns, types, values
summary(cells) # per-column summary stats
nrow(cells); ncol(cells) # dimensions
colnames(cells) # column namesobj@meta.data)str() and summary() are your first-look tools; nrow() / ncol() give dimensions[row, column] — leave either blank to mean “all”$name is the shorthand for a single column — you’ll use this constantlylevels = c("CTRL", "STIM") → contrast is “STIM vs CTRL”[[ ]] extracts contents; [ ] returns a sub-list# coefficient of variation — a small helper function
cv <- function(x, na.rm = TRUE) {
if (na.rm) x <- x[!is.na(x)]
sd(x) / mean(x)
}
cv(c(1, 2, 3, 4, 5)) # 0.527
cv(c(1, 2, NA, 4, 5)) # 0.609 (NA dropped via na.rm)
# named vs positional arguments
round(3.14159, 2) # positional — order matters
round(x = 3.14159, digits = 2) # named — clearer, order-independentname <- function(args) { body }; last expression is returnedinstall.packages() vs library()install.packages() = get it onto your computer (do once)library() = make it available this session (do every time)BiocManager::install() instead of install.packages()muscData::Kang18_8vs8()Note
Workshop package installation is fully covered in Module 00 — Setup. That’s the canonical install block for everything through Module 08. Today’s goal is just to understand the install vs library distinction.
|>library(tidyverse)
cells |>
filter(nCount_RNA > 7000) |> # keep cells with > 7000 UMIs
mutate(genes_per_umi = nFeature / nCount_RNA) |> # add a derived column
group_by(sample) |> # group by condition
summarise(
n_cells = n(),
median_umi = median(nCount_RNA),
.groups = "drop"
) |>
arrange(desc(median_umi)) # sort highest first|> feeds the left side into the first argument of the right side| Verb | What it does | Workshop use |
|---|---|---|
filter() |
Keep rows matching a condition | QC cutoffs (Module 01) |
select() |
Keep / drop columns | Tidy up result tables |
mutate() |
Add or modify columns | percent.mt, genes_per_umi (Module 01) |
arrange() |
Sort rows | Top DE genes by p-value |
group_by() |
Define groups for summaries | Pseudobulk aggregation (Module 06) |
summarise() |
Reduce groups to one row | Counts per donor × condition (Module 06) |
These six verbs cover the majority of data-frame work in every tutorial.
# Module 06 flavour: per-donor QC summary before pseudobulk DE
meta |>
filter(nFeature_RNA > 200, nFeature_RNA < 2500,
percent.mt < 20) |>
group_by(donor, condition) |>
summarise(
n_cells = n(),
median_umi = median(nCount_RNA),
median_genes = median(nFeature_RNA),
.groups = "drop"
) |>
arrange(condition, desc(n_cells))meta is the per-cell metadata data frame from a Seurat object|> pipe is used in every tutorial from Module 01 onwardAlmost every figure in this workshop is a ggplot. You build a plot in layers: data → aesthetic mapping (aes) → geoms → scales/themes.
aes() maps columns to visual properties; geom_*() adds a layer (points, violins, bars)+ chains layers — the same additive idea as the |> pipe, but for graphicsDimPlot/FeaturePlot/VlnPlot all return ggplot objects you can extend with +# write our data frame, then read it back
write_csv(cells, "cells_demo.csv") # tidyverse — no row names
back <- read_csv("cells_demo.csv") # returns a tibble
back
# base R equivalents
write.csv(cells, "cells_demo.csv", row.names = FALSE)
back2 <- read.csv("cells_demo.csv")
# other separators and formats
df_tsv <- read_tsv("data.txt") # tab-separated
# library(readxl); xl <- read_excel("file.xlsx")read_csv() / write_csv() (tidyverse) return tibbles and are faster and friendlier.csv, .tsv) — it outlasts any software version| Skill | First used in |
|---|---|
filter() on per-cell QC metadata |
Module 01 — QC filtering |
mutate() to add derived columns |
Module 01 — percent.mt |
factor(), relevel() for reference levels |
Module 06 — DESeq2 design |
group_by() + summarise() |
Module 06 — pseudobulk aggregation |
arrange() on DE results |
Modules 03, 06, 07 — sorting by p-value / LFC |
read_csv() / write_csv() |
Throughout Modules 01–08 |
The |> pipe |
Every module from 01 onward |
Lists / [[ ]] indexing |
Seurat object internals — Modules 01–08 |
<-, math, log(), sqrt()c(), element-wise ops, logical subsetting, seq()str() / summary(), index with [row, col] and $$ and [[ ]] accessfunction(args) { body }; named argumentsinstall.packages() once; library() every session; Module 00 installs everythingfilter, mutate, group_by, summarise, arrangeread_csv(), write_csv()filter() and mutate() on live single-cell data, immediatelySingle Cell RNA-seq Workshop · P2 — R & RStudio