10x Genomics HDF5

Cell Ranger’s filtered_feature_bc_matrix.h5 and raw_feature_bc_matrix.h5, and the same layout from Space Ranger, Xenium and CellBender. The file is recognised by its content, whatever its name. Given alone, a Space Ranger or Xenium matrix converts without its positions: convert the Space Ranger folder or the Xenium bundle to keep them.

adata convert filtered_feature_bc_matrix.h5 -o counts.h5ad
adata convert raw_feature_bc_matrix.h5 -o rna.h5ad --feature-type "Gene Expression"
adata convert multiome.h5 -o sample.h5ad --split-feature-types
adata convert cellranger2.h5 -o mouse.h5ad --genome mm10
adata convert counts.h5ad -o out.h5 --layer counts
Flag Meaning
--genome Keep this genome’s features; picks the group in a Cell Ranger 2 file holding several
--var-names gene_ids (default) or gene_symbols, scanpy’s default
--make-unique Suffix repeated var names as var_names_make_unique does
--feature-type Keep one feature type, e.g. "Gene Expression"
--split-feature-types Write one output per type, OUT.<type>.h5ad
--layer Export: the matrix to write, X (default), raw/X or a layer
--gene-ids-column Export: var column with gene ids (default gene_ids)
--gene-names-column Export: var column with gene names (default the var names)
--feature-types-column Export: var column with feature types (default feature_types)

Features are named by gene id, with the symbols in var["gene_symbols"]: the layout scanpy.read_10x_mtx(var_names="gene_ids") gives. Ids are unique where symbols repeat (Cell Ranger’s GRCh38-2020-A reference repeats 10), so naming by them, as scanpy does by default, needs --make-unique to give unique names; --var-names gene_symbols does that when wanted. The exception is a probe-level (Flex) matrix, whose several probes per gene share a gene id: pass --make-unique there, or use var["probe_ids"]. Either way, repeated names are reported when they occur. With it, reading gives what scanpy.read_10x_h5(gex_only=False) gives, column for column: gene_ids, feature_types, every other per-feature field Cell Ranger recorded (genome, and pattern, read and so on for antibody and CRISPR features), probe_ids for a probe-based (Flex) matrix, and filtered_barcodes in obs where present. Unlike scanpy, every feature type is kept unless --feature-type says otherwise, and X keeps Cell Ranger’s integer counts, where scanpy converts them to float32; run adata recast out.h5ad X --inplace --dtype float32 if a tool needs floats. Repeated var names are kept and reported, as scanpy does; --make-unique suffixes them. The run’s metadata, which scanpy drops, goes in uns["cellranger"].

The matrix is stored genes x cells in CSC, which is byte for byte cells x genes in CSR, so data, indices and indptr stream straight across; --split-feature-types reads them once for every output.

Writing produces the Cell Ranger 3+ layout for CellBender, SoupX, DropletUtils, Seurat and anything else that reads Cell Ranger output: gzip compression and fixed-width strings, as Cell Ranger writes them, since PyTables (which CellBender reads with) cannot read the variable-length kind. A CSC or dense matrix is transposed or sparsified on the way, streaming. Each feature needs an id and a type: if var has no gene_ids and no feature_types column (or the columns named by the flags above), the export is refused, and --force writes the names as ids and Gene Expression as the type. A matrix of floats is written as it is, with a warning. A file imported by convert exports with its run metadata and tag fields intact.