Skip to main content

BamNado

High-performance tools and utilities for working with BAM and BigWig files in modern genomics workflows. BamNado is written in Rust for speed and low memory use and provides both a command-line interface and Python bindings.

Overview

BamNado is designed for efficient, streaming manipulation of BAM files and signal tracks. It focuses on fast coverage generation, flexible filtering, and lightweight post-processing of bedGraph and BigWig data.

Common use cases:

  • Rapid generation of coverage tracks from large BAM files
  • Filtering reads by tags or barcodes to produce targeted BigWigs
  • Fragment-aware coverage for ATAC-seq and related assays
  • BigWig comparison and aggregation across samples
  • Post-processing of binned signal tracks for visualization

Useful in workflows including single-cell and Micro-Capture-C (MCC), and many others.

Documentation: API docs on docs.rs

Features

  • High-performance, streaming implementations in Rust
  • Cross-platform support (Linux, macOS, Windows)
  • BAM → bedGraph / BigWig coverage generation
  • Fragment-aware and strand-specific pileups
  • Read filtering by mapping quality, length, strand, fragment size, tags, and barcodes
  • BigWig comparison (subtraction, ratio, log-ratio)
  • BigWig aggregation (sum, mean, median, min, max)
  • bedGraph post-processing with collapse-bedgraph
  • Python bindings for selected functionality

Installation

Pre-built binaries (recommended)

Download the appropriate binary from the releases page.

After downloading, move to your user bin directory (no root required):

chmod +x bamnado
mv bamnado ~/.local/bin/bamnado

Ensure ~/.local/bin is on your PATH (add to ~/.bashrc or ~/.zshrc if needed):

export PATH="$HOME/.local/bin:$PATH"

Alternatively, you can run the binary directly from the download location:

./bamnado --help

cargo binstall

If you have cargo-binstall installed, this downloads the pre-built binary automatically:

cargo binstall bamnado

Docker

docker pull ghcr.io/alsmith151/bamnado:latest
docker run --rm ghcr.io/alsmith151/bamnado:latest --help

Images are available for linux/amd64 and linux/arm64.

Cargo

If you have Rust installed:

cargo install bamnado

Build from source

git clone https://github.com/alsmith151/BamNado.git
cd BamNado
cargo build --release

Optional dependency: samtools

samtools is not required but is strongly recommended if your BAM files have non-standard or incomplete headers (e.g. files produced by CellRanger). BamNado automatically falls back to samtools view -H to parse the header when the built-in parser fails. Without samtools on your PATH, BamNado will error on such files.

Install via conda or your system package manager:

conda install -c bioconda samtools
# or
brew install samtools

Command-line interface

Getting help

bamnado --help                      # List all commands
bamnado <command> --help            # Help for a specific command

Available commands

Command Aliases Description
bam-coverage coverage BAM → bedGraph / BigWig coverage
multi-bam-coverage multi-coverage Merge coverage from multiple BAM files into one track
split Split BAM by tag or barcode
split-exogenous split-spikein Split BAM into endogenous / exogenous reads
modify Filter and/or adjust reads in a BAM file
bigwig-compare compare-bigwigs Compare two BigWig files bin by bin
bigwig-aggregate aggregate-bigwigs Aggregate multiple BigWig files into one track
bigwig-infer-scale infer-scale Infer scaling factor and library size from a normalised BigWig
bam-normalize norm-factors Compute between-sample scaling factors from BAM files
collapse-bedgraph collapse Collapse adjacent equal-score bins in a bedGraph

Read filtering

All coverage commands share common read filter flags:

Flag Default Description
--strand both forward, reverse, or both
--proper-pairs off Keep only properly-paired reads
--min-mapq 20 Minimum mapping quality
--min-length 20 Minimum read length (bp)
--max-length 1000 Maximum read length (bp)
--min-fragment-len Minimum insert size (bp); paired-end only
--max-fragment-len Maximum insert size (bp); paired-end only
--blacklist BED file of regions to exclude
--barcode-allowlist Text file of cell barcodes (one per line)
--read-group Keep only this read group
--tag / --tag-value Keep reads where TAG == VALUE
--ignore-duplicates off Exclude PCR/optical duplicate reads
--ignore-secondary off Exclude secondary alignments
--ignore-supplementary off Exclude supplementary alignments

Coverage-specific flags

Flag Default Description
--normalize raw Signal normalization method: raw, rpkm, or cpm
--fragment-counts off Count fragments instead of individual read alignments
--ignore-scaffolds off Skip scaffold or unplaced chromosomes
--threads 6 Threads used when writing BigWig output

Examples

Generate basic coverage

bamnado bam-coverage \
  --bam sample.bam \
  --output coverage.bedgraph \
  --bin-size 100

Generate high-quality, normalized coverage

bamnado bam-coverage \
  --bam sample.bam \
  --output coverage_hq.bw \
  --bin-size 100 \
  --normalize rpkm \
  --min-mapq 30 \
  --proper-pairs

Extract nucleosome-free regions from ATAC-seq

bamnado bam-coverage \
  --bam atac.bam \
  --output nfr_forward.bw \
  --bin-size 10 \
  --strand forward \
  --min-fragment-len 100 \
  --max-fragment-len 200 \
  --fragment-counts \
  --min-mapq 20

Filter by cell barcode (single-cell)

bamnado bam-coverage \
  --bam possorted_genome_bam.bam \
  --output cell_coverage.bw \
  --bin-size 100 \
  --barcode-allowlist barcodes.txt \
  --fragment-counts

Filter by SAM tag (MCC viewpoint)

bamnado bam-coverage \
  --bam mcc.bam \
  --output BCL2_viewpoint.bw \
  --bin-size 50 \
  --tag VP \
  --tag-value BCL2 \
  --fragment-counts \
  --min-mapq 30

Compare two BigWig files

bamnado bigwig-compare \
  --bw1 sample_treated.bw \
  --bw2 sample_control.bw \
  --comparison log-ratio \
  --pseudocount 1e-3 \
  --threads 6 \
  -o treated_vs_control.bw

Aggregate multiple BigWig files

bamnado bigwig-aggregate \
  --bigwigs sample1.bw sample2.bw sample3.bw \
  --method mean \
  --threads 6 \
  -o mean_coverage.bw

Simplify bedGraph file

bamnado collapse-bedgraph \
  --input signal.bedgraph \
  --output signal.collapsed.bedgraph

Normalize between ChIP-seq samples

bamnado bam-normalize \
  --bams chip1.bam chip2.bam chip3.bam \
  --method csaw-background \
  --bin-size 10000 \
  --blacklist blacklist.bed

Apply the reported scale_factor for each sample to bam-coverage -f (or bigwig-aggregate --scale-factors) when generating tracks for that sample.

Between-sample normalization

Comparing ChIP-seq / CUT&Tag / CUT&RUN samples side by side requires removing composition and technical bias, not just sequencing depth. A sample with a stronger pulldown has more of its library consumed by peaks, which deflates its background and makes every other region look artificially low relative to a shallower or weaker-pulldown sample. Simple total-count (CPM) scaling does not correct for this — it's the same problem csaw::normFactors / edgeR::calcNormFactors (TMM) solve in R/Bioconductor.

bamnado bam-normalize bins the genome, counts filtered reads (or fragments) per bin per sample, and reports a per-sample scaling factor plus the underlying bin count matrix for downstream sanity checks (e.g. M-A plots). It reports factors only — it does not generate bigwigs itself.

Method choice

Method When to use
csaw-background (default) Typical composition bias: TMM restricted to large background windows with the most-enriched bins excluded
tmm TMM over all bins, without excluding enriched regions
cpm Naive depth-only baseline, useful for comparison against the other methods
median-of-ratios A robust DESeq2-style alternative estimator
spike-in When a spike-in genome was used and is trusted more than a background estimate

Applying the result

scale_factor is centred on 1 (the geometric mean across samples), so it can be passed directly to bam-coverage -f <factor> or bigwig-aggregate --scale-factors for each corresponding sample.

Use --counts-out counts.tsv to write the underlying bin count matrix (chrom, start, end, one column per sample) for QC, e.g. plotting an M-A plot to confirm the fitted factor sits at the centre of the trimmed M-value cloud.

Spike-in caveat

The spike-in method reads mapped-read counts directly from each BAM's index (no BAM record scan), so those counts are unfiltered by MAPQ, duplicates, or secondary/supplementary status — the same basis as bam-coverage's internal mapped-read count. --exogenous-prefix is required and --bin-size is ignored for this method.

Python API

Installing the Python package also installs the bamnado CLI, including all Rust CLI commands and flags:

pip install bamnado
bamnado bam-coverage --help

BamNado provides Python bindings for high-performance BAM signal generation with flexible read filtering. Install from PyPI:

pip install bamnado
# or
uv pip install bamnado

Quick start

import bamnado
import numpy as np

# Generate coverage from a BAM file
signal = bamnado.get_signal_for_chromosome(
    bam_path="input.bam",
    chromosome_name="chr1",
    bin_size=50,
)
print(f"Mean coverage: {np.mean(signal):.2f}")

ReadFilter class

Customize read filtering with the ReadFilter class. All parameters are optional:

import bamnado

# Create a filter for high-quality, properly-paired reads
strict_filter = bamnado.ReadFilter(
    min_mapq=30,
    proper_pair=True,
    min_length=50,
)

# Apply the filter
signal = bamnado.get_signal_for_chromosome(
    bam_path="input.bam",
    chromosome_name="chr1",
    bin_size=100,
    read_filter=strict_filter,
)

Filter parameters

Parameter Type Default Description
min_mapq int 0 Minimum mapping quality
proper_pair bool False Require properly paired reads
min_length int 0 Minimum read length (bp)
max_length int 1000 Maximum read length (bp)
strand str "both" "forward", "reverse", or "both"
min_fragment_length int | None None Minimum insert size (bp); paired-end only
max_fragment_length int | None None Maximum insert size (bp); paired-end only
blacklist_bed str | None None BED file of excluded regions
whitelisted_barcodes list[str] | None None Cell barcodes to include (CB tag)
read_group str | None None Read group to keep (RG tag)
filter_tag str | None None SAM tag to filter on (e.g. "VP")
filter_tag_value str | None None Required value for filter_tag

Usage examples

Basic coverage

import bamnado
import numpy as np

signal = bamnado.get_signal_for_chromosome(
    bam_path="sample.bam",
    chromosome_name="chr1",
    bin_size=50,
    scale_factor=1.0,
    use_fragment=False,
)
print(f"Signal shape: {signal.shape}, type: {signal.dtype}")
print(f"Mean: {np.mean(signal):.2f}, Max: {np.max(signal):.2f}")

Nucleosome-free regions (ATAC-seq)

import bamnado

# Forward-strand reads, 100–200 bp fragments
nfr_filter = bamnado.ReadFilter(
    strand="forward",
    min_fragment_length=100,
    max_fragment_length=200,
    min_mapq=20,
)

nfr_signal = bamnado.get_signal_for_chromosome(
    bam_path="atac.bam",
    chromosome_name="chr1",
    bin_size=10,
    use_fragment=True,
    read_filter=nfr_filter,
)

Barcode-filtered coverage (single-cell)

import bamnado

# Get coverage for specific cell barcodes
cell_barcodes = ["ACGTACGT-1", "TGCATGCA-1", "AAATAAAA-1"]

barcode_filter = bamnado.ReadFilter(
    whitelisted_barcodes=cell_barcodes,
    min_mapq=25,
)

signal = bamnado.get_signal_for_chromosome(
    bam_path="possorted_genome_bam.bam",
    chromosome_name="chr1",
    bin_size=100,
    use_fragment=True,
    read_filter=barcode_filter,
)

Tag-filtered coverage (e.g. MCC viewpoint)

import bamnado

# Get coverage for specific viewpoint
vp_filter = bamnado.ReadFilter(
    filter_tag="VP",
    filter_tag_value="BCL2",
    min_mapq=30,
)

vp_signal = bamnado.get_signal_for_chromosome(
    bam_path="mcc.bam",
    chromosome_name="chr1",
    bin_size=50,
    use_fragment=True,
    read_filter=vp_filter,
)

High-confidence coverage

import bamnado

# High-quality, properly-paired reads
confident_filter = bamnado.ReadFilter(
    min_mapq=30,
    proper_pair=True,
    min_length=50,
    min_fragment_length=100,
    max_fragment_length=500,
)

signal = bamnado.get_signal_for_chromosome(
    bam_path="sample.bam",
    chromosome_name="chr1",
    bin_size=50,
    scale_factor=1e6,  # CPM normalization
    use_fragment=True,
    read_filter=confident_filter,
)

get_signal_for_chromosome parameters

Parameter Type Default Description
bam_path str Path to indexed BAM file
chromosome_name str Chromosome to process (e.g. "chr1")
bin_size int 50 Bin width in base pairs
scale_factor float 1.0 Linear scaling factor
use_fragment bool False Use fragment (pair) coordinates instead of read
ignore_scaffold_chromosomes bool True Skip non-standard chromosomes
read_filter ReadFilter | None None Optional read filter

Returns: numpy.ndarray of dtype float32 with length = chromosome size / bin_size

Note: Fragment length filtering (min_fragment_length, max_fragment_length) requires paired-end BAM files and will raise ValueError on single-end data.

Between-sample scaling factors

compute_scale_factors mirrors the bam-normalize CLI command — see Between-sample normalization for the underlying method.

import bamnado

result = bamnado.compute_scale_factors(
    ["chip1.bam", "chip2.bam", "chip3.bam"],
    method="csaw-background",
    bin_size=10000,
)
print(result.sample_names, result.scale_factors)

# Include the bin count matrix for QC (e.g. an M-A plot)
result = bamnado.compute_scale_factors(
    ["chip1.bam", "chip2.bam"],
    method="tmm",
    return_counts=True,
)
counts = result.counts()  # (n_bins, n_samples) uint64 array, or None

compute_scale_factors parameters

Parameter Type Default Description
bam_paths list[str] Input BAM file paths, one per sample
method str "csaw-background" "tmm", "csaw-background", "cpm", "median-of-ratios", or "spike-in"
bin_size int 10000 Genomic bin width in bp; ignored for "spike-in"
sample_names list[str] | None None Defaults to each BAM's file stem, disambiguated if duplicated
exclude_top_percent float 5.0 "csaw-background" only: percent of highest-mean bins dropped before estimating
reference_sample str | None None TMM reference sample; defaults to the one closest to the geometric mean
logratio_trim float 0.3 TMM trim fraction for M-values
sum_trim float 0.05 TMM trim fraction for A-values
exogenous_prefix str | None None Required for method="spike-in"
use_fragment bool False Count fragments (pairs) instead of individual reads
ignore_scaffold_chromosomes bool True Skip scaffold / unplaced chromosomes
read_filter ReadFilter | None None Applied per sample
return_counts bool False Populate ScaleFactorResult.counts()

Returns: ScaleFactorResult with method, sample_names, library_sizes, norm_factors, scale_factors, reference_sample, n_bins_total, n_bins_used, and (when return_counts=True) counts(), bin_chroms, bin_starts, bin_ends.

Development

cargo build --release
cargo test

License

Apache-2.0 OR MIT

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

bamnado-0.9.0.tar.gz (138.9 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

bamnado-0.9.0-cp310-abi3-win_amd64.whl (17.6 MB view details)

Uploaded CPython 3.10+Windows x86-64

bamnado-0.9.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (19.0 MB view details)

Uploaded CPython 3.10+manylinux: glibc 2.17+ x86-64

bamnado-0.9.0-cp310-abi3-macosx_11_0_arm64.whl (17.4 MB view details)

Uploaded CPython 3.10+macOS 11.0+ ARM64

bamnado-0.9.0-cp310-abi3-macosx_10_12_x86_64.whl (18.0 MB view details)

Uploaded CPython 3.10+macOS 10.12+ x86-64

File details

Details for the file bamnado-0.9.0.tar.gz.

File metadata

  • Download URL: bamnado-0.9.0.tar.gz
  • Upload date:
  • Size: 138.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: maturin/1.14.1

File hashes

Hashes for bamnado-0.9.0.tar.gz
Algorithm Hash digest
SHA256 ca48412759c5d7f186698575a4203ffdc07290653afcd0f461a328181313d467
MD5 6bed71122b40587d9b9de8d5f4f50699
BLAKE2b-256 556999802c32c66d7bb62ce708f82e230fc94496a7b16e33afa59c1fe928f61d

See more details on using hashes here.

File details

Details for the file bamnado-0.9.0-cp310-abi3-win_amd64.whl.

File metadata

  • Download URL: bamnado-0.9.0-cp310-abi3-win_amd64.whl
  • Upload date:
  • Size: 17.6 MB
  • Tags: CPython 3.10+, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: maturin/1.14.1

File hashes

Hashes for bamnado-0.9.0-cp310-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 9317535eec97d20d192e3d8f68aa78d9fc824df609350d3746b23374581bb9cf
MD5 ffdf1a1879ca1e4aa358c54ebf74ac77
BLAKE2b-256 629c97860e71921071038d0f94be3afae670a351465a92a5690eadef25622889

See more details on using hashes here.

File details

Details for the file bamnado-0.9.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for bamnado-0.9.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 5422267afd817b906457cf23e0afd907832a8492215b8108680c1c3b90caa70c
MD5 d6d8d742b971487c914a5918bcf21dca
BLAKE2b-256 39e7d74be18265eac354a5429b2d8cf49c406c0b79f81258bc929fb7ade569ed

See more details on using hashes here.

File details

Details for the file bamnado-0.9.0-cp310-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for bamnado-0.9.0-cp310-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 56b90b1eff514e1892156fa88a6884cbaad8cbbe137f0e2552f8a7681f9d1952
MD5 0939cd07d308b832a35d3ef3af200067
BLAKE2b-256 14691e7ad41970a739ba33669fd0716be977cbaa490b6cbdb2f47f751559ffd5

See more details on using hashes here.

File details

Details for the file bamnado-0.9.0-cp310-abi3-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for bamnado-0.9.0-cp310-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 ae8f146e2b7311235dac6c16bc38049e3f49c96ec2a79bd23e74c6bb204e7c44
MD5 466b07f40af687073af86b9e4f8cc455
BLAKE2b-256 5e9537f2d78c28ae99385eaacdc141bfc9384ce7ca56a2f2f00dbb9e86cce99c

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.9.0 This release

5 files

0.6.1

5 files

0.6.0

5 files

0.5.8

6 files

0.4.4

5 files

0.4.0

5 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page