NANOVAR
Call structural variants from long reads with NanoVar.
URL: https://github.com/cytham/nanovar
Example
This wrapper can be used in the following way:
rule nanovar:
input:
reads="reads.fq.gz",
ref="genome.fasta",
output:
vcf="calls/a.vcf",
report="calls/a.report.html",
log:
"logs/a.log",
threads: 4
params:
extra="", # optional parameters for nanovar (except -t/-f/positional args)
wrapper:
"v9.16.0/bio/nanovar"
# Same wrapper without a `report` output — exercises the optional-report skip path.
rule nanovar_no_report:
input:
reads="reads.fq.gz",
ref="genome.fasta",
output:
vcf="calls/b.vcf",
log:
"logs/b.log",
threads: 4
params:
extra="", # optional parameters for nanovar (except -t/-f/positional args)
wrapper:
"v9.16.0/bio/nanovar"
Note that input, output and log file paths can be chosen freely.
When running with
snakemake --use-conda
the software dependencies will be automatically deployed into an isolated environment before execution.
Software dependencies
nanovar=1.8.3snakemake-wrapper-utils=0.9.0
Input/Output
Input:
reads: long-read FASTA/FASTQ or aligned BAM/CRAMref: reference genome FASTAbed: BED of regions to filter out (optional)
Output:
vcf: VCF of PASS structural variantsreport: NanoVar HTML summary report (optional)
Params
extra: additional arguments (e.g. -x ont, -l <min SV length>, -c <min coverage>, -s <score>, or -f <built-in genome name>).
Code
__author__ = "Kateřina Havlová"
__copyright__ = "Copyright 2026, Kateřina Havlová"
__email__ = "katkahemalova@gmail.com"
__license__ = "MIT"
import shlex
import tempfile
from pathlib import Path
from snakemake.shell import shell
from snakemake_wrapper_utils.snakemake import move_files
extra = snakemake.params.get("extra", "")
log = snakemake.log_fmt_shell(stdout=True, stderr=True)
# Optional gap/filter BED (-f). Built-in names (hg19/hg38/mm10) can go via extra.
bed = snakemake.input.get("bed", "")
if bed:
bed = f"-f {shlex.quote(bed)}"
# NanoVar writes several files into a working directory, naming them after the
# input (e.g. <sample>.nanovar.pass.vcf). Run it in a temporary directory, then
# move the requested outputs to their declared paths.
with tempfile.TemporaryDirectory() as workdir:
shell(
"nanovar"
" -t {snakemake.threads}"
" {bed}"
" {extra}"
" {snakemake.input.reads:q}"
" {snakemake.input.ref:q}"
" {workdir:q}"
" {log}"
)
# NanoVar names the VCF after the input file, mirroring its own logic
# (src/nanovar/nanovar.py): strip .bam/.cram, or for reads split off ".f".
name = Path(snakemake.input.reads).name
if name.endswith(".bam"):
prefix = name.rsplit(".bam", 1)[0]
elif name.endswith(".cram"):
prefix = name.rsplit(".cram", 1)[0]
else:
prefix = name.rsplit(".f", 1)[0]
mapping = {"vcf": Path(workdir) / f"{prefix}.nanovar.pass.vcf"}
# Optional HTML report (same prefix) — only rescued if the user declares it.
if snakemake.output.get("report"):
mapping["report"] = Path(workdir) / f"{prefix}.nanovar.pass.report.html"
log = snakemake.log_fmt_shell(stdout=True, stderr=True, append=True)
for move_cmd in move_files(snakemake, mapping):
shell("{move_cmd} {log}")