Hybrid mode¶
mode: hybrid — Illumina and ONT reads from the same isolate. Sixteen rules, in
workflow/rules/hybrid/, and the most expensive mode to run: it assembles twice.
The two technologies have opposite error profiles. Long reads span the repeats that break a short-read assembly but still get individual bases wrong, most often indels in homopolymers, which frameshift genes and ruin an annotation. Short reads cannot span a repeat but they get the base right. Hybrid mode builds the genome from the long reads and then corrects it with the short ones.
flowchart TD
subgraph SR["1. the short-read arm builds a comparator genome"]
direction TB
IR([Illumina R1 and R2])
PX[map_phix] --> TR[trim_adapters<br/>fastp]
IR --> PX
TR --> SA[illumina_assembly<br/>SPAdes --isolate]
SA --> SF[filter_contigs]
SF --> SSC[contamination screen]
SSC --> SEL([contigs_sel.fasta<br/>the clean short-read assembly])
end
subgraph LR2["2. the clean short reads then filter the long ones"]
direction TB
IDX[index_selected_contigs<br/>bowtie2-build]
MSC[map_sel_contigs<br/>keeps only pairs that match]
SELR([SEL_R1 and SEL_R2])
IDX --> MSC --> SELR
end
SEL --> IDX
TR --> MSC
subgraph LA["3. the long-read arm assembles and is polished twice"]
direction TB
OR([ONT reads])
Q1[raw_long_read_qc]
FL[filter_long_reads<br/>Filtlong, scored against the short reads]
Q2[filtered_long_read_qc]
ASM[ont_assembly<br/>Flye]
FIX[fix_start<br/>dnaapler]
MED[long_read_consensus<br/>Medaka, long reads]
POL[short_read_correction<br/>Polypolish, short reads]
OR --> Q1
OR --> FL --> Q2
FL --> ASM --> FIX --> MED --> POL
end
SELR --> FL
SELR --> POL
CMP[compare_hybrid_assemblies<br/>Snippy, long vs short]
POL --> CMP
SEL --> CMP
FSC[contamination screen]
OUT([contigs_final.fasta])
POL --> FSC --> OUT
Read it as three stages. The short reads are assembled first, not because that assembly is the product, but because a clean short-read assembly is the best available filter for the long reads: only the pairs mapping to it survive, and Filtlong then scores every ONT read by how much of it those pairs support.
Terms used on this page
| ONT | Oxford Nanopore Technologies, the long-read sequencing platform |
The Illumina leg is the ONT leg's contamination filter¶
This is the design that makes the mode hybrid.
There is no BLAST/BlobTools screen on the long-read assembly. Instead the screen runs
on the Illumina draft, and the Illumina reads that map as proper pairs back to the
decontaminated assembly are pulled out (map_sel_contigs, keeping SAM flag 0x2).
That read set is, by construction, reads from the organism the screen decided to keep
— a contamination-filtered read set obtained without classifying a single read.
Those pairs are then handed to Filtlong as -1/-2. Given short reads, Filtlong stops
scoring by quality alone and asks how much of each long read is supported by k-mers
from the trusted short reads. A long read from a contaminant has no such support, so
one step does the quality filtering and the decontamination together.
A contig dropped by the screen takes its long reads with it
The consequence runs further than the taxonomy table. If the contamination screen removes a genuine contig — a small broad-host-range plasmid is the case that happens, see Decontamination — the reads covering it are absent from the Filtlong reference, the ONT reads covering it score as low quality, and the sequence never reaches Flye at all. It disappears from the assembly rather than merely from the taxonomy.
This is independent of the Filtlong settings below. Both can delete a plasmid, for different reasons, and both are worth ruling out.
The Filtlong flags differ from nanopore mode on purpose:
| Flag | From | Default | Why it differs here |
|---|---|---|---|
--min_length |
parameters.long_read_qc.min_length |
1000 | same as nanopore |
--keep_percent |
parameters.long_read_qc.keep_percent |
95 | same key, same effect on small plasmids (Nanopore mode) |
--length_weight |
parameters.long_read_qc.length_weight |
1 | only reaches Filtlong here. At 10 the 1–3 kb read band is emptied whatever keep_percent says |
--trim, --split 1000 |
fixed | — | cut unsupported read ends, and break a read at any unsupported 1 kb stretch — how a chimeric read is separated |
--target_bases |
not passed | — | the short reads define what is worth keeping, so no coverage cap is needed |
Two genomes, and which one is delivered¶
The ONT assembly is the deliverable. The Illumina assembly is not a by-product: it is what the screen runs on, it is the source of the clean read set, and it is kept as the comparator genome.
| Built from | Role | |
|---|---|---|
contaminants/contigs_sel.fasta |
SPAdes, decontaminated | comparator: QUAST, CheckM and GTDB-Tk all evaluate it too, and Snippy uses it as the reference |
contigs_final.fasta |
Flye → dnaapler → Medaka* → Polypolish | the delivered genome, annotated by every downstream stage |
{sample}_qc_genomes.tsv in 02.assembly/{sample}/eval/ says which is which. In the
MultiQC report the two appear as separate rows — completeness Illumina | {sample} and
completeness ONT | {sample}.
The two FASTAs have entirely different contig names, because the screen ran on one and
the delivered genome came from the other. That is expected, and it is why the plasmid
stage gets a second BLAST table of contigs_final.fasta to look contigs up by ID.
Polypolish¶
short_read_correction aligns each mate separately with bwa mem -a — all
alignments, not just the best — because Polypolish needs to see every place a read
could have come from. polypolish filter then drops alignments inconsistent with the
insert size, which is what makes correction inside repeats safe, and polypolish
polish writes the corrected sequence.
Polypolish always runs, whether or not Medaka did, so this mode needs no
finalize_contigs step: its last rule is unconditional.
The Snippy comparison¶
compare_hybrid_assemblies aligns four stages of the ONT genome against the
Illumina assembly and counts the variants: the raw Flye assembly, the reoriented one,
the Medaka consensus, and the Polypolish-corrected genome. A well-behaved run shows
the count falling towards zero as polishing proceeds.
The digest is 02.assembly/{sample}/snps/SNPs_summary.txt, with the four Snippy
directories beside it. With Medaka off, stage 03 holds a skipped.txt instead.
A variant count of zero does not mean two assemblies are identical
Snippy reports small variants in aligned regions only. Contig joins, structural differences and unaligned sequence are invisible to it, so the summary has to be read together with the contig count and the assembly size. The rule prints that caveat into the file itself.
What it writes¶
Everything illumina and nanopore write, plus:
| Path | Contents |
|---|---|
01.reads/{sample}/illumina/{sample}_sel_R{1,2}.fastq |
the decontaminated Illumina pairs. Kept, not temporary — they are a useful deliverable, and deleting them would drag SPAdes and the whole screen back through the DAG to recreate them |
02.assembly/{sample}/polypolish/ |
empty at the end; every file in it is temporary |
02.assembly/{sample}/snps/ |
the four Snippy runs and SNPs_summary.txt |
02.assembly/{sample}/contaminants/{sample}_final_blastout |
the second BLAST, over the delivered genome, for the plasmid stage |
Environments built: everything illumina and nanopore need except minimap (a hybrid
run has short reads, so it maps with Bowtie2), plus polypolish and snippy.