ONT wf-16S Amplicon Post-Processing Pipeline
Modular, config-driven downstream post-processing, statistical analysis, diversity quantification, and Kraken/Pavian/Krona export for Oxford Nanopore Technologies (ONT) full-length 16S rRNA and ITS amplicon sequencing generated by EPI2ME wf-16s using either Minimap2 or Kraken2/Bracken classifiers.
Current pipeline version: 0.5.0.
The kreport pathway provides the canonical Kraken report, an opt-in Krona
export, and an opt-in original offline Kraken-report explorer. The .kreport
file remains the official Pavian interoperability artifact; the built-in HTML
is not the upstream Pavian Shiny application.
This repository transforms primary outputs from ONT's Nextflow-based wf-16s pipeline into reproducible statistical figures, tables, and Pavian-compatible Kraken reports (.kreport). Supports both minimap2 alignment-based and kraken2/bracken k-mer/Bayesian estimation upstream contracts across 16S and ITS databases. Treat species-level calls and richness estimates as conditional on the upstream classifier, reference database, and abundance threshold—not as independent validation of organism presence.
analysis/
├── 00_run_pipeline.R # Orchestrator & CLI entry point
├── 01_qc_diagnostics.R # Classification donut, read length distributions, filter diagnostics
├── 02_alpha_diversity.R # Registry-driven alpha metrics, rarefaction, optional phylogeny
├── 03_beta_diversity.R # Bray-Curtis, Jaccard, PCoA, PERMANOVA (adonis2) & betadisper
├── 04_taxa_composition.R # Standardized long-format taxa tables, bars, stacks, heatmap
├── 05_ordination.R # Hellinger PCA & Bray-Curtis NMDS (cohort mode)
├── 06_shared_taxa.R # Core/unique taxa by group prevalence, UpSet plot
├── 07_kreport_pavian.R # Kraken report, Krona/Pavian exports, taxonomy provenance
├── 08_faprotax.R # Opt-in FAPROTAX 1.2.12 taxon-based inference
├── 09_faprotax2.R # Opt-in official FAPROTAX-mapper 2.0 taxonomy adapter
├── install_packages.R # Dependency checker & installer (--install)
├── utils/merge_wf16s_cohort.R # Standalone multi-bundle cohort merger utility
├── utils/classifier_contract.R # Classifier contract validation & population accounting
├── utils/krona_builder.py # Stdlib-only offline Krona-compatible HTML builder
├── utils/verify_krona_correspondence.py # Exact Krona HTML/TSV semantic verifier
├── utils/kraken_report_viewer.py # Stdlib-only offline Kraken-report explorer
├── utils/verify_kraken_viewer_correspondence.py # Independent viewer verifier
├── utils/taxonomy_sankey_renderer.py # Stdlib-only canonical Sankey renderer
├── utils/verify_taxonomy_sankey_correspondence.py # Independent Sankey verifier
├── utils/taxonomy_sankey_client.js # Offline browser model and SVG renderer
└── vendor/krona-2.8.1/ # Byte-pinned, unmodified Krona browser assets
Repository-level supporting material is grouped by purpose:
wf16s-inputs/contains local producer bundles; only the compact Ambar Ayunda regression contract is tracked.patch/contains implementation plans, review evidence, and release-audit notes, indexed by version.archived/contains historical scripts, analyses, and legacy outputs.
The pipeline supports two execution modes:
-
Single-Sample Mode (
single):- Focuses on within-sample characteristics: read-length distribution, classification yield, alpha diversity indices, analytical rarefaction curve, rarefaction resamples, taxonomic composition, and Kraken report generation.
- Multi-sample comparative modules (
03_beta_diversity.R,05_ordination.R,06_shared_taxa.R) are gracefully skipped with structured records in the manifest.
-
Cohort Mode (
cohort):- Requires
$\ge 2$ samples and a valid metadata mapping (SampleIDandGroup). - Executes PCoA ordination, group-level taxonomic stacked bars, composition heatmaps, UpSet plots, and non-parametric group comparisons.
-
Statistical Gates:
- PERMANOVA (
adonis2) requires at least 2 groups with$\ge 2$ samples per group and residual degrees of freedom. It is paired withbetadisperhomogeneity of multivariate dispersion testing. A warning is issued if any group has$<3$ samples. - Optional beta rarefaction stability is marked completed only when the configured minimum success fraction (default
0.50) of iterations produces valid Procrustes-aligned coordinates; otherwise the diagnostic is skipped with an explicit reason. - Non-parametric alpha group tests (Wilcoxon rank-sum or Kruskal-Wallis with Benjamini-Hochberg FDR) require at least 2 groups with
$\ge 3$ biological samples each.
- PERMANOVA (
- Requires
Version 0.5.0 is validated against the tracked wf-16s minimap2 and
Kraken2/Bracken abundance, assignment, taxonomy-cache, and parameter schemas
represented by the Ambar Ayunda regression fixture and synthetic Kraken2/ITS fixtures.
Inputs from historical or future wf-16s releases must satisfy the contracts below;
compatibility with arbitrary schemas is not implied.
- Tab-delimited table where the first column is
tax. taxcontains exactly eight semicolon-delimited ranks:superkingdom;kingdom;phylum;class;order;family;genus;species- Every rank must be non-empty after trimming and must not have leading or
trailing whitespace; use an explicit label such as
Unknownwhen applicable. - One or more sample columns containing non-negative, integer counts (e.g.
80556or80556.0). - Synthetic unclassified row:
Unclassified;Unknown;Unknown;Unknown;Unknown;Unknown;Unknown;Unknown. - Optional aggregate column
totalmust reconcile exactly to the row sum across sample columns.
- Optional per-sample mapping. If omitted, abundance-only modules proceed normally and read length diagnostics are cleanly skipped.
- Five tab-delimited columns without header:
- Status (
C= aligned/classified,U= unaligned/unclassified) - Read ID (unique string)
- TaxID (canonical decimal string; TaxID
0denotes read aligned but failed downstream identity/coverage QC) - Length field (exactly a positive decimal length such as
1481, or a numeric prefix and positive length such as0|1481) - Lineage path (pipe-delimited)
- Status (
- Effective Classification: Defined as
taxid > 0. Raw statusCalone overstates classification; reads with statusCand TaxID0are filtered out by upstream reference coverage/identity thresholds. - Plain-text and
.gzassignment inputs are read in bounded two-pass chunks. Schema validation, physical error line numbers, and the final typed QC data frame are preserved while avoiding a whole-file text buffer.
input.params_jsonis required. Version 0.5.0 accepts minimap2 and kraken2, species-rank output from the bundled NCBI database sets without custom reference or taxonomy overrides.input.wf16s_output_rootis optional. When supplied, the pipeline discovers each sample'sbamstats.readstats.tsv.gzby its internalsample_nameand partitionsC + TaxID 0reads into identity-only, coverage-only, and both-threshold failures.- Missing optional bamstats produces explicit
NAfields; a configured invalid or ambiguous bamstats contract fails rather than selecting an arbitrary file.
input.phylogenetic_treemay name a rooted Newick tree with unique tips and finite, non-negative branch lengths. Branch lengths are never imputed.input.phylogenetic_tip_mapis an optional two-column TSV with the exact headerTaxonPath<TAB>TipLabel. Without it, positive classifiedTaxonPathvalues must exactly equal tree-tip labels.- Every positive classified taxon must map.
Unclassifiedcannot be mapped; unused tree tips are excluded from metric traversal while the original root and stem paths are retained; the excluded-tip count, method, and input hashes are recorded inalpha_phylogeny_status.tsvand the run manifest. - Omitting the tree is an intentional module-level skip for Faith PD, PSR, PSE,
and
02e; it emitsalpha_phylogeny_skipped.tsvrather than a partial PNG.
-
Classified-Only Denominator:
- Relative abundance for community composition and alpha diversity is computed relative to classified reads (
$\sum \text{counts}[\text{taxid} > 0]$ ). - Unclassified reads are kept separate and analyzed in the QC diagnostics module.
- Relative abundance for community composition and alpha diversity is computed relative to classified reads (
-
Alpha Diversity Indices:
- Observed species richness
$S$ - Chao1 estimated richness
- Shannon index
$H$ and Effective Number of Species ($e^H$ ) - Simpson's index
$D$ ($1 - \sum p_i^2$ ) and Inverse Simpson ($1 / \sum p_i^2$ ) - Pielou's evenness
$J = H / \log(S)$ - Fisher's log-series alpha
- Berger-Parker dominance (
$\max(N_i) / N$ ) - ACE, Heip's evenness, Smith-Wilson Evar, and the McIntosh diversity index
- Explicitly ordered Rényi entropy (default
$q=1$ ) and Hill numbers (default$q=0,1,2$ );$N_0=S$ ,$N_1=e^H$ , and$N_2$ is inverse Simpson - Optional Faith phylogenetic diversity, phylogenetic species richness (PSR), and phylogenetic species evenness (PSE) when the tree contract is satisfied
- Observed species richness
-
Rarefaction Resamples:
- Analytical rarefaction curves are computed with
vegan::rarefy(). - Subsampling iterations with
vegan::rrarefy()represent rarefaction resamples without replacement to assess community sampling sensitivity. They are never presented as independent biological replicates. -
rarefaction_resamples.tsvretains its legacy columns first and appends registry metrics.rarefaction_resamples_long.tsvis the canonical plotting table with explicit metric keys, labels, q parameters, validity, and reasons. -
alpha_metric_definitions.tsv,alpha_metric_status.tsv, andalpha_plot_registry.tsvmake formulas, edge rules, and facet membership inspectable. The fixed figures are02b(six core metrics),02c(four estimators/evenness metrics),02d(four evenness/entropy metrics), and optional02e(Hill q=0/1/2 plus Faith PD, PSR, and PSE).
- Analytical rarefaction curves are computed with
-
Richness overview:
-
02_richness_overview.tsvreports positive taxa, singletons, taxa with at most 10 reads, and the reads represented by that low-count tail. - These summaries remain conditional on upstream filtering, database choice, taxonomy, and the abundance threshold; low count alone does not prove artifact.
-
| Module | Handling |
|---|---|
| QC | Included in abundance accounting; all assignment reads are shown when assignments exist |
| Alpha diversity | Excluded |
| Beta diversity | Excluded |
| Taxonomic composition | Excluded from rank tables; included in the classification-fraction output |
| Ordination | Excluded |
| Shared taxa | Excluded |
| Kraken/Pavian/Krona | Included as the first U line or top-level Unclassified contribution and in total-read arithmetic |
This release adds deterministic classified-read-relative composition figures at phylum, family, and genus ranks. The new vertical stacked bars are written as matching PNG/TSV pairs:
04_phylum_stacked,04_family_stacked, and04_genus_stackedfor single samples or cohorts;04_<rank>_group_mean_stackedfor cohort group means; and04_heatmap_<rank>for each configured heatmap rank.
The existing single-sample horizontal artifacts (04a through 04d) remain
unchanged. New sidecars retain TaxonPath identity, contextual display labels,
sample/group order, stack/row order, denominator validity, and explicit
IsOther flags. The all-read Unclassified row is not added to these figures;
it remains in classification_fraction.tsv and its corresponding plot.
The defaults are:
composition:
stacked_bar_ranks: ["phylum", "family", "genus"]
stacked_bar_max_taxa: 15
stacked_bar_min_taxa: 5
stacked_bar_min_mean_relative: 0.005
heatmap_rank: null
heatmap_ranks: ["phylum", "family", "genus"]
heatmap_top_n_taxa: 10
heatmap_include_other: true
heatmap_transform: "log10_relative"For compatibility, a non-null legacy scalar heatmap_rank is migrated to a
one-element heatmap_ranks vector with one warning. Supplying both keys is an
error; the pipeline never guesses precedence. Heatmap columns are never
clustered. Cohort rows use complete-linkage clustering only when there are at
least two display rows; single-sample rows are abundance-ordered and are not
clustered. A rank with no positive classified abundance produces a structured
*_skipped.tsv sidecar instead of a fabricated image.
Zero-classified samples are represented as undefined composition: stacked and
heatmap sidecars keep finite numeric zero abundances with
ValidDenominator = FALSE, and those samples are excluded from taxon-selection
means, cohort means, heatmap pseudocounts, and clustering distances. Heatmap
columns are plotted as neutral NA cells with an explicit denominator-status
annotation. The residual Other row is never positive for an invalid sample.
When a cohort group has no valid samples, its group-mean rows remain present with
SamplesUsed = 0 and MeanRelativeAbundance = NA; the plot marks that group as
undefined. Other group means are arithmetic means of valid per-sample classified-
read proportions, not read-depth-pooled proportions.
A positive-total sample with zero classified reads can be processed when the
requested modules are limited to qc, composition, and kreport. Modules
whose statistics require a positive classified denominator (alpha, beta,
ordination, shared, and faprotax) fail preflight with the affected sample
and module names instead of receiving undefined input.
For a single zero-classified sample, the historical 04a-04d composition
figures are also withheld and 04_legacy_single_sample_skipped.tsv records why.
Request the module explicitly with --modules faprotax, or include faprotax
in a comma-separated module list. The default module list is unchanged. The
module checks the optional microeco dependency only when it is requested and
requires microeco >= 2.3.0 with its embedded FAPROTAX version exactly
1.2.12. This is FAPROTAX 1.2.12 via microeco, not FAPROTAX2-db, PICRUSt2, or
a gene/pathway abundance predictor.
Only positive-count Bacteria and Archaea rows enter the mapping. The canonical
unclassified row and classified non-prokaryotic rows are excluded from mapping
but retained in the explicit read accounting. Pipeline superkingdom is
passed to microeco as Kingdom; the NCBI kingdom rank is intentionally
omitted. Function read counts are the sums of classified taxon counts carrying
each function, with no rarefaction, copy-number correction, or cross-function
renormalization. Functions overlap, so their percentages are independent
fractions and must not be stacked or expected to sum to 100%.
The module writes 08_FAPROTAX/ with the following artifacts:
faprotax_function_abundance.tsv: longSampleID,Function,FunctionReadCount,PctEligibleProkaryoticReads,PctClassifiedReads, andPctTotalReadstable. Each percentage uses the denominator named in its column; a zero eligible denominator yields zero percent.faprotax_mapping_coverage.tsv: per-sampleTotalReads,UnclassifiedReads,ClassifiedReads,EligibleProkaryoticReads,ExcludedNonProkaryoticClassifiedReads,FunctionMappedReads,FunctionUnmappedEligibleReads,EligibleProkaryoticTaxa, andFunctionMappedTaxa. The equations areClassifiedReads + UnclassifiedReads = TotalReads,EligibleProkaryoticReads + ExcludedNonProkaryoticClassifiedReads = ClassifiedReads, andFunctionMappedReads + FunctionUnmappedEligibleReads = EligibleProkaryoticReads.FunctionMappedReadscounts each eligible read once when its taxon has at least one function; it is not the sum across overlapping functions. Every function count is bounded by0 <= FunctionReadCount <= EligibleProkaryoticReadsfor its sample.faprotax_taxon_function_assignments.tsv: positive mappings with stableFeatureIDvalues and the originalTaxonPath.faprotax_top_functions.png: independent bars faceted by sample for the configured top functions; it is not a compositional stack.faprotax_provenance.json: package/database versions, method, source, denominator definitions, input filtering, and the overlap warning.
If no positive-count Bacteria or Archaea rows exist, the module writes only
faprotax_skipped.tsv and records a structured skipped module result. A
missing/incompatible microeco installation or embedded database version is a
failure, not a skip.
These are taxon-based functional assignments/inference. They do not establish
gene presence, pathway completeness, expression, or activity. Cite the
original database/software paper: Louca et al. (2016).
The tracked-fixture comparison with the official collapse_table.py workflow
is recorded in faprotax1.2.12-concordance-review.md;
the two engines must not be treated as byte-for-byte equivalent.
--modules faprotax2 runs the official FAPROTAX-mapper 2.0 beta in taxonomy
mode. The existing faprotax backend remains available, and both functional
backends remain outside the default module selection. The mapper distribution
includes its own reference tree and model data; FAPROTAX-db 2.0 alone is not
that runtime. The upstream audit records
the official download, license evidence and SHA-256 identities.
The wrapper consumes the existing pipeline abundance contract. It selects
positive-count Bacteria/Archaea rows, translates the eight NCBI ranks to the
mapper's seven ranks by omitting the intervening kingdom, and retains the
original TaxonPath and count basis. Internally generated Taxon_###### IDs
identify taxonomy rows; they are not representative sequences.
Use native Windows R 4.5.3, Python 3.12, and the existing synchronized
renv library. The optional bootstrap checks that baseline and provisions
mapper assets and optional binary packages separately. It preserves the
baseline library. Run from the repository root in PowerShell:
$env:RENV_CONFIG_AUTOLOADER_ENABLED = 'FALSE'
$env:R_LIBS = (Resolve-Path 'renv/library/windows/R-4.5/x86_64-w64-mingw32').Path
$env:LC_ALL = 'English_United States.utf8'
Rscript --version
python --version
Rscript --vanilla tests/setup_faprotax2_windows.R
if ($LASTEXITCODE -ne 0) { throw 'Optional mapper setup failed' }
Rscript --vanilla analysis/00_run_pipeline.R `
--config tests/fixtures/faprotax2/config.taxonomy.yml `
--modules faprotax2 `
--output-dir 'output/faprotax2-taxonomy-repro' --validate-only
if ($LASTEXITCODE -ne 0) { throw 'Validation failed' }
Rscript --vanilla analysis/00_run_pipeline.R `
--config tests/fixtures/faprotax2/config.taxonomy.yml `
--modules faprotax2 `
--output-dir 'output/faprotax2-taxonomy-repro'
if ($LASTEXITCODE -ne 0) { throw 'Taxonomy mapper failed' }
Rscript --vanilla tests/verify_faprotax2_run.R 'output/faprotax2-taxonomy-repro'The baseline path above is the standard existing Windows project library;
resolve and inspect the actual installed library before using an alternative
path. Setup rejects a missing or mismatched baseline and reuses only
hash-matched cached downloads. It does not restore the baseline automatically.
The setup library is an overlay: shared project/R dependencies remain available,
and each run records their resolved versions, locations and DESCRIPTION hashes.
Keep result directories separate from mapper, reference and package caches.
Choose a fresh result directory, or explicitly request --overwrite for owned
results you intend to replace.
For all nine modules, use
--modules qc,alpha,beta,composition,ordination,shared,kreport,faprotax,faprotax2.
Single-sample comparative analyses retain their structured skips. To compare
both functional backends on the same input, request --modules faprotax,faprotax2
and run tests/compare_faprotax_backends.R on that completed output. Detailed
comparison evidence must go under a separate ignored output/ directory.
Add the following block to an existing pipeline config; paths resolve relative to that YAML file. The public fixture config supplies a runnable example after the optional setup.
faprotax2:
mode: taxonomy
mapper_path: path/to/FAPROTAX-mapper_v2.0/faprotax.R
reference_dir: path/to/FAPROTAX-mapper_v2.0/FAPROTAX_ref_data
mapper_library: path/to/optional-mapper-library
nthreads: 1
timeout_seconds: 600
top_n_functions: 20The adapter pins the audited script and all six reference files, checks optional
dependencies before output mutation, and invokes Rscript with argument vectors.
It uses the reference's per-function defaults, normalize=none and no probability
weighting. One thread is the verified default. The pipeline seed is not forwarded
to the external mapper; two local unseeded fixture repeats were byte-identical,
which does not guarantee determinism across inputs, platforms or binary builds.
09_FAPROTAX2/ contains the long function-abundance table, coverage table,
positive feature/function assignments, top-function PNG and provenance JSON,
plus the input/identity crosswalk, original mapper matrices/report and process
stdout/stderr. The raw states are 1 / 0 / NA for predicted presence / predicted
absence / unknown; annotation probabilities are unitless. Estimated function
abundance is t(states with NA replaced by 0) %*% eligible taxon counts. Unknown
states remain visible in the raw tables. Functions overlap and their independent
abundances can sum above the input total.
Coverage separates eligible/excluded input and taxa with positive function
states. KnownAbsenceOnlyAbundance means rows whose model states are all zero;
absence is still a prediction. Coverage is not a placement-accuracy measure:
unrecognized taxonomies can receive broad fallback predictions. With no eligible
prokaryotes the module writes one structured skip record. Missing software or
altered pinned references fail preflight.
These phenotype predictions do not establish genes, pathway completeness, expression, measured activity or pathogenicity. See the native production validation and independent backend comparison for exact tested commands, results and limits. CI exercises offline adapter contracts and real child-process failure handling; the licensed official-mapper integration was verified locally rather than added as an automatic online CI download.
The official mapper accepts representative 16S FASTA plus matching feature
abundances. The supplied local ASV datasets had exact FASTA/table correspondence
and were Illumina/DADA2-derived. The native one-feature trial reached alignment
and APPLES placement, then failed the mapper's reference-tree consistency check;
no function table was produced. faprotax2.mode: sequence is therefore explicitly
rejected. It has no verified pipeline usage example or representative-feature
input schema exposed by this implementation. The
sequence trial report records the
portability fixes, failed gate and local reproducibility artifacts.
Kraken2 abundance tables contain Bracken species estimates (E) plus raw
unclassified reads (U), so their total is T = E + U. Raw Kraken assignment
counts use N = C + U; the classified population absent from retained species
estimates is recorded separately as D = C - E. Alpha diversity and taxonomic
composition use the species estimates. Builtin HTML exports state this basis.
To combine compatible single-sample results, run
Rscript analysis/utils/merge_wf16s_cohort.R --input RUN1 --input RUN2 --output-dir COHORT.
Each repeated --input accepts a literal path, including commas and semicolons.
The merger validates report and assignment accounting before publication or
--validate-only success. Its generated config references
input.cohort_merge_manifest; the pipeline checks the merged abundance hash,
original source hashes, and per-sample file mappings, and inventories those
inputs throughout the run. Metadata and analysis settings remain editable.
Merger --overwrite requires an unchanged merger bundle without unrelated
files; choose a new destination once analysis outputs have been added.
For local review of uncommitted code, pipeline runs and
tests/verify_release_run.R accept explicit --allow-dirty. Verification still
checks exact source hashes and artifacts; clean release verification remains
the default.
- Generates standard 6-column
.kreportfiles directly from the abundance tree:- Percentage of total reads rooted at this clade
- Number of reads in clade (direct + descendants)
- Number of reads assigned directly to taxon
- Rank code:
U,R,D,K,P,C,O,F,G,S(Standard Kraken rank codes; kingdom isK) - NCBI Taxonomy ID
- Indented scientific name (2 spaces per depth level)
- NCBI Taxonomy Resolution:
- Offline default (
network_mode: cache_only): resolves TaxIDs using localtaxonomy_cache.jsonwithout internet requests. - Assignment-derived TaxIDs are written to a run-local resolved cache; an offline run does not mutate the configured source cache.
- Opt-in refresh (
--refresh-taxonomy): performs a local preflight and then one NCBI Entrez E-utilities resolution pass with bounded retry/backoff, per-request rate limiting, and transactional cache replacement. Multiple processes or clients sharing an IP must coordinate their aggregate NCBI request rate externally. - Local refresh validation (
--validate-only --refresh-taxonomy) makes no network requests or filesystem changes. It reportstaxonomy_resolution=pending_onlinewhen nodes still require resolution;unresolved_policy: erroris deferred until an online resolution pass has occurred. - Explicit full online validation (
--validate-only --refresh-taxonomy --online-preflight) performs the same read-only resolution and failure-policy checks as execution.--online-preflightis rejected during normal execution to prevent an accidental duplicate full-network pass. --online-preflightrequireskreportamong the requested modules; a validation request for modules such asqcalone is rejected instead of silently skipping the taxonomy check.- Fatal request failures and malformed/inconsistent NCBI responses fail under both unresolved policies. Valid not-found, ambiguous, or context-mismatched records remain unresolved under
warnand fail undererror. - Current NCBI
domainrecords are accepted only as an alias for legacysuperkingdomat the canonical Bacteria, Archaea, and Eukaryota roots; scientific-name and ordered-ancestry validation remains strict, and Kraken rank codes are unchanged. - Refresh execution writes flushed, credential-safe operational evidence under the output parent's
.wf16s-diagnostics/<transaction-id>/directory. Non-empty evidence survives ordinary staging cleanup; normal transaction cleanup removes only an empty directory owned by that transaction, never the shared diagnostics root. These logs are not scientific outputs, and an empty transaction directory may remain after hard operating-system termination outside the managed process tree. - Unresolved and conflicting mappings are exported explicitly. Conflicting assignment mappings retain the modal TaxID (minimum numeric TaxID on a tie) for backward-compatible Kreport output, but are labeled
Conflicted/assignment_conflict, emit a run warning, and must not be treated as authoritative without review. Named nodes with TaxID0should be resolved before treating the report as taxonomy-complete in Pavian. - The tracked cache-only reference run intentionally reports 46 unresolved taxonomy nodes and 26 conflicting lineage-to-TaxID mappings. These diagnostics are surfaced rather than silently discarded.
- Offline default (
- Interactive Sankey Visualization:
- Generated
.kreportfiles can be uploaded to Pavian for interactive Sankey and sunburst diagrams.
- Generated
Krona export is an extension of the kreport module and does not add a
separate module name. Enable it with either the CLI switch or YAML:
Rscript analysis/00_run_pipeline.R \
--config config.yml \
--modules kreport \
--krona \
--overwritekrona:
enabled: true
render_html: true
html_renderer: "builtin" # builtin, kronatools, or auto
executable: "ktImportText"For each selected sample, R always writes a portable
07_Kreport/krona/<sample>.krona.tsv in the tab-delimited lineage format
accepted by KronaTools ktImportText. When render_html: true, the default
html_renderer: builtin uses analysis/utils/krona_builder.py; no Perl or
KronaTools installation is required. It writes a deterministic, standalone
<sample>.krona.html containing the Krona-compatible XML, JavaScript, and
image resources. html_renderer: kronatools is strict and fails if the
configured executable is unavailable. html_renderer: auto uses an available
external executable and otherwise falls back to the builtin renderer. Set
render_html: false to retain TSV/provenance only.
The vendored Krona 2.8.1 browser files are unmodified and SHA-256 pinned in
analysis/vendor/krona-2.8.1/SOURCE.json; the wrapper is described as
Krona-compatible, not as official Krona software. The module writes
07_Kreport/krona/krona_provenance.json with renderer policy/version, vendor
manifest hashes, HTML status, and exact read-accounting reconciliation.
Builtin Krona XML records both magnitude (the clade total) and
magnitudeUnassigned (the direct assignment at that node), including internal
nodes and the dataset root. Krona artifact paths in provenance use the
path_basis = "run_dir" contract: they are POSIX-style paths relative to the
completed run root and carry SHA-256 hashes, so they remain valid after private
module staging is removed or the completed run is moved as a unit. The pipeline
renderer identity comes from VERSION; the upstream Krona identity comes from
the pinned vendor manifest.
Krona magnitudes use direct positive-count taxonomy rows plus one explicit
top-level Unclassified contribution when applicable. Ancestor clade counts
are not emitted separately, and Krona generates its own root. The output is a
visualization of the classifier-conditioned abundance table, not independent
taxonomic validation.
Set pavian.enabled: true or pass --pavian with kreport requested. The
pipeline keeps <sample>.kreport as the six-column Kraken report intended for
official Pavian upload/use. It also writes taxonomy_resolution.tsv and, when
enabled, creates 07_Kreport/pavian/<sample>.pavian.json, an optional
<sample>.pavian.html, and pavian_provenance.json.
The primary built-in visualization output is the deterministic Sankey artifact
under 07_Kreport/pavian/sankey/<sample>.sankey.json and, when enabled,
<sample>.sankey.html. The Sankey model is a classified clade-read flow with
persistent Other and Assigned above residual lanes. Every selected rank
column and transition conserves classified reads, including hidden taxa,
intermediate residual carries, direct counts, and zero-classified runs. Use
pavian.sankey.ranks and pavian.sankey.max_taxa_per_rank to choose the
default view; the standalone HTML also supports transient rank/top-N views.
pavian:
enabled: true
render_html: true
sankey:
enabled: true
render_html: true
ranks: ["D", "K", "P", "C", "O", "F", "G", "S"]
max_taxa_per_rank: 10The HTML is an original dependency-free static explorer, not the upstream
Pavian Shiny application. It embeds the normalized JSON as Base64, uses a
restrictive offline CSP, performs no taxonomy lookup or network request, and
preserves resolved, unresolved, and assignment-conflict status from the
resolution sidecar. The .kreport remains the real Pavian-compatible upload
artifact; the built-in explorer and Sankey are reproducible local renderers,
not a bundled Pavian server or a claim of upstream Pavian implementation
equivalence. Set pavian.render_html: false to retain deterministic JSON and
provenance without HTML. Sankey HTML is emitted only when both
pavian.render_html and pavian.sankey.render_html are true; the effective
states are recorded in provenance and manifest revision 4.
config.yml is the tracked Ambar Ayunda regression demonstration.
config.example.yml is a copy-and-edit template pre-populated for that
single-sample demonstration. Give cohort projects their own abundance table,
metadata, assignment mapping, and a fresh output directory.
On Linux, the locked igraph binary also requires the GLPK runtime library
(libglpk40 on the Ubuntu release runner).
# Check core installed packages (exits non-zero if missing)
Rscript analysis/install_packages.R
# Install missing core packages from CRAN
Rscript analysis/install_packages.R --install
# Check optional module dependencies (e.g. FAPROTAX / microeco)
Rscript analysis/install_packages.R --modules faprotax
# Install optional module dependencies from CRAN
Rscript analysis/install_packages.R --install --modules faprotax
# Audit all dependencies including optional modules
Rscript analysis/install_packages.R --allRscript analysis/00_run_pipeline.R --config config.yml --validate-only# Run pipeline with default config (writes to output/)
Rscript analysis/00_run_pipeline.R --config config.yml
# Override output directory and allow overwrite
Rscript analysis/00_run_pipeline.R --config config.yml --output-dir output --overwriteUse a new output root for publication runs. A non-empty output root may only be
reused with --overwrite when it contains a valid pipeline-owned manifest;
the rerun is staged transactionally and replaces the complete owned product set,
while unrelated files are preserved. Normal publication runs also require a
synchronized renv.lock environment and a clean maintained source tree. The
development-only --allow-unlocked and --allow-dirty flags record the
exception in provenance.
For a cohort, the same sample identifiers must appear in all applicable inputs:
abundance columns: Sample_A, Sample_B
metadata SampleID: Sample_A, Sample_B
assignment keys: Sample_A, Sample_B
Set mode: cohort, provide metadata with unique SampleID and non-empty
Group columns, and ensure those IDs match the selected abundance columns
exactly. metadata.example.tsv demonstrates the metadata format only; it is
not paired with the tracked one-sample abundance fixture.
Rscript analysis/install_packages.R --restore
Rscript -e "files <- list.files('analysis', pattern='[.]R$', recursive=TRUE, full.names=TRUE); invisible(lapply(files, parse))"
python -m compileall -q analysis tests
Rscript tests/testthat.R
python -m unittest -v tests/test_ncbi_taxonomy.py tests/test_check_committed_whitespace.py
Rscript analysis/00_run_pipeline.R --config config.yml --validate-onlyThe test suite creates a temporary synthetic cohort at runtime to verify
software behavior only; no biologically validated cohort dataset is included.
The committed renv.lock pins the R 4.5.3 package graph, including test tooling
and microeco; use analysis/install_packages.R --restore before release or
publication runs. The lock covers this post-processing environment, not the upstream
wf-16s workflow, ONT basecaller, reference database archive, or optional
KronaTools executable.
Version 0.5.0 uses manifest schema v2 revision 5. It retains strict artifact
accounting, SHA-256 and byte-size digests for every owned product, explicit
preserved unowned output tracking, and physical output census verification.
Each run also records an ordered source_files path/SHA-256 inventory for the
maintained producer scope and an aggregate digest derived from exact
path<TAB>sha256 records. exports.krona and exports.pavian state the
resolved effective export contract, including the Sankey ranks, top-N limit,
and parent/child HTML gates; Pavian is still an extension of kreport, not a
ninth pipeline module.
Cardinality-dependent fields such as samples, requested modules, package versions, input
collections, module outputs/warnings, artifacts, and Krona provenance samples are always
JSON arrays, including zero and one item. Failed fail-fast runs retain later
requested modules as not_run records with null execution timestamps. Every v2
manifest records whether the environment is locked, the SHA-256 of the
repository renv.lock used for the run, the supplied configuration file's
SHA-256 and byte size, and available package identity metadata from the lockfile
and installed DESCRIPTION files.
Publication safety includes exclusive file locking (.wf16s_output.lock) preventing concurrent
pipeline execution against the same output root, isolated per-module private staging directories,
and hashed sibling transaction journals (.*.wf16s_journal.json) that guarantee deterministic
rollback or forward-recovery across aborted writes. Online taxonomy refresh is computed into the
run-local resolved cache first, then commits the shared source cache under an inter-process lock;
a sibling taxonomy transaction journal and hash comparisons restore or forward-recover an interrupted
commit without overwriting an unrelated cache revision. True zero-mutation
--validate-only checks perform in-memory AST syntax validation without writing bytecode or touch files.
The cohort merger uses the same destination lock and its own schema-validated sibling journal. It
fingerprints the complete prior bundle before replacement, verifies the renamed backup and staged
bundle, and retains recovery material whenever either changes. Resource preflight uses the requested
modules in both validate-only and execution modes. resource_budgets names the units it limits:
sample-by-sample matrix cells, sample-pairs multiplied by taxa, samples multiplied by admissible
permutation rows, sample-by-taxon resampling cells multiplied by iterations, alpha long-table rows,
and original-tree covariance cells.
The tracked assignment fixture retains its typed-column digest under the streamed
reader. On this Windows R 4.5.3 host, the manual 250,000-row benchmark completed
in 13.33 seconds, returned a 30.53 MiB data frame, and observed a 343.27 MiB
process peak working set. Run Rscript tests/benchmark_assignment_parser.R --rows=250000
on each target host for local performance evidence.
| Option | Description |
|---|---|
-c, --config PATH |
Path to YAML config (default: config.yml) |
-o, --output-dir PATH |
Override output directory |
-m, --modules LIST |
Comma-separated modules: qc,alpha,beta,composition,ordination,shared,kreport,faprotax,faprotax2 |
--validate-only |
Run the same requested-module preflight checks without writing to disk |
--keep-going |
Continue executing remaining modules if one fails |
--refresh-taxonomy |
Enable online NCBI queries to resolve missing TaxIDs |
--online-preflight |
With --validate-only --refresh-taxonomy, perform full read-only online resolution; rejected during execution |
--allow-unlocked |
Development-only escape hatch for a missing/mismatched lock (recorded as unlocked) |
--allow-dirty |
Development-only escape hatch for maintained source changes (recorded as dirty) |
--allow-large-workload |
Override a configured resource budget after reviewing validate-only preflight estimates |
--krona |
Enable Krona TSV export and builtin or policy-selected HTML rendering (requires kreport) |
--pavian |
Enable official-Pavian-compatible .kreport integration plus the builtin offline explorer and Sankey (requires kreport) |
--overwrite |
Replace the complete set of pipeline-owned products in a validated output root |
Original standalone scripts (analyze_16s_improved.R, analyze_16s.R, convert_to_kreport.R, fetch_ncbi_taxonomy.py) remain preserved under archived/ for retrospective comparison. New analyses should use analysis/00_run_pipeline.R.
Version 0.5.0 covers validated NCBI/minimap2/Kraken2/Bracken species parsing, exact separate read and estimate accounting,
single-sample summaries, deterministic multi-rank classified-read and estimate composition
figures and heatmaps, synthetically and real-bundle tested cohort modules, offline-by-default
taxonomy resolution, Pavian-ready Kraken reports, the opt-in Krona export,
original offline Kraken-report explorer, the conservation-checked offline
taxonomy Sankey renderer, an opt-in FAPROTAX 1.2.12
functional inference module (via locked microeco 2.3.0), and the standalone merge_wf16s_cohort.R
multi-bundle merger utility. It also includes
manifest schema v2 revision 5, producer-source inventory, bounded assignment
parsing, physical output census verification, transaction journals, and
multi-process cache locking. The project does not include differential
abundance, phylogenetic UniFrac, FAPROTAX2-db, PICRUSt2, the upstream Pavian
Shiny application, or biological validation of cohort statistics or
species-level calls. Version 0.5.0 follows 0.4.9.
Unreleased changes add the opt-in FAPROTAX-mapper 2.0 taxonomy backend and manifest revision 6. Sequence mode remains gated by the failed native proof; no version bump or release tag is included in this migration.
See CHANGELOG.md for release history and CITATION.cff for citation metadata. The code is available under the MIT License.