Learning Single-Cell Analysis with Theis Lab: alevin-fry in Practice

· 7 min read · Tutorials

Learning Single-Cell Analysis with Theis Lab: alevin-fry in Practice

Single-Cell Best Practices

Hands-on Upstream Data Processing

SECTION PREVIEW

1. Get to know alevin-fry, a lightweight single-cell data processing tool

2. Step-by-step guide to setting up your environment and preparing data

3. Master two workflows: the streamlined version (simpleaf) and the full step-by-step version

4. Learn how to load and interpret the output data

This section corresponds to Section 3.8 A real-world example in the original book.

01

Overview

In previous articles, we covered the upstream processing pipeline for single-cell data analysis in detail. In this chapter, we walk through a hands-on example demonstrating how to use alevin-fry to process a small-scale dataset.

For the purposes of this tutorial, we use only human chromosome 5 and its associated annotations as the reference genome (extracted from the 10x Genomics human reference genome). The example dataset is a subset of the 10x Genomics Human Brain Tumor Dataset derived from reads mapping to chr 5.

(All data used in this tutorial can be downloaded via links embedded in the code. The accompanying content package also includes all code and data files — see the end of the article for how to access them.)

The tools used in this example are:

  • alevin-fry
    An efficient, accurate, and memory-lean tool for processing single-cell and single-nucleus RNA-seq data. It automatically quantifies spliced, unspliced (intronic), and ambiguous reads.

  • simpleaf
    A Rust-based tool designed to streamline the alevin-fry workflow. simpleaf wraps the entire process into two steps:

    1. Build a reference index: Combine the genome FASTA and gene annotation (GTF) files to generate a splici reference (a reference that incorporates both spliced transcript and intronic sequence information).
    2. Quantification: Map sequencing reads to this reference and produce a gene expression count matrix.

02

Setup

Environment Configuration

# Create and activate the conda environment
conda create -n af -y -c bioconda simpleaf pyroe
conda activate af

⚠️ Note: If you are using an Apple Silicon (M-chip) Mac, you need to force a 64-bit (x86) environment as follows (this only affects the current conda environment and does not impact others):

CONDA_SUBDIR=osx-64 conda create -n af -y -c bioconda simpleaf pyroe
conda activate af
conda env config vars set CONDA_SUBDIR=osx-64

Data Preparation

# Create and navigate to the working directory
mkdir af_xmpl_run && cd af_xmpl_run

# Download and extract the example data
wget -qO- https://umd.box.com/shared/static/lx2xownlrhz3us8496tyu9c4dgade814.gz | tar xzf - --strip-components=1 -C .

# Define paths to the FASTQ and reference genome directories
fastq_dir="toy_read_fastq"
ref_dir="toy_human_ref"

# Download and decompress the cell barcode whitelist
# (the URL in the original book has a typo; the corrected URL is used here)
wget -qO- https://raw.githubusercontent.com/f0t1h/3M-february-2018/master/3M-february-2018.txt.gz | gunzip - > 3M-february-2018.txt

03

Hands-On Walkthrough

Option 1: Using simpleaf (Streamlined Workflow)

Step 1. Build the Reference Index

# Set the ALEVIN_FRY_HOME environment variable
export ALEVIN_FRY_HOME=$(pwd)/alevin_fry_home
mkdir -p $ALEVIN_FRY_HOME
simpleaf set-paths

simpleaf set-paths checks that all required software is available and properly configured. You may see a message like Could not find macs3 executable — this is expected and will not affect the tutorial, since we are not working with ChIP-seq data. If you need MACS3 for other purposes, install it with conda install macs3.

# Build the index
simpleaf index \
  -o simpleaf_index \
  -f $ref_dir/fasta/genome.fa \
  -g $ref_dir/genes/genes.gtf \
  -r 90 \
  -t 8 \
  --no-piscem

If you encounter an error, first check that ref_dir is defined (it should have been set in the previous section). Note that the current default indexer piscem has known compatibility issues on some systems, so we add --no-piscem to use salmon as the indexer instead. In practice, you can increase the number of threads (-t) to speed up the process.

An important note: -r must match the actual R2 read length (i.e., the number of sequencing cycles), which varies by library chemistry. For standard 10x Chromium data, v3 chemistry uses 91 bp reads and v4 uses 90 bp. You can verify the read length by inspecting the FASTQ file directly or consulting the 10x Genomics documentation.

Step 2. Quantification

# Collect FASTQ file paths
reads1=$(ls -1 "${fastq_dir}"/*_R1_* | sort | tr '\n' ',' | sed 's/,$//')
reads2=$(ls -1 "${fastq_dir}"/*_R2_* | sort | tr '\n' ',' | sed 's/,$//')

# Run quantification
simpleaf quant \
  -c 10xv3 -t 8 \
  -1 $reads1 -2 $reads2 \
  -i simpleaf_index/index \
  -u -r cr-like \
  -m simpleaf_index/index/t2g_3col.tsv \
  -o simpleaf_quant

After the command completes successfully, the quantification output can be found in simpleaf_quant/af_quant/alevin/. This folder contains three files:

quants_mat.mtx — the count matrix (analogous to CellRanger's matrix.mtx)
quants_mat_cols.txt — gene identifiers (analogous to CellRanger's features.tsv)
quants_mat_rows.txt — cell barcodes (analogous to CellRanger's barcodes.tsv)

Option 2: Step-by-Step alevin-fry (Full Workflow)

Step 1. Build the Reference Index

⚠️ Before proceeding, make sure the ref_dir and fastq_dir variables are defined!

# Build the splici reference
pyroe make-splici \
  ${ref_dir}/fasta/genome.fa \
  ${ref_dir}/genes/genes.gtf \
  90 \
  splici_rl90_ref

# Build the salmon index
salmon index \
  -t $(ls splici_rl90_ref/*.fa) \
  -i salmon_index \
  -p 8

Step 2. Read Mapping

# Collect FASTQ file paths
reads1="$(ls -1 "${fastq_dir}"/*_R1_* | sort | tr '\n' ' ' | sed 's/ $//')"
reads2="$(ls -1 "${fastq_dir}"/*_R2_* | sort | tr '\n' ' ' | sed 's/ $//')"

# Run selective alignment with alevin
salmon alevin \
  -i salmon_index \
  -l ISR \
  -1 ${reads1} \
  -2 ${reads2} \
  -p 8 \
  -o salmon_alevin \
  --chromiumV3 \
  --sketch

Step 3. Cell Barcode Resolution and UMI Quantification

# Generate the cell barcode permit list
alevin-fry generate-permit-list \
  -u 3M-february-2018.txt \
  -d fw \
  -i salmon_alevin \
  -o alevin_fry_gpl

# Collate the mapping results
alevin-fry collate \
  -i alevin_fry_gpl \
  -r salmon_alevin \
  -t 8

# Resolve UMIs and quantify
alevin-fry quant \
  -r cr-like \
  -m $(ls splici_rl90_ref/*3col.tsv) \
  -i alevin_fry_gpl \
  -o alevin_fry_quant \
  -t 8

After quantification finishes, the results are stored in alevin_fry_quant/alevin/, which contains the same three files — quants_mat.mtx, quants_mat_cols.txt, and quants_mat_rows.txt — as in Option 1.

04

Interpreting the Output

Output File Format

Although alevin-fry's three output files look superficially similar to CellRanger's output, there are important differences in their contents.

# Count matrix
# Each row contains three values: row index, column index, and the non-zero count
$ tail -3 simpleaf_quant/af_quant/alevin/quants_mat.mtx
138 58 1
139 9 1
139 37 1

# Gene identifiers
# Format: gene_name-splicing_status
#   A = ambiguous, S = spliced, U = unspliced
$ tail -3 simpleaf_quant/af_quant/alevin/quants_mat_cols.txt
ENSG00000120705-A
ENSG00000198961-A
ENSG00000245526-A

# Cell barcodes
# Standard 16-nt 10x cell barcodes
$ tail -3 simpleaf_quant/af_quant/alevin/quants_mat_rows.txt
TTCGATTTCTGAATCG
TGCTCGTGTTCGAAGG
ACTGTGAAGAAATTGC

Loading the Data

The standard data-loading functions in Seurat and scanpy cannot be used directly with alevin-fry output. The correct approach is to use Python's pyroe package or R's fishpond package. (The naming makes sense once you notice the theme: salmon → roe → fishpond — a delightful aquatic naming convention!)

# Python
import pyroe

# Load only spliced (S) and ambiguous (A) counts
adata_sa = pyroe.load_fry('simpleaf_quant/af_quant')

# Load all counts: unspliced (U), spliced (S), and ambiguous (A)
adata_usa = pyroe.load_fry('simpleaf_quant/af_quant',
                           output_format={'X': ['U', 'S', 'A']})

# R
library(fishpond)

# Load the data
sce <- loadFry('alevin_fry_quant')

05

Closing Thoughts

How did you find Chapter 3's hands-on session? With this, we wrap up the upstream processing portion of the book. Next, we'll officially dive into downstream analysis pipelines — starting with the Python-based anndata–mudata–scanpy ecosystem, including environment setup, an anatomy of the AnnData and MuData data structures, and how to convert between different single-cell ecosystems. Stay tuned!


Originally posted on WeChat Official Account: bioinfo_studyroom

Single Cell Tutorial