| name | bio-workflows-neoantigen-pipeline |
| description | Orchestrates neoantigen discovery from somatic variants to ranked vaccine candidates, chaining HLA typing (OptiType/arcasHLA + LOHHLA), VEP annotation (Wildtype+Frameshift plugins) + expression/readcount annotation, proximal-variant phasing, pVACseq MHC-I/II binding, CCF/clonality, and immunogenicity/quality ranking. Use when recognizing that binding is single-digit PPV and the critical steps are downstream (full-resolution HLA + LOH gating, proximal-variant phasing, clonality from purity+CN not raw VAF, expression), sequencing normalize+annotate -> phase -> HLA -> binding -> quality in the defensible order, dropping candidates on LOH-lost alleles, supplying --phased-proximal-variants-vcf so the mutant peptide is real, or ranking WITHIN patient rather than a fixed IC50 threshold. Hands mechanism to the immunoinformatics component skills; not a re-teach of any single step. |
| tool_type | mixed |
| primary_tool | pVACtools |
| goal_approach_exempt | true |
| workflow | true |
| depends_on | ["clinical-databases/hla-typing","immunoinformatics/mhc-binding-prediction","immunoinformatics/mhc-class-ii-prediction","immunoinformatics/neoantigen-prediction","immunoinformatics/immunogenicity-scoring","immunoinformatics/epitope-prediction"] |
| qc_checkpoints | [{"after_hla":"HLA types resolved to 4-digit, coverage adequate"},{"after_binding":"Predictions for ALL alleles (LOH-lost alleles dropped); ranked within patient, not hard-thresholded across patients"},{"after_neoantigen":"Expressed (RNA-confirmed); clonality via CCF from purity+CN, not raw VAF"},{"after_scoring":"Top candidates are a tier-1 hypothesis list for MS + T-cell validation"}] |
Version Compatibility
Reference examples tested with: Ensembl VEP 111+, pVACtools 4.1+ (Frameshift plugin REPLACED the legacy Downstream in 2.0+), MHCflurry 2.1+, NetMHCpan 4.1, OptiType 1.3+ / arcasHLA, LOHHLA, WhatsHap 2.0+ (phasing), matplotlib 3.8+, numpy 1.26+, pandas 2.2+, seaborn 0.13+
Before using code patterns, verify installed versions match. If versions differ:
- Python:
pip show <package> then help(module.function) to check signatures
- CLI:
<tool> --version then <tool> --help to confirm flags
If code throws ImportError, AttributeError, or TypeError, introspect the installed
package and adapt the example to match the actual API rather than retrying.
Neoantigen Pipeline
"Predict neoantigens from my tumor sequencing data" -> Orchestrate HLA typing (OptiType), somatic variant calling, pVACtools neoantigen prediction, MHC binding scoring, and immunogenicity-based candidate ranking for personalized cancer immunotherapy.
Complete workflow from somatic variants to ranked neoantigen vaccine candidates for personalized cancer immunotherapy.
Key Judgment -- binding is the easy part; PPV lives downstream
A binding-only pipeline has single-digit-percent positive predictive value (TESLA; Wells 2020 Cell 183:818). The critical steps are downstream of binding: correct full-resolution HLA typing (wrong allele = confident garbage), HLA loss-of-heterozygosity (run LOHHLA and DROP candidates on a lost allele — it invalidates predictions silently), proximal-variant phasing (supply --phased-proximal-variants-vcf or the mutant peptide is wrong), cancer cell fraction for clonality (clonal beats subclonal; use purity + copy number, not raw VAF), expression, and quality features (agretopicity, foreignness). Treat the ranked output as a tier-1 hypothesis list for immunopeptidomics MS and functional T-cell validation, not a final answer. Add MHC class II (CD4) neoantigens for vaccine help (see immunoinformatics/mhc-class-ii-prediction). Note on DAI below: agretopicity is most often the WT/MT binding ratio; whichever form is used, an anchor-position mutation inflates it without changing the TCR-facing surface, and a barely-presented WT makes it unstable — pair it with anchor evaluation.
Made-once commitments
| Commitment | Consequence inherited downstream |
|---|
| HLA typing at full 4-digit resolution (class I + II) | A wrong allele is confident garbage; every binding prediction inherits it; reconcile DNA vs RNA calls |
| Variant source + somatic caller (matched-normal preferred) | Tumor-only calling leaks germline; indels/frameshifts are disproportionately valuable; expression must be RNA-confirmed and annotated INTO the VCF |
| Proximal-variant phasing | Without it the mutant peptide is one the tumor never makes; germline SNPs in cis are especially treacherous |
| HLA-LOH gate | Candidates on a lost allele are silently invalid (~17% pan-cancer, 30%+ HNSCC/NSCLC/cervical) |
The canonical order and why
Somatic PASS calls -> normalize + VEP-annotate (Wildtype + Frameshift plugins) -> annotate expression + DNA/RNA readcounts INTO the VCF -> PHASE proximal variants -> HLA typing + LOHHLA -> MHC binding -> clonality (CCF from purity+CN) -> quality features -> tier/rank -> pVACview review.
- Order-trap 1 - normalize + annotate with the RIGHT plugins BEFORE pVACseq. pVACseq needs the Wildtype plugin (matched WT peptide -> agretopicity) and the Frameshift plugin (novel ORF); Frameshift REPLACED the legacy Downstream in pVACtools 2.0+. Normalize before annotate.
- Order-trap 2 - PHASE proximal variants BEFORE translating the mutant peptide. THE review-sinker: editing variants independently yields a peptide the patient never makes. Merge somatic+germline, phase (WhatsHap/GATK), supply
--phased-proximal-variants-vcf.
- Order-trap 3 - HLA typing (+ LOHHLA) BEFORE binding. Binding is per-allele; a wrong or lost allele makes every downstream prediction garbage. Drop LOH-lost alleles before ranking.
- Order-trap 4 - CCF/clonality from purity+copy-number BEFORE calling something subclonal. Low purity makes clonal look subclonal; correct VAF to cancer-cell fraction (copy-number/allele-specific-copy-number). Clonal beats subclonal.
- Order-trap 5 - rank WITHIN patient; do NOT hard-threshold IC50 across patients. Immunogenicity scores are relative.
Workflow Overview
Somatic VCF (annotated) + Tumor RNA-seq (optional)
|
v
[1. HLA Typing] --> arcasHLA / OptiType (if types not provided)
|
v
[2. MHC Binding Prediction] --> MHCflurry / NetMHCpan
|
v
[3. Neoantigen Calling] --> pVACseq
|
v
[4. Immunogenicity Scoring] --> Multi-factor ranking
|
v
Ranked Vaccine Candidates (TSV + visualizations)
Prerequisites (Ensembl VEP 111+)
pip install pvactools mhcflurry vatools
mhcflurry-downloads fetch
conda install -c bioconda ensembl-vep arcas-hla optitype
Primary Path: pVACseq Pipeline
Step 1: HLA Typing (if not provided)
HLA types are critical for MHC binding prediction. If not already known from clinical testing:
arcasHLA extract tumor.bam -t 8 -o hla_output/
arcasHLA genotype hla_output/tumor.extracted.1.fq.gz hla_output/tumor.extracted.2.fq.gz \
-g A,B,C,DRB1,DQB1,DQA1,DPB1,DPA1 -t 8 -o hla_output/
cat hla_output/tumor.genotype.json
import json
with open('hla_output/tumor.genotype.json') as f:
hla_data = json.load(f)
hla_alleles = []
for gene, alleles in hla_data.items():
for allele in alleles:
hla_alleles.append('HLA-' + ':'.join(allele.split(':')[:2]))
hla_string = ','.join(hla_alleles)
print(f'HLA alleles: {hla_string}')
Step 2: VCF Annotation with VEP
pVACseq requires VEP-annotated VCF with specific fields:
vep --input_file somatic.vcf \
--output_file somatic.vep.vcf \
--format vcf --vcf --symbol --terms SO \
--plugin Frameshift --plugin Wildtype \
--offline --cache \
--pick --fork 4
vcf-expression-annotator somatic.vep.vcf \
expression.tsv custom gene \
-s tumor_sample --id-column gene_id --expression-column tpm \
-o somatic.vep.expression.vcf
whatshap phase -o phased.vcf.gz --reference reference.fa somatic_plus_germline.vcf.gz tumor.bam
tabix -p vcf phased.vcf.gz
Step 3: Run pVACseq (Ensembl VEP 111+)
pvacseq run \
somatic.vep.vcf \
tumor_sample \
"HLA-A*02:01,HLA-A*24:02,HLA-B*07:02,HLA-B*44:02,HLA-C*07:02,HLA-C*05:01" \
MHCflurry MHCnuggetsI NetMHCpan \
pvacseq_output/ \
-e1 8,9,10,11 \
--iedb-install-directory /path/to/iedb \
-t 8
pvacseq run \
somatic.vep.expression.vcf \
tumor_sample \
"HLA-A*02:01,HLA-A*24:02,HLA-B*07:02,HLA-B*44:02" \
MHCflurry NetMHCpan \
pvacseq_output/ \
-e1 8,9,10,11 \
--phased-proximal-variants-vcf phased.vcf.gz \
--tumor-purity 0.7 \
--tdna-vaf 0.1 \
--expn-val 1 \
-t 8
Drop candidates on HLA-LOH-lost alleles (run LOHHLA/DASH) BEFORE ranking, and correct clonality to cancer-cell fraction (CCF from purity + copy number, not raw VAF; see copy-number/allele-specific-copy-number) — the raw-VAF filter below is a coarse proxy.
Step 4: Filter and Rank Candidates
import pandas as pd
import numpy as np
results = pd.read_csv('pvacseq_output/MHC_Class_I/tumor_sample.filtered.tsv', sep='\t')
strong_binders = results[results['Median MT IC50 Score'] < 500].copy()
strong_binders['DAI'] = strong_binders['Median WT IC50 Score'] / strong_binders['Median MT IC50 Score']
if 'Gene Expression' in strong_binders.columns:
strong_binders = strong_binders[strong_binders['Gene Expression'] > 1]
strong_binders = strong_binders[strong_binders['Tumor DNA VAF'] > 0.1]
def immunogenicity_score(row):
score = 0
if row['Median MT IC50 Score'] < 150:
score += 3
elif row['Median MT IC50 Score'] < 500:
score += 2
if row['DAI'] > 10:
score += 2
elif row['DAI'] > 2:
score += 1
if row['Tumor DNA VAF'] > 0.3:
score += 2
elif row['Tumor DNA VAF'] > 0.15:
score += 1
if 'Gene Expression' in row.index and row['Gene Expression'] > 10:
score += 1
return score
strong_binders['Immunogenicity Score'] = strong_binders.apply(immunogenicity_score, axis=1)
ranked = strong_binders.sort_values('Immunogenicity Score', ascending=False)
top_candidates = ranked.head(20)
top_candidates.to_csv('top_neoantigen_candidates.tsv', sep='\t', index=False)
print(f'Total strong binders: {len(strong_binders)}')
print(f'Top 20 candidates exported')
print(ranked[['Gene Name', 'MT Epitope Seq', 'HLA Allele', 'Median MT IC50 Score', 'DAI', 'Immunogenicity Score']].head(10))
Step 5: MHC Class II Neoantigens (CD4+ T cell help)
pvacseq run \
somatic.vep.vcf \
tumor_sample \
"DRB1*01:01,DRB1*07:01,DQA1*05:01-DQB1*02:01,DQA1*03:01-DQB1*03:01" \
MHCnuggetsII NetMHCIIpan \
pvacseq_class2_output/ \
-e2 15 \
--iedb-install-directory /path/to/iedb \
-t 8
Alternative: Standalone MHCflurry
For quick binding predictions without full pVACseq pipeline:
from mhcflurry import Class1PresentationPredictor
predictor = Class1PresentationPredictor.load()
peptides = ['SIINFEKL', 'GILGFVFTL', 'NLVPMVATV']
alleles = ['HLA-A*02:01', 'HLA-B*07:02']
results = predictor.predict(peptides=peptides, alleles=alleles,
include_affinity_percentile=True, verbose=0)
print(results[['peptide', 'best_allele', 'presentation_score', 'affinity', 'affinity_percentile']])
Visualization
import matplotlib.pyplot as plt
import seaborn as sns
fig, axes = plt.subplots(1, 3, figsize=(15, 5))
ax1 = axes[0]
ax1.hist(ranked['Median MT IC50 Score'], bins=50, edgecolor='black')
ax1.axvline(500, color='red', linestyle='--', label='500nM threshold')
ax1.set_xlabel('Median MT IC50 (nM)')
ax1.set_ylabel('Count')
ax1.set_title('Binding Affinity Distribution')
ax1.legend()
ax2 = axes[1]
scatter = ax2.scatter(ranked['Median MT IC50 Score'], ranked['DAI'],
c=ranked['Immunogenicity Score'], cmap='viridis', alpha=0.7)
ax2.set_xlabel('MT IC50 (nM)')
ax2.set_ylabel('Differential Agretopicity Index')
ax2.set_title('Tumor Specificity vs Binding')
plt.colorbar(scatter, ax=ax2, label='Immunogenicity Score')
ax3 = axes[2]
gene_counts = ranked['Gene Name'].value_counts().head(15)
gene_counts.plot(kind='barh', ax=ax3)
ax3.set_xlabel('Number of Neoantigens')
ax3.set_title('Top Genes with Neoantigens')
plt.tight_layout()
plt.savefig('neoantigen_summary.pdf')
Parameter Recommendations
| Step | Parameter | Value | Rationale |
|---|
| pVACseq | -e1 | 8,9,10,11 | MHC-I binds 8-11mer peptides |
| pVACseq | -e2 | 15 | MHC-II binds 13-25mer, 15 is core |
| Filtering | IC50 | <500nM | Standard strong binder threshold |
| Filtering | VAF | >0.1 | Ensures clonal representation |
| Filtering | Expression | >1 TPM | Detectable transcription |
| Ranking | DAI (WT/MT IC50 ratio) | >2 moderate, >10 strong | MT binds better than WT (>1); higher = more tumor-specific |
Common Errors
| Symptom | Cause | Fix |
|---|
| Peptides the tumor never makes | Proximal variants edited independently (unphased) | --phased-proximal-variants-vcf (WhatsHap/GATK); include germline in cis |
| Frameshift ORFs lost / no agretopicity | Wrong/legacy VEP plugin (Downstream instead of Frameshift; missing Wildtype) | pvacseq install_vep_plugin; run --plugin Wildtype --plugin Frameshift |
| Confident but invalid predictions | HLA allele wrong or on a LOH-lost haplotype | Full 4-digit typing + LOHHLA drop before ranking |
--expn-val/VAF filters silently pass everything | Expression/readcounts not annotated into the VCF | vcf-expression-annotator + vcf-readcount-annotator before pVACseq |
| Clonal candidate mis-tiered subclonal | Raw VAF used as clonality on a low-purity tumor | CCF from purity + copy number (copy-number/allele-specific-copy-number) |
| Candidates mis-ranked across patients | Fixed IC50 threshold applied cross-patient | Rank WITHIN patient (immunoinformatics/immunogenicity-scoring) |
| No neoantigens found | Low mutation burden | Lower IC50 threshold to 1000nM; check TMB/MSI first |
References
- Hundal J, Kiwala S, Feng YY, et al (2020) pVACtools: a computational toolkit to identify and visualize cancer neoantigens. Cancer Immunology Research 8:409-420. DOI 10.1158/2326-6066.CIR-19-0401.
- Wells DK, van Buuren MM, Dang KK, et al (2020) Key parameters of tumor epitope immunogenicity revealed through a consortium approach improve neoantigen prediction (TESLA). Cell 183:818-834. DOI 10.1016/j.cell.2020.09.015. (single-digit PPV of binding-only.)
- McGranahan N, Rosenthal R, Hiley CT, et al (2017) Allele-specific HLA loss and immune escape in lung cancer evolution. Cell 171:1259-1271. DOI 10.1016/j.cell.2017.10.001. (LOHHLA.)
- Wood MA, Nguyen A, Struck AJ, et al (2020) neoepiscope improves neoepitope prediction with multivariant phasing. Bioinformatics 36:713-720. DOI 10.1093/bioinformatics/btz653. (phasing matters.)
Output Files
| File | Description |
|---|
*.filtered.tsv | pVACseq filtered neoantigens |
*.all_epitopes.tsv | All predicted epitopes |
top_neoantigen_candidates.tsv | Ranked vaccine candidates |
neoantigen_summary.pdf | Visualization figures |
Related Skills
- immunoinformatics/mhc-binding-prediction - MHCflurry parameters; BA vs EL, %Rank vs nM, abundance bias
- immunoinformatics/mhc-class-ii-prediction - class II (CD4) neoantigens for vaccine help
- immunoinformatics/neoantigen-prediction - pVACtools details; LOHHLA, phasing, clonality
- immunoinformatics/immunogenicity-scoring - rank within patient (don't threshold); fitness-model quality
- immunoinformatics/epitope-prediction - B-cell epitopes
- clinical-databases/hla-typing - HLA typing (T1K is the 2024-2026 all-rounder; OptiType for class I; arcasHLA for RNA-seq); check HLA-LOH via LOHHLA / DASH which abolishes neoantigen presentation in ~17% pan-cancer (~30%+ HNSCC / NSCLC / cervical)
- clinical-databases/tumor-mutational-burden - TMB-H pan-tumor ICI biomarker; check before neoantigen-vaccine candidate selection
- clinical-databases/msi-detection - MSI-H / dMMR pan-tumor ICI biomarker; MSI-H supersedes TMB-H per Sha 2020
- clinical-databases/somatic-signatures - Clonal neoantigen burden (McGranahan 2016 Science) predicts ICI response better than total TMB
- workflows/somatic-variant-pipeline - Upstream somatic calling