Command-line interface¶
The topiary command runs the whole pipeline: read an antigen source, call one
or more MHC predictors, filter and rank the predictions, write a table. Every
run needs an input, a predictor (or a cache) and, for allele-specific
models, a list of alleles.
topiary \
--fasta proteins.fasta \
--mhc-predictor netmhcpan \
--mhc-alleles 'HLA-A*02:01,HLA-B*07:02' \
--ic50-cutoff 500 \
--output-csv results.csv
Predictors and alleles¶
Name one or more predictors with --mhc-predictor and alleles with
--mhc-alleles:
--mhc-predictor netmhcpan mhcflurry --mhc-alleles 'HLA-A*02:01,HLA-B*07:02'
All predictors come from mhctools, which
also handles their installation and licensing. Quote allele lists: * is a
glob character, and shells that do not pass unmatched patterns through (zsh,
and bash under failglob) reject the command before topiary sees it.
| CLI name | Predicts |
|---|---|
netmhcpan |
affinity + presentation (auto-detects installed version) |
netmhcpan4 / netmhcpan41 / netmhcpan42 |
specific NetMHCpan 4.x versions |
netmhcpan4-ba / netmhcpan4-el |
single-mode (binding affinity or eluted ligand) |
mhcflurry |
affinity + presentation + processing |
mixmhcpred |
presentation |
netmhciipan / netmhciipan4 / netmhciipan43 |
MHC class II |
bigmhc / bigmhc-el / bigmhc-im |
presentation / immunogenicity |
netmhcstabpan |
pMHC stability |
pepsickle / netchop |
proteasomal cleavage |
netmhcpan-iedb / netmhccons-iedb / smm-iedb |
local compatibility wrappers; require NetMHCpan 4.1 BA, NetMHCcons or SMM, respectively |
random |
random predictions (for testing) |
The historical *-iedb names run installed tools locally and have no HTTP
fallback. See MHCTools' compatibility-wrapper requirements.
Peptide lengths for sliding-window scans come from the predictor unless you set
them: --mhc-epitope-lengths 8,9,10,11.
Input modes¶
Peptides scored as given¶
topiary \
--peptide-csv peptides.csv \
--mhc-predictor netmhcpan \
--mhc-alleles 'HLA-A*02:01' \
--output-csv results.csv
The CSV needs a peptide column and may have a name column. No sliding
window is applied.
Proteins scanned with a sliding window¶
topiary \
--fasta proteins.fasta \
--mhc-predictor netmhcpan \
--mhc-alleles 'HLA-A*02:01,HLA-B*07:02' \
--output-csv results.csv
Restrict the scan to parts of each sequence with --regions NAME:START-END
(0-indexed, half-open):
--regions spike:319-541 nucleocapsid:0-50
Somatic variants¶
topiary \
--vcf somatic.vcf \
--mhc-predictor netmhcpan \
--mhc-alleles 'HLA-A*02:01,HLA-B*07:02' \
--filter-by "ba <= 500 | el.rank <= 2" \
--sort-by "0.6 * affinity.descending_cdf(500, 200) + 0.4 * presentation.score" \
--only-novel-epitopes \
--output-csv epitopes.csv
--maf, --variant and --json-variants take the same pipeline from other
variant formats. RNA expression can annotate and filter these
rows.
A protein change with no genomic coordinate¶
Hotspots are usually named at the protein level. --protein-change GENE CHANGE
takes one directly, picks a protein-coding transcript whose residue at that
position matches the reference amino acid, and tiles peptides over it:
topiary \
--protein-change EGFR T790M \
--genome grch37 \
--mhc-predictor netmhcpan \
--mhc-alleles 'HLA-A*02:01' \
--output-csv hotspot.csv
The variant column is empty for these rows: no genomic position was named, so
none is invented. Read-level DNA/RNA and variant-expression evidence therefore
cannot attach to them. Gene- and transcript-expression evidence can attach
because the selected transcript supplies those identities.
Protein changes can be named beside --vcf, --maf, --variant or
--json-variants in one run. The output column mutation_input is
genomic_variant for coordinate-bearing rows and protein_change for direct
changes. This column is available to --filter-by and --sort-by, so a filter
requiring variant-only evidence can state what should happen to protein changes:
--variant-expression isovar.tsv \
--filter-by "mutation_input == 'protein_change' | variant_num_alt_reads >= 3"
Every configured mutation shares one effect-selection, prediction, filter and
sort pass. Distinct --protein-change flags remain independent inputs; they are
not treated as transcript alternatives merely because all lack a genomic
variant (#421). Exact duplicate
fragments still follow the pipeline's normal deduplication.
Where several transcripts carry the named reference residue, topiary picks
between them with representative_transcript, the same rule the gene sources
use: complete protein-coding translations first, then standard amino-acid
sequences, then length, with transcript-ID tie breaking. A change can therefore
land on a different transcript as the annotation release changes; pass
--ensembl-release to pin it. The chosen transcript is named in the
transcript_id and transcript_name columns.
Genes, transcripts and proteome-scale sources¶
topiary --gene-names BRAF TP53 EGFR --mhc-predictor netmhcpan --mhc-alleles 'HLA-A*02:01'
topiary --gene-ids ENSG00000157764 --mhc-predictor netmhcpan --mhc-alleles 'HLA-A*02:01'
topiary --transcript-ids ENST00000288602 --mhc-predictor netmhcpan --mhc-alleles 'HLA-A*02:01'
topiary --ensembl-proteome --mhc-predictor netmhcpan --mhc-alleles 'HLA-A*02:01'
topiary --cta --mhc-predictor netmhcpan --mhc-alleles 'HLA-A*02:01' # cancer-testis antigens
--cta uses the included PirlyGenes integration. The same sources are available in Python
through topiary.sources — see the quickstart.
Source species, reference backgrounds and MHC¶
--species selects the antigen sequence source. Human is the default for direct
inputs; a non-human built-in source requires --ensembl-release. Species names
and aliases follow PyEnsembl (mouse and Mus musculus select the same species).
--mhc-alleles is independent: using mouse proteins with a human HLA allele is
valid, including HLA-transgenic models (Pascolo et al., PMID 9182675).
# Mouse proteins presented by mouse MHC
topiary --gene-names Trp53 --species mouse --ensembl-release 102 \
--mhc-predictor netmhcpan --mhc-alleles 'H2-Kb'
# The same source with human HLA, for an HLA-transgenic model
topiary --gene-names Trp53 --species mouse --ensembl-release 102 \
--mhc-predictor netmhcpan --mhc-alleles 'HLA-A*02:01'
# Human antigens with an explicitly selected mouse comparison background
topiary --gene-names TP53 --species human \
--exclude-ensembl --exclude-species mouse --exclude-ensembl-release 102 \
--mhc-predictor netmhcpan --mhc-alleles 'HLA-A*02:01'
Built-in exclusions normally inherit the source species and release. For variant
inputs, this comes from the annotations actually loaded, including references in
MAF and JSON files. --genome still chooses variant coordinates; it is rejected
for direct sequence inputs, where --species / --ensembl-release select the
source. For protein changes, either form can select the annotation. If source
species/release flags accompany an annotated input, they must agree with it.
--exclude-species starts an independent reference context; its release is
--exclude-ensembl-release, never a number borrowed from another species.
Explicit human references may use the current human default; non-human references
require a release. --exclude-ensembl-release alone keeps the inferred source
species and overrides its background release. Mixed-species annotations,
multiple annotation releases and custom annotations without a numbered Ensembl
release require an explicit background when using built-in exclusions. They
remain usable without that ambiguous built-in comparison.
FASTA/CSV inputs carry no inferred species metadata: choose --species and a
release explicitly when they should determine a non-human built-in background.
Additional --exclude-fasta files can supply other backgrounds; all their
sequences are retained even if different files reuse a header. Combining them
excludes matches to the union. Run separate comparisons if you need separate
human and mouse results. Exclusions are sequence matching, not a simulation of
host antigen processing or transplant immunity.
--cta is human-only in the antigen-source context. --exclude-non-cta and
--exclude-tissues are human-only in the background context. Human CTA
antigens with a mouse background are valid; requesting mouse CTA membership or
applying the human tissue-expression table as mouse data gives an error.
Before 5.112, built-in exclusions defaulted to human even for mouse variants. They now follow the actual input annotation. To request a different reference deliberately, use the exclusion-specific options instead of changing source flags.
A gene usually has several Ensembl translations. All gene-derived inputs use
best_protein_transcript: complete protein-coding translations first, then
standard amino-acid sequences, then length, with transcript-ID tie breaking.
--protein-change applies that same ranking, through the shared
representative_transcript, to the transcripts carrying its reference residue.
By default, Topiary skips protein scan inputs containing X (case-insensitive),
including all their clean windows, and warns with a count and example source
names. Other proteins continue normally; if every input is excluded, the command
succeeds with an empty prediction table. This shared policy covers CTA, gene,
tissue, FASTA, transcript, proteome and variant/fragment scans. An excluded WT
baseline leaves WT prediction values missing without removing the candidate.
It acts on the actual scan input, after region or variant-fragment extraction.
Use --protein-x-policy windows (Python: protein_x_policy="windows") to
process the usable parts of these proteins. Only windows whose peptide and
required model flanks contain no X are scored. Names and offsets still refer
to the original protein. An internal X never becomes a new terminus, and
regions on either side are never concatenated. For example, a 9-residue window
in XASIINFEKLGGG can start at offset 3 or 4 with a model requiring two residues
of context on each side; shorter flanks are allowed only at the true boundary.
Models without flanking inputs can use more windows.
The model or cache must declare its required context. Unknown limits cause the
X-containing inputs to be skipped with a warning; clean proteins continue.
Stored predictions retain their original context and values. Missing retained
cache windows still raise unless --cache-miss-report requests partial results;
see cached predictions.
--protein-x-policy allow explicitly passes original proteins unchanged to a
model that supports X, retaining strict producer errors. Use windows for the
X-free override. Other residues, exact peptide/peptide-occurrence inputs and
reference exclusion sets retain their existing validation and semantics.
Filtering and ranking¶
--filter-by and --sort-by take ranking DSL strings:
# Keep a peptide if affinity or presentation passes
topiary \
--fasta proteins.fasta \
--mhc-predictor netmhcpan \
--mhc-alleles 'HLA-A*02:01' \
--filter-by "ba <= 500 | el.rank <= 2" \
--output-csv results.csv
# Rank by a composite score from two models
topiary \
--fasta antigens.fasta \
--mhc-predictor netmhcpan mhcflurry \
--mhc-alleles 'HLA-A*02:01' \
--filter-by "ba <= 500" \
--sort-by "mean(netmhcpan:affinity.logistic(350, 150), mhcflurry:affinity.logistic(350, 150))" \
--output-csv results.csv
--ic50-cutoff, --percentile-cutoff and --presentation-cutoff are shorthand
for the common single-threshold filters. For variant runs, --predict-wt scores
each wildtype peptide too, which is what wt.* reads:
--predict-wt --sort-by "affinity.score - wt.affinity.score"
Exclusion filtering¶
Remove peptides found in reference proteomes, for tumor-specific or pathogen-specific selection:
--exclude-ensembl # source annotation's Ensembl proteome
--exclude-non-cta # non-CTA proteins (requires pirlygenes)
--exclude-tissues heart_muscle lung # genes expressed in these tissues
--exclude-fasta reference.fasta # custom reference sequences
--exclude-mode substring # "substring" (default) or "exact"
Output¶
With no output path, the CLI prints a compact preview of the first 20 prediction
rows after filtering and ranking, and reports how many rows were omitted.
--subset-output-columns and --rename-output-column also apply to this
preview. The summary on stderr counts prediction rows, unique peptide sequences,
and named alleles in those rows; several prediction kinds can give one peptide
several rows. Empty input and empty results are reported explicitly.
Explicit CSV/HTML paths save all rows and suppress the automatic preview:
--output-csv results.csv
--output-html results.html
--output-csv-sep "\t"
--subset-output-columns peptide allele affinity
--rename-output-column value ic50
--output-csv - sends every result row to stdout for a shell pipeline;
progress messages, --print-columns and the summary then go to stderr:
topiary --peptide-csv peptides.csv --mhc-predictor netmhcpan41 \
--mhc-alleles 'HLA-A*02:01' --output-csv - > results.csv
Columns¶
Every prediction has source_sequence_name, peptide, peptide_offset,
peptide_length, allele, kind, score, value, affinity,
percentile_rank and prediction_method_name.
Fragment-based predictions — predict_from_fragments and the variant-based
methods, which build fragments internally — add fragment_id, source_type,
overlaps_target, wt_peptide, wt_peptide_length, and any fragment-level
annotations flattened to columns. With --predict-wt or
TopiaryPredictor(predict_wt=True) they also add wt_value, wt_score,
wt_affinity and wt_percentile_rank.
Variant predictions add variant, gene, gene_id, transcript_id,
transcript_name, effect, effect_type, contains_mutant_residues,
mutation_start_in_peptide and mutation_end_in_peptide.
Expression data adds columns named {prefix}_{column}, such as gene_tpm — see
RNA expression.
Units follow the row's kind, which output files do not restate: value and
affinity are nM for pMHC_affinity; value and score are 0–1 for
pMHC_presentation and antigen_processing; percentile_rank is a percentage.
Saved files¶
Saved CSV/TSV and HTML files hold one row per prediction, with no index column,
so pandas.read_csv(path) and topiary's own read_csv / read_tsv read them
back as written. (Through 5.81.0 the row number was saved under the header #,
which readers that treat # as a comment — including topiary's — took for a
metadata line.)
Floats are written to six significant digits: a predictor reporting 6.296 had
been saved as 6.296000000000002. The digits past the sixth come from binary
floating point, not from the model. Values keep their decimal point, so a
reloaded measurement column is still a float.
Row order is the ranking when --sort-by is given. Otherwise it follows each
source sequence's windows in position order (peptide_offset ascending), with
source sequences in the order they first appear; a peptide list keeps its input
order. With --sort-by, an output_row column numbers the rows from 1 so the
order survives re-sorting in a spreadsheet. It is a row position in this file,
not a per-candidate rank — see rank_candidates and candidate_rank for that.
HTML output is a complete page, and a missing value is an empty cell whatever its type.
Exit status¶
| Status | Meaning |
|---|---|
| 0 | Success |
| 1 | Something topiary found after reading the command: a missing or unreadable input, an allele a predictor rejects, a broken dependency installation, a predictor that isn't set up, an output that can't be written. One topiary: error: line on stderr. |
| 2 | The command line is malformed: an unknown flag, a bad value, required flags missing or in conflict. The error follows the usage text. |
| 3 | Partial result under --cache-miss-report (see cached predictions). |
Output paths, --mhc-predictor-path and the inputs are checked before any
predictor is loaded, so these fail in the first second rather than after the
run.
Installation details¶
pip install topiary requires Python 3.11 or newer and brings in Osteosarc and
its read-extraction dependency, which supply shared source data and indexed
regional read extraction; see shared Osteosarc data.
Importing topiary does not acquire any data.
MHC predictors are installed separately and called through
mhctools: MHCflurry with
pip install mhcflurry && mhcflurry-downloads fetch, NetMHCpan and the other
DTU tools under a license from DTU Health Tech.
Variant annotation, gene lookups and SelfProteome need a local Ensembl
annotation database. Topiary uses PyEnsembl's default GRCh38 release,
which is Ensembl 115 in PyEnsembl 2.32.3:
pyensembl install --release 115 --species human
Installing some other release does not change that default — select it
explicitly with --ensembl-release or the API's release= argument. GRCh37
inputs need release 75.
The normal install includes cancer-testis antigen and tissue-expression
sources through PirlyGenes/OncoRef (--cta, --exclude-non-cta,
--exclude-tissues), RNA assembly through Isovar, and WEIRDO foreignness.
No Topiary installation extras are needed. See the
consumer guide for the Isovar version rules.
PirlyGenes 6.0.18 currently pins OncoRef 1.19.2, so the compatible installation uses that release rather than the newer OncoRef 1.21.0. Adoption of the newer owner data is tracked in PirlyGenes #655. Reference genomes, model assets and licensed executables remain explicit inputs; installing Topiary does not download them.