get_MNV

Get started

Command Line Tutorial

The command line is get_MNV's main interface: everything the tool can do is reachable from it, and it is what you put in a pipeline. This tutorial runs it end to end on the bundled M. tuberculosis example, and spends most of its time on the part that matters, reading what comes back.

There is a Desktop GUI Tutorial covering the same ground in the app.

1. Get the example data

The example/ folder of the repository ships everything you need:

FileRole
MTB_ancestor.fasReference (single contig MTB_anc)
anot_genes.txtGene table (name, start, end, strand, and for its RNA genes phase and biotype)
G35894.var.snp.vcfVarScan-style variant calls
G35894.demo.bamTiny aligned-read subset for read support
git clone https://github.com/PathoGenOmics-Lab/get_MNV.git
cd get_MNV/example

2. Annotate the variants

get_mnv \
  --vcf G35894.var.snp.vcf \
  --fasta MTB_ancestor.fas \
  --genes anot_genes.txt

get_MNV logs what it decided before it logs what it found. The run prints its whole configuration, then the lines that matter:

[INFO get_mnv::pipeline] Using genetic code: Bacterial/Archaeal/Plant Plastid (NCBI table 11)
[INFO get_mnv::io::annotation::tsv] TSV gene entries parsed: 4008 | mapped to SNPs: 635 | without SNPs: 3373
[INFO get_mnv::pipeline::processing] Contig 'MTB_anc' -> 950 SNP/variant records in VCF, 635 mapped genes
[INFO get_mnv::pipeline::processing] Contig 'MTB_anc' -> 134 intergenic variant(s) added
[INFO get_mnv::pipeline] Summary 'MTB_anc' -> variants=941 (SNP=797, MNV=0, SNP/MNV=10, INDEL=0, intergenic=134)
[INFO get_mnv::pipeline] Processing complete. Output files generated successfully.

It writes G35894.var.snp.MNV.tsv in the current directory.

Read the summary line, every time

950 records became 941 variants because a codon carrying two substitutions is reported once. SNP/MNV=10 is the codon-level work: ten codons where separate VCF records combine. MNV=0 means no single record already carried more than one substituted base.

intergenic=134 is your sanity check on the annotation. get_MNV cannot tell a variant outside a gene from a variant whose gene it failed to find, so a mismatched annotation does not fail: it succeeds, reports almost everything as intergenic, and prints Processing complete. If that count is most of your variants, your gene coordinates do not line up with your reference.

Genetic code

get_MNV defaults to NCBI translation table 11 (bacterial), which is correct for M. tuberculosis. Use --translation-table for other organisms.

Use --dry-run to get the same summary with nothing written, which is the cheap way to check inputs before a long run.

3. Read the output

Open the TSV. One row stands out: gene Rv2036 carries two SNVs in the same codon.

ColumnValue
Positions2282376, 2282377
Reference Bases / Base ChangesT, T → C, C
Reference CodonGTT
SNP CodonGCT, GTC
MNV CodonGCC
AA ChangesVal93Ala
SNP AA ChangesVal93Ala, Val93Val
Variant TypeSNP/MNV
SO Term / Impactmissense_variant / MODERATE
HGVS g.g.[2282376T>C;2282377T>C]

Read one base at a time, the two substitutions disagree: GCT is Val93Ala and GTC is Val93Val, a silent change. Read together as GCC, the codon is a single Val→Ala substitution. That reclassification is what get_MNV is for, and it is invisible to a per-SNV annotator. See Output Formats for every column.

4. Add read support

Annotation says what the codon would mean. It does not say whether any single molecule carries both changes. For that, give get_MNV the alignments:

get_mnv \
  --vcf G35894.var.snp.vcf \
  --fasta MTB_ancestor.fas \
  --genes anot_genes.txt \
  --bam G35894.demo.bam

The Rv2036 row gains its evidence columns:

ColumnValueMeaning
MNV Reads24reads carrying the whole haplotype
MNV Forward Reads12balanced across strands
MNV Reverse Reads12the other half of the same balance
Total Reads24depth at the codon
MNV Frequencies1.0000every read spanning it carries both
SNP Reads0, 0reads carrying one change without the other
MNV Phasing Support1.0000of the reads that could answer, all carried both
MNV Phasing Reads24how many reads answered
Haplotype LD-see below

SNP Reads = 0, 0 next to MNV Reads = 24 is not a gap: the two columns split the evidence instead of double-counting it. No read carries one substitution alone, so nothing lands in the solo counts.

Why Haplotype LD is empty on a perfect haplotype

D' measures whether two variants co-occur more than their own frequencies predict. Here both are on all 24 molecules, so neither varies and there is nothing left to correlate: the honest answer is -, not 1. That is a different question from MNV Phasing Support, which asks how many of the reads that could answer carried the whole haplotype, and answers 1.0000. Linkage works through the cases where they diverge.

BAM requirements

The BAM must be coordinate-sorted and indexed (.bai), and aligned to the same reference. The bundled G35894.demo.bam covers only the Rv2036 locus, which is why every other row reports no read support.

5. Filter on that support

With a BAM you can require evidence. The thing to know before you do is how the two thresholds combine on a codon-level row:

CommandRowsWhat happened
(no filter)941everything
--snp 110every plain SNP row without a supporting read is gone; the 10 codon-level rows stay
--mnv 5941nothing happens
--snp 1 --mnv 51only Rv2036, the one codon with reads

A SNP/MNV row is kept when either its individual SNVs clear --snp or its haplotype clears --mnv. That is deliberate, so a well-supported haplotype survives even when its individual SNVs do not. The consequence is easy to trip over: with --snp left at its default of 0, the SNP side passes trivially, so --mnv on its own never removes a row. Raise both, or neither.

6. Get a report you can send

The same run writes a single self-contained HTML file:

get_mnv \
  --vcf G35894.var.snp.vcf \
  --fasta MTB_ancestor.fas \
  --genes anot_genes.txt \
  --bam G35894.demo.bam \
  --report sample.html

The interactive HTML report get_MNV writes: summary counts, consequence breakdown, search and a variant matrix The interactive HTML report get_MNV writes: summary counts, consequence breakdown, search and a variant matrix

The report opens in any browser with no server and travels as one attachment. It records the exact command that produced it along the top.

It is searchable and filterable, breaks the calls down by Sequence Ontology term (here 476 missense, 320 synonymous, 134 intergenic, 10 stop gained, 1 stop lost), and draws a variant matrix across the contig. For a cohort already processed one sample per run, build one report from the existing outputs with --report-from run1.MNV.tsv run2.MNV.tsv --report cohort.html.

7. The other things it can write

FlagOutput
--convert / --bothVCF instead of, or alongside, the TSV
--vcf-gz / --index-vcf-gzBGZF-compressed VCF and its Tabix index
--bcfBCF converted from the generated VCF
--summary-json <FILE>the summary above, machine-readable
--run-manifest <FILE>command, version, inputs, outputs and checksums
--error-json <FILE>structured error details when a run fails

Next steps

Edit this page on GitHub