
Ultra-fast quality control and summary reports for nanopore reads
v0.10.0
Nanoq implements ultra-fast read filters and summary reports for high-throughput nanopore reads.
We would appreciate a citation if you are using nanoq for research. Please see here for some suggestions how you could give back to the community if you are using nanoq for industry applications :pray:
Steinig and Coin (2022). Nanoq: ultra-fast quality control for nanopore reads. Journal of Open Source Software, 7(69), 2991, https://doi.org/10.21105/joss.02991
Nanoq is as fast as seqtk-fqchk for summary statistics of small datasets (e.g. Zymo - 100,000 reads) and slightly faster on large datasets (e.g. Zymo - 3.5 million reads, 1.3x - 1.5x). In fast mode (no quality scores), nanoq is ~2-3x faster than rust-bio-tools and seqkit stats for summary statistics and other commonly used read summary or filtering methods (up to 297x-442x). Memory consumption is consistent and tends to be lower than other tools (~5-10x).
Nanoq comes with high test coverage for your peace of mind.
cargo test
Cargocargo install nanoq
CondaExplicit version (for some reason defaults to old version)
conda install -c conda-forge -c bioconda nanoq=0.10.0
BinariesPrecompiled binaries for Linux and MacOS are attached to the latest release.
VERSION=0.10.0
RELEASE=nanoq-${VERSION}-x86_64-unknown-linux-musl.tar.gz
wget https://github.com/esteinig/nanoq/releases/download/${VERSION}/${RELEASE}
tar xf nanoq-${VERSION}-x86_64-unknown-linux-musl.tar.gz
nanoq-${VERSION}-x86_64-unknown-linux-musl/nanoq -h
Nanoq accepts a file (-i) or stream (stdin) of reads in fast{a,q}.{gz,bz2,xz} format and outputs reads to file (-o) or stream (stdout).
nanoq -i test.fq.gz -o reads.fq
cat test.fq.gz | nanoq > reads.fq
Reads can be filtered by minimum read length (-l), maximum read length (-m), minimum average read quality (-q) or maximum average read quality (-w).
nanoq -i test.fq -l 1000 -m 10000 -q 10 -w 15 > reads.fq
A fixed number of bases can be trimmed from the start (-S) or end (-E) of reads:
nanoq -i test.fq -S 100 -E 100 > reads.fq
Read summaries are produced when using the stats flag (-s, report to stdout, no read output to stdout) or when specifying a report file (-r):
nanoq -i test.fq -s
nanoq -i test.fq -r report.txt > reads.fq
For report types and configuration see the output section.
:warning: When using fast mode
-fread quality scores are not computed (output of quality fields:NaN)
Read qualities may be excluded from filters and statistics to speed up read iteration (-f).
nanoq -i test.fq.gz -f -s
Output compression is inferred from file extensions (gz, bz2, lzma).
nanoq -i test.fq -o reads.fq.gz
Output compression can be specified manually with -O and -c.
nanoq -i test.fq -O g -c 9 -o reads.fq.gz
Nanoq can be used to check on active sequencing runs and barcoded samples.
find /data/nanopore/run -name "*.fastq" -print0 | xargs -0 cat | nanoq -s
for i in {01..12}; do
find /data/nanopore/run -name barcode${i}.fastq -print0 | xargs -0 cat | nanoq -s
done
nanoq 0.10.0
Filters and summary reports for nanopore reads
USAGE:
nanoq [FLAGS] [OPTIONS]
FLAGS:
-f, --fast Ignore quality values if present
-h, --help Prints help information
-H, --header Header for summary output
-j, --json Summary report in JSON format
-s, --stats Summary report only [stdout]
-V, --version Prints version information
-v, --verbose Verbose output statistics [multiple, up to -vvv]
OPTIONS:
-c, --compress-level <1-9> Compression level to use if compressing output [default: 6]
-i, --input <input> Fast{a,q}.{gz,xz,bz}, stdin if not present
-m, --max-len <INT> Maximum read length filter (bp) [default: 0]
-w, --max-qual <FLOAT> Maximum average read quality filter (Q) [default: 0]
-l, --min-len <INT> Minimum read length filter (bp) [default: 0]
-q, --min-qual <FLOAT> Minimum average read quality filter (Q) [default: 0]
-o, --output <output> Output filepath, stdout if not present
-O, --output-type <u|b|g|l> u: uncompressed; b: Bzip2; g: Gzip; l: Lzma
-r, --report <FILE> Summary read statistics report output file
-t, --top <INT> Number of top reads in verbose summary [default: 5]
-L, --read-lengths <FILE> Output read lengths of surviving reads to file
-Q, --read-qualities <FILE> Output read qualities of surviving reads to file
-S, --trim-start <INT> Trim bases from the start of each read [default: 0]
-E, --trim-end <INT> Trim bases from the end of each read [default: 0]
Files with read lengths (--read-lengths/-L) and qualities (--read-qualities/-Q) of the surviving reads can be output:
nanoq -i test.fq -Q rq.txt -L rl.txt > reads.fq
Summary reports are output to file explicitly using --report/-r:
nanoq -i test.fq -r report.txt > reads.fq
nanoq -i test.fq -r report.txt -s
When using the --stats/-s flag read output is suppressed and summary is directed to stdout:
nanoq -i test.fq -s > report.txt
Report format is minimal by default:
100000 400398234 5154 44888 5 4003 3256 8.90 9.49
A machine readable header can be added using the -H flag:
nanoq -i test.fq -s -H
Extended summaries analogous to NanoStat can be obtained using multiple -v flags (up to -vvv), including the top (-t) read lengths and qualities:
-v - verbose read summary (top block as below)-vv - like -v with read length and/or quality thresholds -vvv - like -vv with top ranking read lengths and/or qualitiesnanoq -i test.fq -f -s -t 5 -vvv
Nanoq Read Summary
====================
Number of reads: 100000
Number of bases: 400398234
N50 read length: 5154
Longest read: 44888
Shortest read: 5
Mean read length: 4003
Median read length: 3256
Mean read quality: NaN
Median read quality: NaN
Read length thresholds (bp)
> 200 99104 99.1%
> 500 96406 96.4%
> 1000 90837 90.8%
> 2000 73579 73.6%
> 5000 25515 25.5%
> 10000 4987 05.0%
> 30000 47 00.0%
> 50000 0 00.0%
> 100000 0 00.0%
> 1000000 0 00.0%
Top ranking read lengths (bp)
1. 44888
2. 40044
3. 37441
4. 36543
5. 35630
JSON formatted extended output (equivalent to -vvv) can be output to --report (-r) or stdout (-s) using the --json/-j flag:
nanoq -i test.fq --json -f -r report.json > reads.fq
nanoq -i test.fq --json -f -s > report.json
{
"reads": 100000,
"bases": 400398234,
"n50": 5154,
"longest": 44888,
"shortest": 5,
"mean_length": 4003,
"median_length": 3256,
"mean_quality": null,
"median_quality": null,
"length_thresholds": {
"200": 99104,
"500": 96406,
"1000": 90837,
"2000": 73579,
"5000": 25515,
"10000": 4987,
"30000": 47,
"50000": 0,
"100000": 0,
"1000000": 0
},
"quality_thresholds": {
"5": 0,
"7": 0,
"10": 0,
"12": 0,
"15": 0,
"20": 0,
"25": 0,
"30": 0
},
"top_lengths": [
44888, 40044, 37441, 36543, 35630
],
"top_qualities": []
}
Note that in this example no read qualities are computed; quality thresholds are therefore all zero.
Benchmarks evaluate processing speed and memory consumption of a basic read length filter and summary statistics on the even Zymo mock community (GridION) with comparisons to rust-bio-tools, seqtk fqchk, seqkit stats, NanoFilt, NanoStat and Filtlong. Time to completion and maximum memory consumption were measured using /usr/bin/time -f "%e %M", speedup is relative to the slowest command in the set. We note that summary statistics from rust-bio-tools and seqkit stats do not compute read quality scores and are therefore comparable to nanoq-fast.
Tasks:
stats: basic read set summariesfilter: minimum read length filter (into /dev/null)Tools:
rust-bio-tools 0.28.0nanostat 1.5.0 nanofilt 2.8.0filtlong 0.2.1seqtk 1.3-r126seqkit 2.0.0nanoq 0.8.2Commands used for stats task:
nanostat (fq + fq.gz) --> NanoStat --fastq test.fq --threads 1 rust-bio (fq) --> rbt sequence-stats --fastq < test.fqrust-bio (fq.gz) --> zcat test.fq.gz | rbt sequence-stats --fastqseqtk-fqchk (fq + fq.gz) --> seqtk fqchkseqkit stats (fq + fq.gz) --> seqkit stats -j1nanoq (fq + fq.gz) --> nanoq --input test.fq --stats nanoq-fast (fq + fq.gz) --> nanoq --input test.fq --stats --fast Commands used for filter task:
filtlong (fq + fq.gz) --> filtlong --min_length 5000 test.fq > /dev/null nanofilt (fq) --> NanoFilt --fastq test.fq --length 5000 > /dev/null nanofilt (fq.gz) --> gunzip -c test.fq.gz | NanoFilt --length 5000 > /dev/null nanoq (fq + fq.gz) --> nanoq --input test.fq --min-len 5000 > /dev/null nanoq-fast (fq + fq.gz) --> nanoq --input test.fq --min-len 5000 --fast > /dev/null Files:
zymo.fq: uncompressed (100,000 reads, ~400 Mbp)zymo.fq.gz: compressed (100,000 reads, ~400 Mbp)zymo.full.fq: uncompressed (3,491,078 reads, ~14 Gbp)Data preparation:
wget "https://nanopore.s3.climb.ac.uk/Zymo-GridION-EVEN-BB-SN.fq.gz"
zcat Zymo-GridION-EVEN-BB-SN.fq.gz > zymo.full.fq
head -400000 zymo.full.fq > zymo.fq && gzip -k zymo.fq
Elapsed real time and maximum resident set size:
/usr/bin/time -f "%e %M"
Task and command execution:
Commands were run in replicates of 10 with a mounted benchmark data volume in the provided Docker container. An additional cold start iteration for each command was not considered in the final benchmarks.
for i in {1..11}; do
for f in /data/*.fq; do
/usr/bin/time -f "%e %M" nanoq -f- s -i $f 2> benchmark
tail -1 benchmark >> nanoq_stat_fq
done
done

stats + zymo.full.fq| command | mb (sd) | sec (sd) | reads / sec | speedup | quality scores |
|---|---|---|---|---|---|
| nanostat | 741.4 (0.09) | 1260. (13.9) | 2,770 | 01.00 x | true |
| seqtk-fqchk | 103.8 (0.04) | 125.9 (0.15) | 27,729 | 10.01 x | true |
| seqkit-stats | 18.68 (3.15) | 125.3 (0.91) | 27,861 | 10.05 x | false |
| nanoq | 35.83 (0.06) | 94.51 (0.43) | 36,938 | 13.34 x | true |
| rust-bio | 43.20 (0.08) | 06.54 (0.05) | 533,803 | 192.7 x | false |
| nanoq-fast | 22.18 (0.07) | 02.85 (0.02) | 1,224,939 | 442.1 x | false |
filter + zymo.full.fq| command | mb (sd) | sec (sd) | reads / sec | speedup |
|---|---|---|---|---|
| nanofilt | 67.47 (0.13) | 1160. (20.2) | 3,009 | 01.00 x |
| filtlong |
$ claude mcp add nanoq \
-- python -m otcore.mcp_server <graph>