16S rRNA (bacteria and archaea)¶
16S is the default marker: config/config.yaml ships with amplicon.type: 16S.
Where 16S settings come from
The YAML blocks on this page are examples of what to put in your own config; the page itself sets nothing. Two files decide how a 16S run behaves, and they do not overlap:
workflow/markers/16S.yaml— the marker pack. Facts about the marker: which databases to use, that the amplicon length is measured by in-silico PCR against SILVA, that Metaxa2 is the region extractor, which ranks the tables have (eight slots on SILVA 144, Domain to Species; seven on SILVA 138.2, which has no kingdom; the last slot, Species, only the separate species database can fill). It holds no run settings, and you normally do not edit it.config/config.yaml, plus any run config merged on top — the choices about your experiment: primers, expected length, truncation, taxon filter, paths.
The pack is read separately and is never merged into the config, so almost no
setting can come from both. The exceptions sit under references:. A
database path there wins over the pack default — that is how you point at a shared
copy of SILVA instead of downloading your own — and references.silva.release
replaces the pack's default SILVA release. The full picture is in which file a setting actually comes from.
Setting up a run¶
Set type: 16S and supply the forward and reverse primer FASTAs for the region
amplified. The rest of the block below reproduces the shipped defaults for the keys you
are most likely to want to set on a 16S run — not every key the run touches; cutadapt,
trunc_len and length_filter are covered further down and in the
configuration reference. You do not need to copy any
of it into your own config to get these values, since the template already provides them.
The two exceptions are keep and discard: those ship commented out, so the values
shown are the recommended 16S starting point rather than something already in effect.
amplicon:
type: 16S
primers:
fwd: /path/to/fwd_primer.fasta
rev: /path/to/rev_primer.fasta
orientation: fixed # fixed | mixed
expected_length: auto # in-silico PCR against SILVA
probe_length_stat:
16S: p95 # which statistic of the probe distribution to use
min_overlap: 12 # bp of R1/R2 overlap the truncLen pair must preserve
extraction:
enabled: true # Metaxa2
taxonomy:
method: sintax # rdp | sintax
min_boot: 80 # rdp only
sintax_cutoff: 0.8 # sintax only
try_rc: true # rdp only
silva_other: verbatim # SILVA 144 only: verbatim | strip
filter:
enabled: true
keep: [d__Bacteria, d__Archaea] # recommended, ships commented out
discard: [o__Chloroplast, f__Mitochondria] # recommended, ships commented out
discard_min_support: 50 # best-hit check for discard; null = off
organelles: metaxa2 # drop what Metaxa2 calls organelles; off = keep
Note
amplicon.probe_length_stat.16S must be present for a 16S run, whether or not
expected_length is auto — MetaFlux checks the key at start-up and exits with a
message naming it if it is missing. The shipped config/config.yaml already has it.
Reference databases¶
16S is classified against SILVA. MetaFlux ships two SILVA releases: SILVA 144, the
default, and the previous release, SILVA 138.2, which a run can still choose.
None of the files needs to be listed in the config: the marker pack carries the file
names, download URLs and md5 checksums, and MetaFlux fetches what the run needs on
first use into references.refdb_root (default refdb), where it stays cached for
later runs. Every download is checked against its md5 before anything uses it; on a
mismatch the file is deleted and the run stops.
SILVA 144 (default)¶
The DADA2 files for SILVA 144 are built and published by the SILVA team itself
(arb-silva.de); the
138.2 files come from the DADA2 author's own Zenodo record (below). MetaFlux downloads
the 144 files from the release folder, release_144, rather than from
"current-release", so the address does not change when SILVA 145 comes out.
| Pack symbol | Path under refdb_root |
What it is | How it arrives |
|---|---|---|---|
silva_train_raw |
silva/silva_nr99_v144_toGenus_trainset.fa.gz |
the training set exactly as SILVA publishes it, seven ranks; also the in-silico PCR substrate | download from SILVA (rule fetch_silva_train_raw) |
silva_train |
silva/silva_nr99_v144_toGenus_7rank_other-verbatim_trainset.fa.gz |
the same sequences and the same seven ranks, with the kingdom names written without SILVA's --other suffix: RDP training set |
built locally (rule convert_silva_train) |
silva_sintax |
silva/silva_nr99_v144_7rank_other-verbatim_sintax.fa.gz |
SINTAX database for VSEARCH | built locally from silva_train (rule convert_silva_sintax) |
silva_species |
silva/silva_v144_assignSpecies.fa.gz |
addSpecies reference (16S, rdp only) |
download from SILVA (rule fetch_silva_species) |
With amplicon.taxonomy.silva_other: strip (see below) the two built files carry
other-stripped instead of other-verbatim in their names, so the two settings never
share a cached file. "7rank" in the names says that the files keep all seven SILVA
ranks.
The headers look like this — the differences matter for what each step can return:
silva_train_raw >Bacteria;Pseudomonadati--other;Bacteroidota;Bacteroidia;Bacteroidales;Odoribacteraceae;Odoribacter;
silva_train >Bacteria;Pseudomonadati;Bacteroidota;Bacteroidia;Bacteroidales;Odoribacteraceae;Odoribacter;
silva_sintax >25;tax=d:Bacteria,k:Pseudomonadati,p:Bacteroidota,c:Bacteroidia,o:Bacteroidales,f:Odoribacteraceae,g:Odoribacter
silva_species >AM889137.2051270.2052798 Neisseria meningitidis
The training set is a toGenus release: its lineages stop at genus, with no rank
prefixes and no species field. That single fact explains both the addSpecies step
and the rank depth of the two taxonomy methods, below.
Domain and kingdom¶
SILVA 144 re-annotated all prokaryote sequences, using LPSN as the main source of
names, and added a Kingdom rank between Domain and Phylum. Its lineages therefore
have seven ranks where 138.2 had six, and MetaFlux classifies on all seven: on SILVA 144
the domain is written d__ and the kingdom k__, followed by p__ to g__ and, from
addSpecies, s__.
d__Bacteria;k__Pseudomonadati;p__Pseudomonadota;c__Gammaproteobacteria;o__Pseudomonadales;f__Pseudomonadaceae;g__Pseudomonas
- Both come from the classifier, with the same cutoff as every other rank
(
min_bootunderrdp,sintax_cutoffundersintax). The lineage stops at the first rank below the cutoff, so an ASV that the classifier can place in a kingdom but not in a phylum reads, for example,d__Bacteria;k__Bacillati. - Nine kingdom names can occur: Pseudomonadati, Bacillati, Fusobacteriati and Thermotogati for Bacteria; Methanobacteriati, Thermoproteati, Nanobdellati and Promethearchaeati for Archaea; and Incertae Sedis, SILVA's placeholder for the few phyla it places in no named kingdom. The few eukaryote outgroup records of the file carry a domain only.
- The kingdom never carries
--other. SILVA files whole phyla underPseudomonadati--other(all of Bacteroidota, for example) and underMethanobacteriati--other. That is a note about where they sit in SILVA's tree (see the--othersuffix, below); at kingdom level it only splits one kingdom into two labels, and the taxon filter readsX--otherasXanyway. So ruleconvert_silva_trainwrites every kingdom without the suffix, whicheversilva_otheris set. It rewrites the headers only, never the sequences, and it refuses a file that does not have the shape of a SILVA 144 toGenus file (a 138.2 file, a toSpecies file, a broken download) rather than guess. - The rank set is checked. Before any classification, the
reference check makes sure that the
file the classifier reads has exactly SILVA 144's seven ranks, with a kingdom name in
the second one. A SILVA 138.2 file, whose phyla would land in the Kingdom column, or
SILVA's own download with its
--otherkingdoms, stops the run there.
The --other suffix (amplicon.taxonomy.silva_other)¶
SILVA 144 writes X--other for a clade that does not contain the nomenclatural type of
taxon X, but whose sequences SILVA still considers part of X — for example
Bacillaceae--other next to Bacillaceae, or Bradyrhizobium--other next to
Bradyrhizobium. About 40% of the reference sequences carry it somewhere in their
lineage. One setting decides what MetaFlux does with it:
silva_other |
Effect |
|---|---|
verbatim (default) |
Names are kept exactly as SILVA writes them, apart from the kingdom, which is always written without the suffix (above). The keep/discard filter treats X--other as X (so g__Bradyrhizobium also removes g__Bradyrhizobium--other), and so does the genus check of addSpecies; the species is written with the plain genus (g__Lactobacillus--other;s__Lactobacillus iners). |
strip |
The suffix is removed from every name before the classifier is trained, so X and X--other become one taxon. |
On the 16S test set (PRJNA305879, SILVA 144,
expected_length: 384, 229 ASVs), the two settings gave the same lineages apart from
the suffix itself and the depth some of them reached. Under sintax, strip took 7 ASVs
one rank further, 4 of them to genus (124 ASVs with a genus, against 120). Under rdp it
took 19 ASVs one rank further and 3 one rank less far, a net 3 more with a genus (104
against 101). Most changes add a rank, because the classifier no longer has to choose
between two labels for one taxon.
SILVA 144 also merges a few intermixed taxa into one label joined by +, each part with
its own suffix: Enterobacter--other+Klebsiella--other, Rubrivivax--other+Ideonella--other
(about 0.2% of the reference sequences). MetaFlux keeps these labels as they are:
neither the filter nor addSpecies splits them, so a token g__Klebsiella does not
remove an ASV labelled g__Enterobacter--other+Klebsiella--other. Add the full label
as a token if you need to.
Choosing SILVA 138.2¶
To run on the previous release, add this to the run config:
The 138.2 files are Benjamin Callahan's DADA2 build
(Zenodo 14169026): six ranks, Domain to
Genus, with no kingdom and no --other suffix. The training set is used as downloaded,
with no conversion step, and silva_other has no effect. The tables then have seven
slots, d__ Domain, p__ Phylum … s__ Species, and no k__:
d__Bacteria;p__Pseudomonadota;c__Gammaproteobacteria;o__Pseudomonadales;f__Pseudomonadaceae;g__Pseudomonas
The 138.2 files keep their own file names, so switching back and forth never overwrites the other release's files:
| Pack symbol | Path under refdb_root |
How it arrives |
|---|---|---|
silva_train |
silva/silva_nr99_v138.2_toGenus_trainset.fa.gz |
download from Zenodo |
silva_species |
silva/silva_v138.2_assignSpecies.fa.gz |
download from Zenodo |
silva_sintax |
silva/silva_nr99_v138.2_sintax.fa.gz |
built locally from silva_train |
Using a shared copy¶
Apart from the release, an entry under references: in the run config is needed only
to relocate a file that already exists elsewhere, for instance on a shared filesystem. Under SILVA 144, relocate
the files that belong together, so the training set and its SINTAX build always come
from the same conversion:
references:
refdb_root: refdb
silva:
train_raw: /shared/dbs/silva_nr99_v144_toGenus_trainset.fa.gz
train: /shared/dbs/silva_nr99_v144_toGenus_7rank_other-verbatim_trainset.fa.gz
sintax: /shared/dbs/silva_nr99_v144_7rank_other-verbatim_sintax.fa.gz
species: /shared/dbs/silva_v144_assignSpecies.fa.gz
train and sintax are files MetaFlux builds itself, so a path given for them is
where MetaFlux writes them, and it rebuilds them there whenever their input or the
conversion script is newer (see
reference files MetaFlux builds itself).
Amplicon length probe (probe_mode: pcr)¶
SILVA sequences are whole 16S genes (the SILVA 144 files are trimmed to the gene
itself, 138.2 still carries some flanking sequence), so the length of the amplicon the
primers actually produce has to be worked out rather than read off the database. The
amplicon_probe rule does an in-silico PCR with two Cutadapt passes over SILVA's
training set as downloaded (silva_train_raw on SILVA 144, silva_train on 138.2):
- keep the reference sequences in which the forward primer matches, trimming it and
everything upstream of it (
-g file:<fwd> --discard-untrimmed); - of those, keep the ones in which the reverse complement of the reverse primer
matches, trimming it and everything downstream
(
-a file:<rev_rc> --discard-untrimmed --minimum-length 30).
Neither match is anchored, because SILVA holds whole 16S genes and the primers bind
inside them; a match anchored to the sequence ends would find nothing. Each pass strips
the flanking gene sequence the primers would never have amplified, so what survives both
is the amplicon body itself. Primer mismatches are tolerated at
amplicon.cutadapt.max_error_rate (default 0.2).
Chloroplast, mitochondrial and eukaryote references are then left out of the length
statistics (marker pack field probe_exclude_taxa). Bacterial primers amplify organelle
SSU in silico too, often with long insertions, but those are not what a 16S survey
measures, and the taxon filter removes them from the results anyway. SILVA 144 holds
about eight times more organelle sequences than 138.2, enough to drag the statistic
along: for 799F/1175R, p95 is 397 bp with them and 386 bp without. With 138.2 it is
384 bp either way. The amplicons FASTA still contains every product.
The rule then writes the length distribution — n_amplicons, min, q1, median,
q3, p95, p99, max, mean, stdev, plus excluded_taxa and n_excluded — to a
JSON file in the project-level cache:
refdb/cache/probe_16S_silva_v144_toGenus_excl-chloroplast-eukaryota-mitochondria_<primer_hash>.json
refdb/cache/probe_16S_silva_v144_toGenus_excl-chloroplast-eukaryota-mitochondria_<primer_hash>.amplicons.fa.gz
The excluded lineages are part of the name, so a probe computed before v2.5.0 (or with a different list) is never reused by mistake.
<primer_hash> is the first 12 hex characters of a SHA-256 over the two primer files.
Different primers give a different filename, so the probe re-runs; the same primers
hit the cache, which lives inside the repository and therefore survives across runs
and across output directories.
Two steps consume the probe:
pick_trunclentakesexpected_lengthfrom the statistic named inprobe_length_stat.16S(defaultp95) and uses it in the overlap constraint.dada_length_filterbuilds its ASV length window as[q1 − window_margin, p95 + window_margin], withwindow_margindefaulting to 50 bp.
The probe only runs when expected_length: auto. A fixed integer or a [min, max]
range skips it entirely.
Warning
If no reference sequence carries both primers, the probe stops with an error rather
than returning an empty distribution. The usual causes are a primer written in the
wrong orientation for the database, or a degenerate primer that was collapsed to a
single consensus sequence before being written to the FASTA — keep the IUPAC
ambiguity codes, Cutadapt matches them. A low cutadapt.max_error_rate on a
mismatch-tolerant primer has the same effect.
Truncation¶
16S uses the standard quality-based truncation picker: truncLen is cut just before the
position where the aggregated per-base lower quartile first falls below
trunc_len.q_threshold, subject to keeping the pair mergeable —
— with trunc_len.resolve_policy deciding what happens when quality and overlap
disagree.
Three checks run in a fixed sequence. First, a coverage gate caps each sample at the
length trunc_len.min_read_coverage_pct (95%) of its reads still reach, so the quality
search cannot pick a position most reads never get to. Only then is the quality
threshold applied, and only then the overlap constraint. See
Amplicon length and truncation for the full picture, and
Troubleshooting for what a run looks like when the cut still
lands past the real read length.
Region extraction with Metaxa2¶
With extraction.enabled: true (the default), the target_extract rule runs
Metaxa2 over the ASV sequences to keep
only the part of each ASV that is genuinely small-subunit rRNA. Anything that flanks
it — primer remnants, chimeric tails, non-ribosomal carry-over — is trimmed away, so
the ASV lengths that reach the length filter are directly comparable to the probe
distribution measured on SILVA.
| Input | 05.dada2/seqs.fasta and 05.dada2/seqtab_head_names.txt, from dada_seqtab |
| Command | metaxa2 -t all --fasta T --table T --plus T --silent T |
| Output | 05.dada2/seqs_extracted.fasta, 05.dada2/seqtab_extracted_head_names.txt, 05.dada2/metaxa2_extraction.results.txt, 05.dada2/metaxa2_origin.tsv |
| Raw tool output | kept under 05.dada2/metaxa2/ for inspection |
| Consumed by | dada_length_filter; assign_taxonomy reads metaxa2_origin.tsv |
-t all means all domains are scanned and every extracted sequence is kept.
Metaxa2 is not used to decide what is bacterial: that decision is made later, by the
taxon filter, on the classified lineage. The filter does use one of Metaxa2's calls,
the organelle one: ASVs that Metaxa2 places in mitochondria or chloroplast are removed
(filter.organelles, below). ASVs Metaxa2 cannot extract are dropped from
both the FASTA and the count table, and the drop is reported in the rule log.
For 16S the pre- and post-extraction length distributions usually look almost the
same, because a clean 16S amplicon is SSU from end to end. Both are plotted in
stats/dada2/asv_length_hist.png, which makes an unexpected difference easy to spot.
Metaxa2's two origin calls¶
The organelle filter uses the second answer only, collected per ASV in
05.dada2/metaxa2_origin.tsv. The difference matters most when you open the Metaxa2
files yourself to ask how much chloroplast and mitochondrial carry-over a run had,
because the raw output under 05.dada2/metaxa2/ answers that question twice and the
two answers can differ widely.
First pass — the HMM screen. Metaxa2 begins by sliding profile HMMs along each
sequence to decide, cheaply, whether it is small-subunit rRNA at all and where the
gene starts and stops. The job of this pass is to find the rRNA and mark its edges,
not to identify it. Its verdict is the single letter in column 3 of
seqs.extraction.results (B, A, E, C, M, O for bacteria, archaea,
eukaryota, chloroplast, mitochondria, other) and the block of seqs.summary.txt
headed "SSU rRNA sequences by preliminary origin". Metaxa2 itself labels this call
preliminary.
Second pass — the BLAST refinement. The extracted regions are then aligned
against Metaxa2's reference database and classified on the alignment. This is the
call to use. It is what lands in seqs.taxonomy.txt, in the per-origin
FASTAs (seqs.bacteria.fasta, seqs.mitochondria.fasta, and so on), and in the
block of seqs.summary.txt headed "Number of SSU rRNA sequences assigned to each
origin".
On the 16S test set (PRJNA305879, six samples, default settings), Metaxa2 recognised 228 ASVs as SSU rRNA:
| Origin | First pass, HMM screen | Second pass, after BLAST |
|---|---|---|
| Bacteria | 69 | 195 |
| Chloroplast | 55 | 0 |
| Mitochondria | 104 | 29 |
| Uncertain | — | 4 |
By the first pass, 46% of these ASVs are mitochondrial and 24% chloroplast; by the second, 86% are bacterial and none is chloroplast.
The second reading is the correct one, and the disagreement is expected rather than a malfunction. Chloroplasts and mitochondria descend from free-living bacteria and their SSU genes still look bacterial, so the organellar HMM profiles and the bacterial ones overlap heavily. A fast profile scan cannot separate them; an alignment against full-length references can. The screen is deliberately permissive because its purpose is to avoid missing rRNA, not to name it.
These are ASV counts, not read counts
Every number above counts distinct sequences. On the same test set the 29
mitochondrial ASVs are 13% of the 226 ASVs that reach the taxon filter, but they
carry 1.5% of the reads (2,984 of 196,081): organellar ASVs are often numerous but
individually rare, and in a root or leaf sample it can be the reverse. To weight
by reads, use 06.taxonomy/asv_table_unfiltered.txt: it has Metaxa2's call
(metaxa2_origin) next to the per-sample counts of every ASV, the removed ones
included (see
the table with everything).
asv_table.txt will not do, because the organelle filter has already removed the
ASVs Metaxa2 calls mitochondria or chloroplast.
Taxonomy¶
amplicon.taxonomy.method picks one of two classifiers. Both read the
length-filtered ASVs (05.dada2/seqs_lenfilt.fasta plus the matching
seqtab_lenfilt_head_names.txt), both apply the same taxon filter, and both write the
same four tables into 06.taxonomy/: the three filtered ones and
asv_table_unfiltered.txt, which lists every ASV with Metaxa2's call and what the filter
did to it.
rdp |
sintax |
|
|---|---|---|
| Tool | DADA2 assignTaxonomy, then addSpecies |
vsearch --sintax |
| Reference | silva_train + silva_species |
silva_sintax |
| Confidence setting | min_boot: 80 |
sintax_cutoff: 0.8 |
| Reverse complement | try_rc: true |
--strand both, always |
| Deepest rank returned | Species, as a binomial | Genus |
| Conda environment | workflow/envs/taxonomy.yaml |
workflow/envs/vsearch.yaml |
| Reproducibility | fixed by amplicon.seed, apart from DADA2's random tie-breaking (rare, see Troubleshooting) |
fixed by amplicon.seed, at any thread count |
The RDP path classifies the unique ASV sequences and then expands the result back so every ASV ID gets its own row — extraction can leave two ASVs with an identical trimmed sequence, and this keeps them from being classified twice.
VSEARCH SINTAX needs about 2–3 GB regardless of how many ASVs are in the table, which
makes it the practical choice on large runs. With amplicon.seed fixed, its bootstrap
confidence comes out the same at any thread count, because VSEARCH 2.32, the version
MetaFlux uses from v2.5.0 on, gives every ASV its own random stream.
The species step (16S only)¶
silva_train stops at genus, so the RDP path alone cannot name a species. 16S is the
only marker whose pack declares a taxonomy_species_db, and for it the rdp branch of
assign_taxonomy runs DADA2's addSpecies against silva_species — a separate,
species-annotated SILVA file — immediately after assignTaxonomy. MetaFlux calls it
with DADA2's own defaults apart from tryRC, which follows taxonomy.try_rc (the same
setting assignTaxonomy uses), so a species is added only on an unambiguous exact match;
ASVs with no match, or with more than one, keep an empty species slot.
addSpecies returns the bare epithet (subtilis), not the full binomial, and the
Species column of taxon_seq_table.txt keeps it as it is (see
reading the tables in R for
building the binomial there). The 16S pack sets prefix_style: bare, which tells the
taxonomy-string builder two things: add the rank prefixes itself, and render the last
slot as a Genus + species binomial by gluing the genus back on. A finished 16S lineage
on SILVA 144 therefore reads (on SILVA 138.2 the same, without the k__ slot):
d__Bacteria;k__Bacillati;p__Bacillota;c__Bacilli;o__Bacillales;f__Bacillaceae;g__Bacillus;s__Bacillus subtilis
Under sintax there is no species rank at all. The SINTAX database is converted from
the same toGenus training set and carries only the ranks down to genus (d: to g:;
seven on SILVA 144, six on 138.2), so the
Species column of taxon_seq_table.txt is NA for every ASV and no s__ segment
appears in the taxonomy string. Species-level 16S calls require method: rdp, and under
sintax a filter token with the s__ prefix stops the run at start-up, because it
could never match.
Tip
Species assignment from a single 16S region is exact-match only and often absent — that is the method, not a failure of the run. Where species resolution is the point of the experiment, the two bacterial protein-coding markers are the alternative: gyrB has higher intra-genus resolution than 16S, and rpoB assigns far more ASVs to species than 16S V3–V4 does.
The prefixes are keyed to what a rank means: the domain is written d__ and, on
SILVA 144, the kingdom k__, under both methods, whatever letters the SINTAX file uses
internally. A keep: [d__Bacteria] token therefore behaves identically whichever method
is selected (see domain and kingdom, above).
Keeping and discarding taxa¶
The keep and discard lists have no built-in default — they are commented out in the shipped config on purpose, so a run that forgets them applies no tokens rather than silently applying another marker's. The organelle filter (below) is on by default and needs no tokens, so it still runs. The recommended 16S starting point:
taxonomy:
filter:
enabled: true
keep: [d__Bacteria, d__Archaea]
discard: [o__Chloroplast, f__Mitochondria]
keepruns first and defines what survives.[d__Bacteria, d__Archaea]keeps prokaryotes and drops both off-target eukaryotic hits and ASVs that stayed unclassified at domain level.discardthen prunes what is left. Chloroplast and mitochondrial 16S are amplified by most universal primers from any plant, algal or host material in the sample, and they are ribosomal enough to pass Metaxa2 — the filter is where they go.- Lab and kit contaminants a negative control revealed can be added to
discardas further genus tokens, e.g.[o__Chloroplast, f__Mitochondria, g__Ralstonia]. - ASVs that Metaxa2 calls mitochondria or chloroplast are removed as well
(
filter.organelles: metaxa2, the default;offkeeps them), and every ASV is still listed, with Metaxa2's call, in06.taxonomy/asv_table_unfiltered.txt— see the organelle filter.
Each token is matched against a whole rank segment of the taxonomy string, so
g__Bacillus matches a genus named exactly that and never a substring somewhere else
in the lineage (a SILVA 144 --other suffix is ignored, see above). A token that can
never match a 16S string stops the run at start-up, before any step: one written for
MetaFlux v2.4.0 or earlier (k__Bacteria, now d__Bacteria), a k__ token on SILVA
138.2, or a name that cannot stand in its slot (k__Fungi); see
when MetaFlux refuses a token at start-up.
If the filter removes every ASV after the classification, MetaFlux stops with an error
instead of writing an empty table — that combination nearly always means the tokens
belong to a different marker.
discard also looks one step past the reported taxonomy. The reported lineage stops at
the last rank whose confidence reaches min_boot / sintax_cutoff, and mitochondrial
16S often stays below that at order and family level although the classifier's best
hit is clearly Mitochondria — plant and algal mitochondria are diverse, and SILVA 144
holds many more of them than 138.2. Such an ASV is reported as p__Pseudomonadota,
escapes f__Mitochondria, and turns up in the abundance table and, as a very long
branch, in the tree. So an ASV is also discarded when its best hit carries a discard
token at the token's own rank with at least filter.discard_min_support support
(default 50, in percent; SINTAX confidences count ×100). Each such ASV is listed in the
log with its support. discard_min_support: null switches the check off.
On the 16S test set, with the recommended filter above and otherwise default settings,
this check removed 6 ASVs: all were reported only to phylum (p__Pseudomonadota), all
had Mitochondria as best hit, and Metaxa2 called all of them mitochondrial. Full
behaviour on Keeping and discarding taxa.
Plant mitochondria that no token catches
On the 16S test set (PRJNA305879, plant-associated),
some mitochondrial ASVs got past every token: 13 ASVs (1,421 reads) with rdp on
SILVA 144, 10 (1,292 reads) with either method on SILVA 138.2, and 3 (7 reads) with
sintax on SILVA 144, the default. rdp reported most of them as Enterobacterales,
some down to genus. Their best hit is another taxon, or Mitochondria with support
below discard_min_support, so neither the tokens nor the best-hit check can catch
them. Metaxa2 still calls them mitochondrial, and the organelle filter removes them on
that call, so at the default settings they are gone whichever classifier and release
you use. With filter.organelles: off they stay in the table.
What a 16S run produces¶
The final tables are in 06.taxonomy/:
| File | Rows | Contents |
|---|---|---|
asv_table.txt |
ASV_# IDs |
per-sample counts plus a taxonomy column |
asv_table_seqs.txt |
ASV sequences | the same table, keyed by sequence |
taxon_seq_table.txt |
ASV_# IDs |
one column per rank plus the sequence: Domain, Kingdom, Phylum … Species on SILVA 144; Domain, Phylum … Species on SILVA 138.2 |
asv_table_unfiltered.txt |
ASV_# IDs, every ASV that reached the filter |
the same counts and taxonomy, plus Metaxa2's call (metaxa2_origin) and filter_status: kept, or the filter step that removed the ASV |
Alongside them, stats/taxonomy_reference_check.json records what the reference check
saw in the SILVA file, stats/trunclen.json records the truncation decision,
stats/dada2/asv_length_stats.json and asv_length_hist.png record the ASV length
distributions before extraction, after extraction and after the length filter, and
stats/read_tracking.txt shows how many reads each sample kept at every stage. The
full layout is in Output files.
16S is also the only marker with an optional phylogeny stage: switch it on and the run adds a maximum-likelihood tree of the retained ASVs, exported unrooted, for Faith's PD and UniFrac in R. It is off by default and adds nothing to the run when it stays off. See Phylogeny (16S).