NANOVAR

https://img.shields.io/badge/wrapper_version-v9.16.0-10785b https://img.shields.io/github/issues-pr/snakemake/snakemake-wrappers/bio/nanovar?label=version%20update%20pull%20requests&color=1cb481

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.3

  • snakemake-wrapper-utils=0.9.0

Input/Output

Input:

  • reads: long-read FASTA/FASTQ or aligned BAM/CRAM

  • ref: reference genome FASTA

  • bed: BED of regions to filter out (optional)

Output:

  • vcf: VCF of PASS structural variants

  • report: 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>).

Authors

  • Kateřina Havlová

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}")