Opening SEA-AD single-cell files in R

Quick-start with a single donor

Author

IPRE Winter 2026 · MOTCO · research line IPI-26-1206

This tutorial walks through loading one SEA-AD donor’s single-nucleus RNA-seq file into R and looking at what is inside. Using one donor instead of the whole cohort keeps the download and memory requirements small, so you can get a working object in a few minutes before you split off into your own track. Everything after the download stays in R.

SEA-AD ships its data as .h5ad, a format from the Python world. We read it straight into R with schard, which is pure R (no Python environment is required) and returns a SingleCellExperiment, the standard Bioconductor object used by both downstream pipelines.

Before you start

You need R 4.2 or newer and a web browser. One donor file is small enough for any laptop.

Step 1 — Install the R packages

Run this once. The first two packages come from Bioconductor; schard comes from GitHub.

# Bioconductor packages
if (!requireNamespace("BiocManager", quietly = TRUE)) {
  install.packages("BiocManager")
}
BiocManager::install(c("rhdf5", "SingleCellExperiment"))

# schard: reads .h5ad in pure R, no Python needed
if (!requireNamespace("remotes", quietly = TRUE)) {
  install.packages("remotes")
}
remotes::install_github("cellgeni/schard")

If schard reports an installation error, install rhdf5 on its own first (it is the component that reads the HDF5 file), then try installing schard again.

Step 2 — Download one donor’s file in a web browser

The single-cell data is available from the public SEA-AD download site. No account or command-line tool is required. The per-donor RNA-seq files are in PFC/RNAseq/donors_objects/. PFC is the prefrontal cortex, Brodmann area 9, also called DLPFC. There is one file per donor in that folder, plus a large all-cohort file elsewhere in RNAseq/ that you should skip for now.

  1. Open the SEA-AD public data browser.
  2. Open the PFC folder, then RNAseq, then donors_objects.
  3. Find the filename containing H20.33.001 (its full name is H20.33.001_SEAAD_DFC_RNAseq_final-nuclei.<date>.h5ad).
  4. Download that .h5ad file.
  5. In the repository root, create a data/sea-ad/ folder if it does not exist, then move the downloaded file into it and rename it donor_H20.33.001.h5ad. The full path from the repository root should be data/sea-ad/donor_H20.33.001.h5ad.

This is the shared data folder for the whole tutorial series. Later tutorials reuse the same file from here, so you only download it once. It is already git-ignored, so it will never be committed.

Any donor works; H20.33.001 is just a concrete choice. If you use a different donor, change the filename in the R code below. The other brain region, MTG (middle temporal gyrus), has the same layout under MTG/RNAseq/donors_objects/.

Step 3 — Load it into R

Set R’s working directory to this tutorial’s folder. In RStudio, select Session > Set Working Directory > To Source File Location. The path below then reaches the shared data/sea-ad/ folder from here (../../ steps up out of tutorials/01-read-h5ad/ to the repository root). Run the following code.

library(schard)
library(SingleCellExperiment)

sce <- schard::h5ad2sce("../../data/sea-ad/donor_H20.33.001.h5ad")
sce

This prints a summary of the object. A SingleCellExperiment holds three things you will reach for constantly:

  • the expression matrix: counts(sce) or assay(sce);
  • the per-cell metadata: colData(sce); and
  • the per-gene metadata: rowData(sce).

Step 4 — Look at what you loaded

Get your bearings before doing anything else. This is also the raw material for the variable dictionary you were asked to start.

dim(sce)                 # genes (rows) x cells (columns)
assayNames(sce)          # which matrices are stored
head(rownames(sce))      # gene identifiers
colnames(colData(sce))   # every per-cell metadata column

Now find the columns that matter for the Alzheimer’s work: the cell-type label, the donor’s sex, and the pathology measure.

cd <- colData(sce)

# Cell-type labels in the SEA-AD taxonomy
table(cd$Subclass)     # broad types (e.g. Astrocyte, Oligodendrocyte)
table(cd$Supertype)    # fine-grained types

# Sex and the categorical AD pathology score
table(cd$Sex)
table(cd$`Overall AD neuropathological Change`)

# Pathology staging variables: find them, then inspect their levels. In these
# per-donor files these are all *ordinal stages* (not a continuous number).
grep(
  "Braak|Thal|CERAD|CAA|neuropath",
  colnames(cd),
  value = TRUE,
  ignore.case = TRUE
)
table(cd$Braak)          # e.g. Braak IV
table(cd$Thal)           # e.g. Thal 2
table(cd$`CERAD score`)  # e.g. Sparse

Two things to notice:

  1. Column names with spaces need backticks, as with Overall AD neuropathological Change. Copy the capitalization exactly as colnames(colData(sce)) prints it; here the “n” in “neuropathological” is lowercase.
  2. Because this is a single donor, Sex and the pathology stages are the same for every cell. The differences you care about appear only when you compare donors, which is the next step in both tracks.
NoteWant a continuous pathology score?

These per-donor files carry only the ordinal pathology stages above. SEA-AD also defines a Continuous Pseudo-progression Score (CPS), a continuous 0–1 axis of disease severity, but it is not stored in these files. It lives in the combined atlas object and in the supplementary data of the original paper (Gabitto et al., Nat Neurosci 2024). Download the per-donor CPS table here, a simple sheet with two columns, Donor ID and CPS: sea-ad_global_and_local_cps.xlsx. Join it to your cells by Donor ID:

library(readxl)
cps <- read_excel("../../data/sea-ad/sea-ad_global_and_local_cps.xlsx")
# match(): pull each cell's donor CPS out of the lookup table
cd$CPS <- cps$CPS[match(cd$`Donor ID`, cps$`Donor ID`)]
ImportantYour deliverable: a variable dictionary

As you explore, keep a running variable dictionary: your own notes on the colData columns, what each one means, whether it is categorical or continuous, and whether it describes a single cell or the whole donor. This is your artifact, not a graded worksheet, and you will lean on it constantly: the grouping variables, confounders, and contrasts you choose in later tutorials all come from here. Start it now with the columns above (Subclass, Supertype, Sex, Overall AD neuropathological Change, and the other ordinal staging scores Braak, Thal, CERAD score), and add to it whenever you meet a new column. Nobody hands you the “right” set of variables; deciding which ones matter for your question is the first piece of the analysis that is yours.

Step 5 — Subset to one cell type

To see how subsetting works, keep just one cell type. Match the label exactly to what table(cd$Subclass) printed.

astro <- sce[, sce$Subclass == "Astrocyte"]
dim(astro)

Microglia, the brain’s resident immune cells and a focus of Alzheimer’s research, are worth finding too. In this taxonomy they are not their own Subclass; they sit inside the broader Immune subclass, with Supertype labels beginning Micro-PVM. You can select them either way:

immune <- sce[, sce$Subclass == "Immune"]                 # whole immune compartment
micro  <- sce[, grepl("^Micro-PVM", sce$Supertype)]       # microglia specifically
dim(immune)
dim(micro)

If something breaks

WarningThe file cannot be found

Confirm that the file is at data/sea-ad/donor_H20.33.001.h5ad under the repository root and that R’s working directory is this tutorial’s folder. Check with:

getwd()
file.exists("../../data/sea-ad/donor_H20.33.001.h5ad")
WarningInteger-overflow warning, or 'p' must be a nondecreasing vector

This can happen with very large .h5ad files, such as the full 1.2-million-cell cohort file, which is about 35 GB. Using one donor avoids the problem; this is a known limitation of reading very large files this way.

WarningOut of memory

Do not load the all-cohort file on a laptop. A one-donor file is appropriate for this tutorial.

WarningA table() result is empty or a column is oddly named

Run colnames(colData(sce)) again and copy the column name exactly, including spaces and capitalization.

Where this goes next

You now have a SingleCellExperiment for one donor and know where sex, pathology, and cell type live in it.

Before you move on, spend a few minutes exploring on your own. This is where the analysis choices you’ll make later begin:

  • Browse the full metadata with colnames(colData(sce)) and a few table() or summary() calls. Which variables would you use to compare cells within this donor? Which only make sense when comparing donors?
  • Which columns look like they could be confounders, things that might track with pathology but aren’t pathology itself (sex, age, post-mortem interval, RNA quality)? Note them in your variable dictionary; you’ll decide what to do about them when you run a real comparison.

There isn’t one right answer here; the point is to start reasoning about this as your dataset rather than a fixed recipe.

Next comes tutorial 02: Preprocessing, the shared foundation for everything that follows. There you’ll take this same donor’s raw counts through quality control, normalization, feature selection, and dimensionality reduction to produce an analysis-ready object. Both project tracks start from that object:

  • Pseudobulk analysis: repeat this loading process over donors, then perform per-donor pseudobulk aggregation.
  • Trajectory analysis: run PCA and UMAP on your chosen cell type, then anchor the slingshot trajectory in low-pathology cells.

Bring your variable dictionary to the next check-in.