get_MNV

How it works

Scope and Compatibility

What get_MNV takes responsibility for when it annotates indels and MNVs, what it leaves to your variant caller, and where its limits are.

get_MNV is a variant annotator and haplotype summarizer for existing variant calls. It does not replace a variant caller: the input VCF or iVar TSV is still responsible for deciding which alleles exist. When a BAM is provided, get_MNV uses read evidence to count support and to emit exact combined indel/SNV/MNV haplotypes that are observed on the same reads.

For how an indel is read off the alignments, what each output number counts, and how local haplotypes are discovered and reported, see Indels and Local Haplotypes. For whether a haplotype's variants genuinely travel together, see Linkage.

Caller Compatibility

Different callers can represent the same local haplotype in different ways. For example, FreeBayes is haplotype-based and can emit SNPs, indels, MNPs and complex events as raw haplotype calls. Its own documentation recommends decomposing those calls after calling if primitive SNP/indel records are needed.

bcftools norm handles the other side of the problem: it can left-align and normalize indels with a FASTA reference, split multiallelic sites, and atomize complex variants or MNVs into simpler records. That normalization step is useful before comparing callsets from different callers.

GATK HaplotypeCaller is a caller, not an annotator. It uses local assembly and genotyping parameters such as sample ploidy, maximum haplotypes, and MNP merge distance. get_MNV currently does not perform this de novo haplotype discovery or genotype likelihood modelling.

Left-Alignment

An insertion or deletion inside a homopolymer or a tandem repeat can be written at any of several positions that all describe the same change: deleting one GCT from GCTGCTGCT removes the first copy, the second or the third. Aligners put the gap at the leftmost of them, and get_MNV counts an indel's read support from reads whose CIGAR carries that exact gap, so an allele written further right finds no supporting reads at all. A VCF written from a 3'-shifted HGVS description, or by a caller that places indels its own way, does exactly that.

--left-align moves each indel to its leftmost equivalent position against the --fasta reference before anything else reads it, which is the normalization bcftools norm -f ref.fa performs:

The protein change and the HGVS descriptions do not depend on where the record was written, since HGVS places an indel at its 3'-most position whatever the input says. What moves is Positions, Reference Bases, Base Changes, Event Components, the output VCF record and, with them, the read support. Left-alignment helps that support only where the aligner left-aligned the gaps, which most aligners do; when the reads place a gap somewhere else, the warning about spanning reads without exact support says so.

It is off by default, on the command line and in the desktop app. The one deliberate difference from bcftools is an ambiguity code in the reference: bcftools reads R as A, moves an indel through it and writes that A into REF, which then disagrees with the FASTA, where get_MNV stops the indel at the R. The tests/leftalign suite runs both tools on thousands of indels and complex records placed at random in the repeats of the bundled genome, spelled in several ways, and requires the same record from each.

What get_MNV Adds

Boundary Rules

VCF insertions are interbase events anchored on the previous reference base. An insertion is treated as overlapping a feature only when the inserted sequence falls between two reference bases inside that feature. An insertion anchored at the final feature base is outside that feature.

VCF deletions are anchored, but their biological effect is the deleted reference span. A deletion anchored just before a CDS/gene still affects that feature if the deleted bases overlap it.

A deletion that runs from the bases before the start codon into the gene is read at its 3'-most place along the transcript, within the first exon, as HGVS places it. A deletion in a repeat can be written at several places, and left-aligned, as --left-align and bcftools norm write it, deleting the second ATG of a gene that starts ATGATG right after a G begins on that G; read where it is written, it would keep only two coding bases and come out a frameshift. Placed 3'-most it lies inside the gene and reads Met2del, with the same codons and c. as the same deletion written there. One that still reaches the base before the start codon in that place loses the start. The row keeps the record as written.

An insertion or deletion that can be placed wholly outside the protein changes no coding base and is not the gene's: it is reported as the bases outside the gene are, intergenic, however its record is written. At the stop codon that place is its 3'-most along the transcript, as HGVS places it. A run of As that begins in a TAA is the usual case: one A fewer, left-aligned onto the stop codon, would otherwise read as a frameshift at the protein's last residue, while the stop codon is there either way. A deletion that still removes stop-codon bases in its 3'-most place is read as written, and a coding sequence that does not end on a codon boundary, as a CDS row ending at an exon edge mid-codon does, has no stop codon to move past. At the start codon the place is its 5'-most along the transcript: one A fewer or one more in a run of As that ends in the A of an ATG leaves an ATG where the ribosome finds it, and the same protein behind it, though HGVS writes the change on the start codon (c.1del, c.1dup). One that puts an initiation codon where the start codon began, as a copy of the protein's first bases does, stays the gene's: the ribosome reads the copy.

Neither end moves an indel past a base another record changes on the same molecules, which would describe another haplotype. Records are taken to share the indel's molecules unless they say otherwise: two indel alleles of one site, as a split multiallelic record leaves them, are alternatives; a caller can phase two records apart; and a record whose frequency is under half the indel's is missing from most of the molecules that carry it. A phased haplotype holding an indel that lies outside the protein is not reported as a haplotype of its own, since its other variants' rows already say what it does to the protein. A complex record that writes such an indel together with a substitution in one line is still read as one change.

When an MNV row overlaps an indel, get_MNV keeps the MNV row as positional context and marks its amino-acid effect as Unknown with Change Type = Indel overlap. If the BAM supports the full combined event, get_MNV emits a separate exact complex_indel row.

Exact support for complex indels is CIGAR-aware. A read must produce the same local ALT sequence and contain the expected insertion/deletion components. This matters for net-neutral combinations, where an insertion plus a deletion can produce the same sequence as a simple MNV under another alignment.

Eukaryotic CDS Notes

For eukaryotic GFF/GTF annotations, use --gff-features CDS so get_MNV can use GFF phase and transcript identifiers. When CDS rows carry transcript_id or Parent, get_MNV builds a spliced CDS model for each transcript and evaluates codon grouping, MNV amino-acid effects, and indel frameshift context on that full coding sequence.

This means codons split across exon junctions can be annotated as one transcript-level MNV, and downstream SNPs are marked as frameshifted only when the net upstream coding indel shift remains out of frame. CDS rows without a usable transcript identifier keep the older per-feature behavior.

Current Limits

Tuning Knobs

These flags change indel-aware behaviour. Two of them no longer default to the tool's original behaviour, because that behaviour was wrong more often than it was right: the frame shift propagates only from a majority upstream indel, and indel locus depth is counted from the anchor base.

When an indel that has read coverage produces zero exact-CIGAR support, get_MNV emits a warning: this usually means the input indel is not left-aligned the same way as the BAM (common in homopolymers/tandem repeats). Rerun with --left-align, or normalize the input first with bcftools norm -f ref.fa, so the allele matches the read alignment. If the warning stays with --left-align, the reads place the gap elsewhere or do not carry the indel.

References

Edit this page on GitHub