DextraDemixer
Probabilistic identification of antigen-specific T cells from single-cell pMHC multimer experiments.
DextraDemixer models pMHC multimer UMI counts as a mixture of specific and nonspecific binding components. It returns a posterior binding probability and assignment for each cell, helping separate antigen-specific signal from background binding and assay noise.
The method is described in DextraDemixer enables accurate identification of antigen-specific T cells from pMHC multimer experiments.
[!NOTE] DextraDemixer is research software under active development. Interfaces may change while the package matures.
Highlights
- Infers cell-level posterior probabilities of antigen specificity from pMHC UMI counts.
- Supports optional negative-control multimers.
- Incorporates clonotype information through clone-level probability aggregation.
- Provides fixed-threshold and Bayesian false discovery rate (FDR) assignments.
- Works directly with
MuData,AnnData, andPandas DataFramesobjects and uses JAX and NumPyro for inference.
Installation
pip install dextrademixer
Alternative: Conda environment
For a conda environment.
git clone https://github.com/SchubertLab/DextraDemixer.git
cd DextraDemixer
conda env create -f environment.yaml
conda activate dextrademixer
pip install -e . # or pip install dextrademixer
The final command installs the local package in editable mode. Runtime dependency constraints are aligned between pyproject.toml and environment.yaml. To reproduce the numbers from the manuscript, use environment_reproducible.yaml instead: it pins the exact versions, and results can shift slightly with other JAX/NumPyro releases.
Quick start
Single pMHC
The example below fits one pMHC feature and classifies cells using a posterior-probability threshold of 0.5.
import muon as mu
from dextrademixer import DextraDemixer
mdata = mu.read("data/example_data.h5mu")
model = DextraDemixer().fit(mdata, pmhc_key="pmhc1", pmhc_modality_key="gex")
p_binder, is_binder = model.predict(threshold=0.5)
mdata.mod["gex"].obs["dextrademixer_probability"] = p_binder
mdata.mod["gex"].obs["dextrademixer_assignment"] = is_binder
To include a negative-control multimer, pass neg_ctrl_key. To aggregate probabilities within clonotypes, pass the clonotype column as ir_clone_key and set clonotype_median_p=True when predicting:
model = DextraDemixer().fit(
mdata,
pmhc_key="pmhc1",
pmhc_modality_key="gex",
neg_ctrl_key="neg_control",
ir_clone_key="clone_id",
)
p_pred, assignment = model.predict(threshold=0.5, clonotype_median_p=True)
Use either threshold for a fixed decision boundary or target_fdr for FDR-controlled assignments; do not specify both.
Multiple pMHCs
DextraDemixerMulti fits one independent DextraDemixer per pMHC and returns cells x pMHC tables instead of vectors. Each fit stays reachable as model.demixers[pmhc_key].
from dextrademixer import DextraDemixerMulti
mdata = mu.read("data/example_multi_pmhc.h5mu")
model = DextraDemixerMulti().fit(
mdata,
pmhc_keys=["pmhc1", "pmhc2", "pmhc3"],
pmhc_modality_key="gex",
neg_ctrl_key="neg_control",
)
p_pred, assignment = model.predict(threshold=0.5, clonotype_median_p=True, max_prob=True)
Because the pMHCs are fitted independently, a cell can pass the threshold for several. max_prob=True keeps only the pMHC with the highest probability per cell, combined with clonotype_median_p=True the same choice is made per clonotype.
Input data
DextraDemixer needs the pMHC UMI counts and, optionally, a cell-level clonotype identifier. It reads them from any of:
- A
MuDataobject: counts in the.Xof the feature modality (pmhc_modality_key,gexby default), clonotypes in the.obsof the AIRR modality (ir_modality_key,airrby default). - An
AnnDataobject: counts in.X, clonotypes in.obs;pmhc_modality_keyandir_modality_keyare then unused. - A cells x features
DataFrame: counts and annotation in the same table, so every key is a column name.
pmhc_key (or pmhc_keys) and the optional neg_ctrl_key name the count columns, ir_clone_key the clonotype column, whose ids may be integers or strings. The bundled example dataset ships in all three formats: data/example_data.h5mu, .h5ad and .csv. data/example_multi_pmhc.h5mu is a simulated three-pMHC panel.
See Tutorial.ipynb for a complete, reproducible workflow using the bundled example dataset, including configuration, model fitting, evaluation, and visualization, and Tutorial DextraDemixerMulti.ipynb for the same with multiple pMHCs:
jupyter lab Tutorial.ipynb
Reproducing the manuscript
The analyses and figure-generation code used in the manuscript are maintained in the DextraDemixer reproducibility repository.
Contributing
Bug reports, feature requests, and pull requests are welcome through the GitHub issue tracker. When reporting a problem, please include a minimal reproducible example and details of your operating system and Conda environment.
Citation
If DextraDemixer supports your research, please cite:
@article{An2026DextraDemixer,
author = {An, Yang and Drost, Felix and Bonafonte-Pard{\`a}s, Irene and Grotz, Myriam and Schober, Kilian and Schubert, Benjamin},
title = {DextraDemixer enables accurate identification of antigen-specific T cells from pMHC multimer experiments},
journal = {bioRxiv},
year = {2026},
publisher = {Cold Spring Harbor Laboratory},
doi = {10.64898/2026.06.23.733339},
url = {https://doi.org/10.64898/2026.06.23.733339},
elocation-id = {2026.06.23.733339}
}
License
DextraDemixer is distributed under the BSD 3-Clause License.
Metadata
Release files for dextrademixer 0.0.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| dextrademixer-0.0.1.tar.gz | 45.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| dextrademixer-0.0.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 93.6 kB
Release files / dextrademixer-0.0.1.tar.gz
| Download URL | dextrademixer-0.0.1.tar.gz |
|---|---|
| Size | 45.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
5447e9f793efce0b52eea6d00f2ce2c33be3e48a03c29d2e5adc669105d3a4bb
|
|
BLAKE2b-256 checksum How to use checksums |
2c606a5b172c26178bb3047d3388235bbf2c369b614f72f145e7ec9da0248acb
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Release files / dextrademixer-0.0.1-py3-none-any.whl
| Download URL | dextrademixer-0.0.1-py3-none-any.whl |
|---|---|
| Size | 48.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ef7f8bccc657d26262e43c5e3cf1d07e01fca3efe582221874f9094634776fdf
|
|
BLAKE2b-256 checksum How to use checksums |
5d90c5e1e5ebd1340a84d7e40a27359bf55a26a0d1507b060c0d1c55d3e2f0a3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|