Build a gene x cell UMI count matrix directly from a CellRanger-tagged BAM.
bam2mtx walks a BAM's alignment records once, groups reads by
(cell barcode, gene) using the CB/GX tags CellRanger wrote into
the file, and counts distinct UMIs (the UB tag) per group. Useful
when you have a CellRanger BAM but the matrix was never archived or
got lost.
- Python >= 3.9
- pysam >= 0.19
- A BAM produced by CellRanger's Gene Expression pipeline (or anything
writing the same tag conventions, e.g. STARsolo), specifically the
CB(corrected cell barcode),UB(corrected UMI) andGX(gene ID(s) a read confidently overlaps) tags.
git clone https://github.com/powellgenomicslab/bam2mtx.git
cd bam2mtx
pip install .This installs the bam2mtx command.
bam2mtx <bam> -o <out_dir> [--xf-mode {robust,strict,off}] [--threads N] [--top-n N] [--v2-format]| Option | Description |
|---|---|
bam |
Path to a CellRanger Gene Expression BAM (CB/UB/GX/GN tagged). |
-o, --out-dir |
Output directory (required). |
--xf-mode |
How to use 10x's xf "extra flags" tag for read selection. See xf-mode filtering below. Default: robust. |
--threads |
BAM decompression threads. Default: 4. |
--top-n |
Keep only the top N barcodes by total UMI count. Default: keep every observed barcode (the "raw" matrix). |
--v2-format |
Write the legacy uncompressed CellRanger v2 layout (matrix.mtx/genes.tsv/barcodes.tsv, 2-column genes.tsv) instead of the modern gzipped v3 layout (matrix.mtx.gz/features.tsv.gz/barcodes.tsv.gz, 3-column features.tsv.gz). Default: v3. |
Standard CellRanger MatrixMarket layout, loadable with scipy.io.mmread,
Seurat::Read10X, scanpy.read_10x_mtx, or any other standard 10x-format
reader. The gene ID -> gene symbol map is built from the BAM's own
GX/GN tags.
10x's xf tag is a per-read "extra flags" bitmask. bam2mtx uses it (in
addition to requiring CB+UB+GX and a single-gene GX) to decide which
reads to count:
robust(default) — a bitmask test: bit 0 (confidently mapped) and bit 4 (UMI-count representative) set, bit 1 (discordant multi-mapper) clear.strict—xf == 17orxf == 25exactly.off— ignorexfentirely; rely only onCB+UB+GXpresence and single-geneGX.
I checked bam2mtx against a CellRanger run using 10x Genomics'
public "1k PBMCs from a Healthy Donor (v3 chemistry)"
dataset. Running it on CellRanger 3.0.0's own BAM with the default
--xf-mode robust reproduced CellRanger's own raw feature-barcode matrix
exactly.