sam-formatter
Convert SAM/BAM alignment files into a uniform tabular format — CSV, TSV, PSV, Parquet, or any custom delimiter — with optional SAM tags promoted to their own sorted columns.
Features
- Reads SAM (text) and BAM (binary/BGZF) from a file or standard input.
- Auto-detects format from magic bytes (
--input-formatto override). - Outputs CSV (default), TSV, PSV, Parquet, or a custom delimiter.
- Optional tags (
NM,RG,MD, …) become their own columns, sorted alphabetically. - Two-phase discover-then-stream; tag discovery is capped at
min(--detect-limit, --limit)so memory stays bounded. - Parquet output is typed:
FLAG/POS/MAPQ/PNEXT/TLENasint32, text and tags asutf8, missing tags asNULL. - Downsample:
--downsample 0.1keeps ~10% of records (Bernoulli);--downsample 1000keeps exactly 1000 uniformly random records (reservoir sampling).--seedmakes a sample reproducible.
Install
# or build locally:
Requires Rust ≥ 1.89 (noodles).
Usage
| |
Output format:
Tags:
Downsampling:
A fraction in (0, 1) keeps each record independently (≈ that share of the input); an
integer ≥ 1 keeps exactly that many records via reservoir sampling (held in memory; the
whole stream is read before any output). --limit caps the input before sampling.
Options
| Flag | Default | Purpose |
|---|---|---|
[INPUT] |
- |
SAM/BAM file, or - for standard input |
-o, --output |
stdout | output file (extension picks format) |
-f, --format |
auto | csv|tsv|psv|parquet|custom |
--input-format |
auto |
auto|sam|bam |
-d, --delimiter |
, |
delimiter for custom |
-n, --limit |
1000000 |
max records read from input (capped before sampling) |
--detect-limit |
100000 |
records scanned to discover tags |
--keep-tag-prefix |
off | keep TAG:TYPE:VALUE instead of value only |
--no-quotes |
off | disable CSV quoting |
--downsample |
off | fraction (0,1) or integer ≥1; downsample output |
--seed |
off | u64 seed for a reproducible --downsample |
Notes
- When piping SAM text, include the header (
samtools view -h): records whoseRNAMEis not declared in an@SQline are rejected. BAM carries its header internally, so no special handling is needed. - A gzip-compressed SAM is not read directly (auto-detect misreads it as BAM, and the
tool does not decompress). Decompress first:
zcat in.sam.gz | sam-formatter. - A mate reference equal to
RNAMEis written as=(matchessamtools view).
How it works
Parsing uses noodles for both SAM and BAM via the
shared sam::alignment::Record trait. Each record is serialized to a canonical SAM line
with noodles' own writer and then split into columns — so CIGAR, SEQ/QUAL, and typed tag
formatting are always spec-correct, identically for SAM and BAM.
License
Licensed under the MIT License.