DotMatch to scverse for Perturb-seq and Feature Barcodes
This tutorial shows the intended handoff from DotMatch assignment artifacts to AnnData/scverse objects. Use the CLI for FASTQ-scale assignment, then load the small, stable TSV outputs into Python.
1. Count guide or feature-barcode reads
dotmatch count \
--targets guides.tsv \
--reads guide_capture_R2.fastq.gz \
--sample-label guide_capture \
--target-start 63 \
--target-length 19 \
--k 1 \
--metric hamming \
--ambiguity-policy radius \
--ambiguous discard \
--out guide_counts.tsv \
--summary guide_summary.json \
--sample-qc guide_sample_qc.tsv \
--assignments guide_assignments.tsv
For TotalSeq/CITE-seq-style feature barcodes, use the feature-barcode table as
--targets and set --target-start / --target-length to the antibody or
feature barcode window.
2. Load counts into AnnData
import dotmatch
guide_adata = dotmatch.counts_tsv_to_anndata("guide_counts.tsv")
guide_adata.uns["dotmatch_summary_json"] = "guide_summary.json"
guide_adata.uns["dotmatch_sample_qc_tsv"] = "guide_sample_qc.tsv"
The count matrix contains uniquely assigned targets only. Ambiguous reads are
reported in summary.json, sample_qc.tsv, and assignments.tsv; they are not
silently assigned to a guide or feature.
3. Attach per-read assignments when cell barcodes are available
If your assignment table includes a cell barcode column, convert it to an AnnData observation-level table:
import dotmatch
assign_adata = dotmatch.assignments_to_anndata(
"guide_assignments.tsv",
cell_col="cell_barcode",
target_col="target_id",
)
For custom pipelines, join DotMatch assignments to cell barcodes before this
step. Keep assignment_status so downstream filtering can distinguish unique,
ambiguous, unmatched, and invalid reads.
4. Use scanpy-style helpers
import scanpy as sc
import dotmatch.tl as dm_tl
library = [
{"id": "guide_A", "sequence": "ACGTACGTACGTACGTACG"},
{"id": "guide_B", "sequence": "TGCATGCATGCATGCATGC"},
]
dm_tl.assign_features(
adata,
seq_col="guide_sequence",
library=library,
k=1,
metric="hamming",
)
feature_adata = dm_tl.feature_counts(
adata,
seq_col="guide_sequence",
library=library,
k=1,
metric="hamming",
)
Use this path for notebook-scale inspection and prototypes. For production
FASTQ processing, prefer dotmatch count so the exact command, assignment
engine, ambiguity policy, and QC summaries are written as reproducible files.
5. Recommended scverse metadata
Store DotMatch provenance in .uns:
adata.uns["dotmatch"] = {
"summary": "guide_summary.json",
"sample_qc": "guide_sample_qc.tsv",
"assignments": "guide_assignments.tsv",
"ambiguity_policy": "radius",
"ambiguous_reads_counted": False,
}
For Perturb-seq analysis, keep guide assignment QC next to standard scRNA-seq QC. A high ambiguous or unmatched rate usually means the guide window, barcode library, or correction radius should be checked before interpreting guide-level effects.