π§ Genome Assembly Fundamentals
π― What is Genome Assembly?
Genome assembly is the process of reconstructing a genome from millions of short sequencing reads. It involves overlapping reads, building contigs, scaffolding, and polishing to produce a consensus sequence representing the original genome. It's the foundation of genomics, enabling variant calling, annotation, and comparative analysis.
Why Genome Assembly Matters
Reference: Build a reference genome. Variants: Call SNPs and SVs. Annotation: Find genes. Evolution: Compare species. Disease: Identify mutations. Foundation: All genomics starts here.
# Genome Assembly β the big picture
# Reconstructing a genome from sequencing reads.
# CONCEPTUAL OVERVIEW
print("""
=== Genome Assembly ===
What it is:
- Reconstruct genome from reads
- Overlap reads β contigs
- Order contigs β scaffolds
- Correct errors β polished assembly
Why it's hard:
- Repeats confuse assembly
- Sequencing errors
- Uneven coverage
- Heterozygosity
- Large genome size
Types of assembly:
- De novo: No reference
- Reference-guided: With reference
- Comparative: Multiple related genomes
- Metagenome: Mixed community
Steps:
1. Quality control (QC)
2. Error correction (optional)
3. Assembly (contigs)
4. Scaffolding (scaffolds)
5. Gap filling
6. Polishing
7. Quality assessment
Applications:
- Reference genomes
- Variant discovery
- Comparative genomics
- Metagenomics
- Structural variation
""")
# WHY IT MATTERS
print("=== Why It Matters ===")
print("""
Biological questions:
- What is the full genome sequence?
- Where are the genes?
- What structural variants exist?
- How do species differ?
- What is the microbiome composition?
Assembly answers:
- Complete genome
- Gene annotation
- Variant discovery
- Comparative analysis
- Metagenomic profile
""")
# HISTORICAL CONTEXT
print("=== Historical Context ===")
print("""
1977: Sanger sequencing
1995: First bacterial genome (H. influenzae)
2001: Human genome (draft)
2005: Next-gen sequencing (454)
2007: Illumina/Solexa
2010: PacBio
2014: Nanopore
2019: Telomere-to-telomere (T2T)
2020s: Complete genomes, pangenomes
""")
# CHALLENGES
print("=== Challenges ===")
print("""
1. REPEATS
- Transposons, rDNA, centromeres
- Collapse or misassemble
2. HETEROZYGOSITY
- Diploid genomes
- Two haplotypes
- Phasing
3. SEQUENCING ERRORS
- Short reads: substitutions
- Long reads: indels
- Error correction needed
4. COVERAGE
- Uneven coverage
- GC bias
- Low coverage regions
5. COMPUTATIONAL
- Memory (de Bruijn graph)
- Time (large genomes)
- Scalability
""")π― Why Assembly Matters
π― The Value of Genome Assembly
A high-quality genome assembly is the foundation for almost all downstream genomic analyses β from gene annotation to population genetics.
Biological Insights
Reference: Gold standard. Variants: SNPs, SVs. Genes: Annotation. Evolution: Comparative. Disease: Mutations. Metagenome: Community.
# Why Genome Assembly Matters
print("=== 1. Reference Genome ===")
print("""
Reference genome:
- Gold standard for species
- Used for read mapping
- Variant calling
- Annotation
Examples:
- Human: GRCh38, T2T-CHM13
- Mouse: GRCm39
- Arabidopsis: TAIR10
- E. coli: K-12 MG1655
Quality:
- Contiguity (N50)
- Completeness (BUSCO)
- Accuracy (QV)
- Scaffolding
""")
print("\n=== 2. Variant Discovery ===")
print("""
Variant calling:
- SNPs
- Indels
- Structural variants (SVs)
- Copy number variants (CNVs)
Workflow:
1. Assemble genome
2. Map reads
3. Call variants
4. Annotate
Tools:
- GATK
- FreeBayes
- Delly
- Manta
""")
print("\n=== 3. Gene Annotation ===")
print("""
Annotation:
- Gene prediction
- Functional assignment
- Regulatory elements
- Non-coding RNAs
Steps:
1. Repeat masking
2. Ab initio prediction
3. Homology-based
4. RNA-seq evidence
5. Manual curation
Tools:
- BRAKER
- MAKER
- AUGUSTUS
- NCBI PGAP
""")
print("\n=== 4. Comparative Genomics ===")
print("""
Comparative:
- Synteny
- Orthologs
- Gene family evolution
- Genome rearrangements
Examples:
- Human vs chimp
- Vertebrate genomes
- Plant genomes
- Microbial pangenomes
Tools:
- MCScanX
- OrthoFinder
- SyMap
""")
print("\n=== 5. Structural Variation ===")
print("""
SV discovery:
- Deletions
- Duplications
- Inversions
- Translocations
Why assembly:
- Short reads miss SVs
- Long reads resolve SVs
- Assembly-based SV calling
Tools:
- Sniffles
- SVIM
- Assemblytics
""")
print("\n=== 6. Metagenomics ===")
print("""
Metagenome assembly:
- Mixed community
- No reference
- Strain variation
Steps:
1. QC
2. Assembly
3. Binning
4. Annotation
Tools:
- SPAdes (meta)
- MEGAHIT
- metaFlye
- MetaBAT
""")
print("\n=== 7. Pangenomics ===")
print("""
Pangenome:
- Multiple genomes
- Graph representation
- Captures diversity
Why assembly:
- Each genome assembled
- Graph construction
- Variation analysis
Tools:
- minigraph
- vg
- PanSN
""")
print("\n=== 8. Clinical Genomics ===")
print("""
Clinical:
- Rare disease
- Cancer
- Pharmacogenomics
Why assembly:
- Detect SVs
- Resolve complex regions
- HLA typing
- Pharmacogenes
Examples:
- CYP2D6
- HLA
- BRCA1/2
""")βοΈ Algorithms
π― How Assembly Algorithms Work
Genome assembly is a massive puzzle. The main algorithmic approaches are de Bruijn graphs (short reads) and overlap-layout-consensus (OLC) (long reads).
Algorithm Categories
Greedy: Merge best overlaps. OLC: Overlap-layout-consensus. De Bruijn: K-mer graph. String graph: OLC variant. Hybrid: Combine short+long. Reference-guided: Map to reference.
# Algorithms
print("=== Greedy Assembly ===")
print("""
Greedy:
1. Compute all pairwise overlaps
2. Sort by overlap length
3. Merge highest overlap
4. Repeat until no overlaps
Pros:
- Simple
- Fast for small genomes
Cons:
- Greedy (local optimum)
- Not for repeats
- Not scalable
Tools:
- TIGR Assembler
- CAP3 (ESTs)
""")
print("\n=== OLC (Overlap-Layout-Consensus) ===")
print("""
OLC:
1. Overlap: Find overlaps between reads
2. Layout: Build overlap graph
3. Consensus: Find path, call consensus
Steps:
- All-vs-all overlap
- Build graph
- Simplify
- Find contigs
- Consensus
Pros:
- Good for long reads
- Handles repeats
- Accurate
Cons:
- Slow (all-vs-all)
- Memory heavy
- Not for short reads
Tools:
- Celera Assembler
- Canu
- Flye (partly)
- HGAP
""")
print("\n=== De Bruijn Graph ===")
print("""
De Bruijn:
- Nodes = k-mers
- Edges = overlap of k-1
- Assembly = path
Steps:
1. Break reads into k-mers
2. Build graph
3. Simplify (remove errors)
4. Find paths
5. Contigs
Pros:
- Memory efficient
- Fast
- Good for short reads
- Scalable
Cons:
- Repeat resolution hard
- k-mer choice critical
- Not for long reads
Tools:
- SPAdes
- Velvet
- ABySS
- SOAPdenovo
""")
print("\n=== String Graph ===")
print("""
String graph:
- OLC variant
- Remove transitive edges
- Compressed graph
Steps:
1. Overlap
2. Build string graph
3. Simplify
4. Find contigs
Pros:
- Compact
- Fast
- Good for long reads
Cons:
- Complex
- Not for short reads
Tools:
- SGA
- Fermi
""")
print("\n=== Hybrid Assembly ===")
print("""
Hybrid:
- Combine short + long
- Short for accuracy
- Long for contiguity
Strategies:
1. Long reads β contigs
2. Short reads β polish
3. Or: Short reads β graph
4. Long reads β scaffold
Tools:
- SPAdes (hybrid)
- Unicycler
- MaSuRCA
- HASLR
""")
print("\n=== Reference-Guided ===")
print("""
Reference-guided:
- Map reads to reference
- Call consensus
- Fill gaps
Steps:
1. Align reads
2. Sort
3. Pileup
4. Consensus
5. Gaps
Pros:
- Fast
- Simple
- Good for closely related
Cons:
- Reference bias
- Miss novel sequence
- Not de novo
Tools:
- BWA
- Bowtie2
- samtools
- GATK
""")
print("\n=== Algorithm Comparison ===")
print(f"{'Algorithm':<25} {'Read Type':<15} {'Speed':<12} {'Memory':<12} {'Tools':<20}")
print("-" * 85)
print(f"{'Greedy':<25} {'Any':<15} {'Fast':<12} {'Low':<12} {'CAP3':<20}")
print(f"{'OLC':<25} {'Long':<15} {'Slow':<12} {'High':<12} {'Canu':<20}")
print(f"{'De Bruijn':<25} {'Short':<15} {'Fast':<12} {'Medium':<12} {'SPAdes':<20}")
print(f"{'String Graph':<25} {'Long':<15} {'Medium':<12} {'Low':<12} {'SGA':<20}")
print(f"{'Hybrid':<25} {'Both':<15} {'Medium':<12} {'Medium':<12} {'Unicycler':<20}")
print("\n=== Which Algorithm to Choose? ===")
print("""
Short reads only (Illumina):
β De Bruijn (SPAdes, ABySS)
Long reads only (PacBio, Nanopore):
β OLC (Canu, Flye)
β String graph (Flye, hifiasm)
Both (hybrid):
β Hybrid (SPAdes, Unicycler)
Small genome (< 10 Mb):
β SPAdes (short)
β Flye (long)
Large genome (> 1 Gb):
β HiFi: hifiasm
β Nanopore: Flye, Shasta
β Hybrid: MaSuRCA
Metagenome:
β SPAdes (meta)
β MEGAHIT
Closely related reference:
β Reference-guided (BWA + samtools)
""")πΈοΈ De Bruijn Graphs
π― The Short-Read Workhorse
The de Bruijn graph is the dominant data structure for short-read assembly. It breaks reads into k-mers, builds a graph, and finds a path representing the genome.
De Bruijn Graph
K-mer: Substring of length k. Nodes: K-mers. Edges: Overlap of k-1. Path: Genome. Simplify: Remove errors. Contigs: Unambiguous paths.
# De Bruijn Graph Assembly
print("=== k-mers ===")
print("""
K-mer = substring of length k
Example: sequence = "ACGTACGT"
k=3: ACG, CGT, GTA, TAC, ACG, CGT
k=4: ACGT, CGTA, GTAC, TACG, ACGT
k=5: ACGTA, CGTAC, GTACG, TACGT
K-mer size:
- Small k: more connections, more repeats
- Large k: fewer connections, less repeat
- Optimal depends on genome
- Usually k = 21-55 for Illumina
""")
print("\n=== Graph Construction ===")
print("""
De Bruijn graph:
- Nodes: k-mers
- Edges: if k-1 overlap
Example: reads = "ACGT", "CGTA"
k-mers:
ACG, CGT (from ACGT)
CGT, GTA (from CGTA)
Nodes: ACG, CGT, GTA
Edges:
ACG β CGT (overlap CG)
CGT β GTA (overlap GT)
Graph: ACG β CGT β GTA
Path: ACGT β ACGTA
""")
print("\n=== Simplification ===")
print("""
Errors create false k-mers:
- Remove low-coverage nodes
- Remove tips (dead ends)
- Remove bubbles (SNPs)
- Merge linear paths
Steps:
1. Count k-mers
2. Filter low-count
3. Remove tips
4. Resolve bubbles
5. Merge unitigs
Tools:
- SPAdes (built-in)
- Velvet (built-in)
- Bcalm
""")
print("\n=== Assembly Path ===")
print("""
After simplification:
- Unambiguous paths = contigs
- Branch = repeat boundary
- Cycle = repeat
Output:
- Contigs (FASTA)
- Graph (GFA)
- Coverage
Example:
Contig 1: ACGTACGTA...
Contig 2: TGCATGCAT...
""")
print("\n=== K-mer Choice ===")
print("""
K-mer size affects:
- Repeat resolution
- Contiguity
- Error sensitivity
Guidelines:
- k = 21: error correction
- k = 33: assembly
- k = 55: large genomes
- k = 77+: repeats
SPAdes:
- Uses multiple k
- Auto-select
- k = 21,33,55
""")
print("\n=== SPAdes Algorithm ===")
print("""
SPAdes:
1. Error correction
2. Multi-k assembly
3. Simplification
4. Scaffolding
5. Repeat resolution
6. Polishing
Steps:
- K-mer counting
- De Bruijn graph
- Multi-k merging
- Contig output
""")
print("\n=== Advantages & Disadvantages ===")
print("""
ADVANTAGES:
β Memory efficient
β Fast
β Scalable
β Good for short reads
β Error handling
DISADVANTAGES:
β Repeats hard
β K-mer choice critical
β Not for long reads
β Graph complexity
""")π OLC & Greedy
π― Overlap-Layout-Consensus
OLC is the classic long-read assembly approach. It finds overlaps between reads, builds a graph, and derives the consensus sequence.
OLC
Overlap: All-vs-all. Layout: Build graph. Consensus: Path. Long: Reads. Accurate: High. Slow: All-vs-all.
# OLC Assembly
print("=== Overlap ===")
print("""
All-vs-all overlap:
- Compare every read pair
- Find overlaps > threshold
- O(nΒ²) comparisons
- n = number of reads
Optimization:
- k-mer filtering
- Minimizer
- Suffix array
- Seed and extend
Tools:
- minimap2 (overlap)
- BLASR
- MHAP
""")
print("\n=== Layout ===")
print("""
Layout:
- Build overlap graph
- Nodes = reads
- Edges = overlaps
- Simplify graph
- Find paths
Graph types:
- Overlap graph
- String graph
- A-Bruijn graph
Steps:
1. Build graph
2. Remove transitive edges
3. Resolve repeats
4. Find contigs
""")
print("\n=== Consensus ===")
print("""
Consensus:
- Align reads in path
- Call consensus
- Correct errors
Steps:
1. Multiple alignment
2. Pileup
3. Consensus base
4. Quality score
Tools:
- racon (polish)
- medaka (nanopore)
- arrow (pacbio)
""")
print("\n=== Greedy Assembly ===")
print("""
Greedy:
1. Compute all overlaps
2. Sort by overlap
3. Merge highest
4. Repeat
Example:
Reads:
R1: ACGTACGT
R2: CGTACGTA
R3: GTACGTAC
Overlaps:
R1-R2: 7 (CGTACGT)
R2-R3: 7 (GTACGTA)
R1-R3: 6 (GTACGT)
Merge R1+R2:
ACGTACGT
CGTACGTA
β ACGTACGTA
Merge with R3:
ACGTACGTA
GTACGTAC
β ACGTACGTAC
""")
print("\n=== Canu Algorithm ===")
print("""
Canu:
1. Correction
2. Trim
3. Assembly
4. Polishing
Steps:
- Overlap correction
- Error correction
- Read trimming
- OLC assembly
- Consensus
Modes:
- -pacbio (CLR)
- -nanopore
- -pacbio-hifi
""")
print("\n=== Flye Algorithm ===")
print("""
Flye:
1. Overlap
2. Assembly graph
3. Repeat resolution
4. Polishing
Steps:
- k-mer (minimizer)
- Overlap graph
- Simplify
- Contigs
- Polishing (racon)
Modes:
- --pacbio-raw
- --nano-raw
- --pacbio-hifi
- --meta
""")
print("\n=== Advantages & Disadvantages ===")
print("""
ADVANTAGES:
β Handles long reads
β Resolves repeats
β High accuracy
β Good for large genomes
DISADVANTAGES:
β All-vs-all slow
β Memory heavy
β Not for short reads
β Requires coverage
""")ποΈ Scaffolding
π― Ordering and Orienting Contigs
Scaffolding orders and orients contigs into larger structures using mate-pair, paired-end, or long-read information.
Scaffolding
Contigs: Input. Links: Mate pairs. Order: Orient. Gaps: Fill. Scaffolds: Output. Hi-C: Chromosome-scale.
# Scaffolding
print("=== Why Scaffolding? ===")
print("""
After assembly:
- Many contigs
- Order unknown
- Orientation unknown
- Gaps between
Scaffolding:
- Use linking info
- Order contigs
- Orient contigs
- Estimate gaps
Result:
- Scaffolds
- Fewer sequences
- Larger N50
- More complete
""")
print("\n=== Link Types ===")
print("""
1. Paired-end:
- Same fragment
- Both ends
- Short insert
2. Mate-pair:
- Large insert
- Jumping library
- Long-range
3. Long reads:
- Span contigs
- Direct links
4. Hi-C:
- Chromatin contacts
- Chromosome-scale
5. Optical mapping:
- Bionano
- Long-range
""")
print("\n=== Scaffolding Algorithm ===")
print("""
Steps:
1. Align links to contigs
2. Build scaffold graph
3. Order and orient
4. Estimate gaps
5. Fill gaps (optional)
Graph:
- Nodes = contigs
- Edges = links
- Weight = support
- Path = scaffold
""")
print("\n=== Tools ===")
print("""
1. SSPACE
- Mate-pair
- Short reads
2. LINKS
- Long reads
- Quick
3. ARCS
- 10x linked reads
- Long reads
4. SALSA
- Hi-C
- Chromosome-scale
5. 3D-DNA
- Hi-C
- Chromosome-scale
6. RagTag
- Reference-guided
- Fast
""")
print("\n=== Gap Filling ===")
print("""
Gap filling:
- After scaffolding
- Fill N's
- Local assembly
- Close gaps
Tools:
- GapFiller
- Sealer
- LR_Gapcloser
""")
print("\n=== Example ===")
print("""
Contigs:
C1: ACGTACGT
C2: TGCATGCA
C3: GGGCCCAA
Links:
C1-C2: 10 links
C2-C3: 8 links
C1-C3: 2 links
Scaffold:
C1 β C2 β C3
ACGTACGT NNNN TGCATGCA NNNN GGGCCCAA
""")
print("\n=== Best Practices ===")
print("""
1. Use multiple link types
2. High coverage (> 50x)
3. Combine short + long
4. Validate with Hi-C
5. Check conserved synteny
""")β¨ Polishing
π― Correcting Assembly Errors
Polishing corrects errors in the assembly using reads. It's essential for accurate gene prediction and variant calling.
Polishing
Errors: Indels, substitutions. Reads: Re-align. Consensus: Call. Iterate: Improve. Long: racon, medaka. Short: Pilon.
# Polishing
print("=== Why Polish? ===")
print("""
Errors in assembly:
- Long reads: indels (~5-15%)
- Short reads: substitutions
- Assembly: consensus errors
- Gaps: false
Polishing:
- Re-align reads
- Call consensus
- Correct errors
- Improve quality
""")
print("\n=== Long-Read Polishing ===")
print("""
Tools:
- Racon
- Medaka (Nanopore)
- Arrow (PacBio)
- ntEdit
Steps:
1. Map reads to assembly
2. Pileup
3. Consensus
4. Repeat
Example:
racon reads.fastq assembly.fasta output.fasta
""")
print("\n=== Short-Read Polishing ===")
print("""
Tools:
- Pilon
- NextPolish
- iPolish
Steps:
1. Map short reads
2. Pileup
3. Consensus
4. Iterate
Example:
pilon --genome assembly.fasta --frags reads.bam --output polished
""")
print("\n=== Hybrid Polishing ===")
print("""
Hybrid:
- Long reads (contiguity)
- Short reads (accuracy)
Steps:
1. Long reads β assembly
2. Short reads β polish
3. Long reads β polish
Tools:
- Unicycler
- POLCA
- HyPo
""")
print("\n=== Quality Metrics ===")
print("""
QV (Quality Value):
- Phred-scaled error rate
- QV 30 = 99.9% accuracy
- QV 40 = 99.99%
- QV 50 = 99.999%
Tools:
- Merqury
- yak
- Jellyfish
Example:
merqury.sh kmer.meryl assembly.fasta
""")
print("\n=== Best Practices ===")
print("""
1. Polish with same reads
2. Use multiple rounds
3. Check QV
4. Validate with BUSCO
5. Check conserved genes
6. Compare to reference
7. Use Hi-C validation
""")π οΈ Tools (SPAdes, Flye, Canu)
π― Ready-to-Use Assembly Tools
Many high-quality assemblers exist. Each has strengths and is suited to different data types and genome sizes.
Tools
SPAdes: Short reads. Flye: Long reads. Canu: Long reads. Hifiasm: HiFi. Unicycler: Hybrid. MEGAHIT: Metagenome.
# Tools
print("=== SPAdes ===")
print("""
SPAdes (St. Petersburg genome assembler):
- Short reads (Illumina)
- Multi-k de Bruijn
- Hybrid mode
- Metagenome mode
- Popular
Command:
spades.py -1 reads_1.fastq -2 reads_2.fastq -o output
Modes:
--careful (recommended)
--meta (metagenome)
--rna (RNA-seq)
--hybrid (short + long)
Output:
contigs.fasta
scaffolds.fasta
graph.gfa
""")
print("\n=== Flye ===")
print("""
Flye:
- Long reads (PacBio, Nanopore)
- OLC + repeat graph
- Fast
- Metagenome mode
Command:
flye --pacbio-raw reads.fastq --out-dir output
Modes:
--pacbio-raw (CLR)
--pacbio-hifi (HiFi)
--nano-raw (Nanopore)
--nano-hq (Q20+)
--meta (metagenome)
Options:
--genome-size 5m
--threads 8
--iterations 3
Output:
assembly.fasta
assembly_graph.gfa
""")
print("\n=== Canu ===")
print("""
Canu:
- Long reads (PacBio, Nanopore)
- OLC
- Accurate
- Slow
Command:
canu -p assembly -d output genomeSize=5m -pacbio reads.fastq
Modes:
-pacbio (CLR)
-nanopore
-pacbio-hifi
Options:
genomeSize=5m
maxThreads=8
corOutCoverage=40
correctedErrorRate=0.045
Output:
assembly.contigs.fasta
assembly.contigs.gfa
""")
print("\n=== Hifiasm ===")
print("""
Hifiasm:
- PacBio HiFi
- Fast
- Accurate
- Phasing
Command:
hifiasm -o output -t 8 reads.fastq
Options:
-o prefix
-t threads
--h1 Hi-C
--h2 Hi-C
-l 0 (no error correction)
Output:
output.bp.p_ctg.fasta
output.bp.hap1.p_ctg.fasta
output.bp.hap2.p_ctg.fasta
""")
print("\n=== Unicycler ===")
print("""
Unicycler:
- Hybrid (short + long)
- Bacterial genomes
- Complete genomes
- Bridges short & long
Command:
unicycler -1 short_1.fastq -2 short_2.fastq -l long.fastq -o output
Modes:
- Normal (hybrid)
- --short (short only)
- --long (long only)
- --meta (metagenome)
Output:
assembly.fasta
assembly.gfa
""")
print("\n=== MEGAHIT ===")
print("""
MEGAHIT:
- Metagenome
- Short reads
- Fast
- Memory efficient
Command:
megahit -1 reads_1.fastq -2 reads_2.fastq -o output
Options:
--k-min 21
--k-max 141
--min-contig-len 200
--num-cpu-threads 8
Output:
final.contigs.fa
""")
print("\n=== Other Tools ===")
print("""
1. ABySS
- Short reads
- De Bruijn
2. Velvet
- Short reads
- Classic
3. MaSuRCA
- Hybrid
- Large genomes
4. Shasta
- Nanopore
- Fast
5. Raven
- Nanopore
- Fast
6. wtdbg2
- Long reads
- Fast
7. Peregrine
- HiFi
- Fast
8. Verkko
- T2T
- Human genomes
""")
print("\n=== Installation ===")
print("""
# Conda (recommended)
conda install -c bioconda spades flye canu hifiasm unicycler megahit
# Docker
docker pull quay.io/biocontainers/spades
# From source
git clone https://github.com/ablab/spades
cd spades && ./spades_compile.sh
""")π Python Integration
π― Assembly from Python
You can run assemblers from Python using subprocess and parse outputs. Here's how.
Python
subprocess: Run CLI. Bio: Parse. Stats: Analyze. Plot: Visualize. Pipeline: Automate. QC: Check.
# Python Integration
print("=== Run SPAdes ===")
print("""
import subprocess
from Bio import SeqIO
def run_spades(reads_1, reads_2, output_dir="spades_output",
threads=4, careful=True):
\"\"\"Run SPAdes assembler.\"\"\"
cmd = [
'spades.py',
'-1', reads_1,
'-2', reads_2,
'-o', output_dir,
'-t', str(threads)
]
if careful:
cmd.append('--careful')
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode != 0:
raise RuntimeError(f"SPAdes failed: {result.stderr}")
# Parse output
contigs = f"{output_dir}/contigs.fasta"
return contigs
# Use
# contigs = run_spades("reads_1.fastq", "reads_2.fastq")
""")
print("\n=== Run Flye ===")
print("""
def run_flye(reads, output_dir="flye_output",
mode="--pacbio-raw", threads=4,
genome_size="5m"):
\"\"\"Run Flye assembler.\"\"\"
cmd = [
'flye',
mode, reads,
'--out-dir', output_dir,
'--threads', str(threads),
'--genome-size', genome_size
]
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode != 0:
raise RuntimeError(f"Flye failed: {result.stderr}")
assembly = f"{output_dir}/assembly.fasta"
return assembly
# Use
# assembly = run_flye("reads.fastq", mode="--pacbio-raw")
""")
print("\n=== Run Canu ===")
print("""
def run_canu(reads, output_dir="canu_output",
genome_size="5m", mode="-pacbio",
threads=8):
\"\"\"Run Canu assembler.\"\"\"
cmd = [
'canu',
'-p', 'assembly',
'-d', output_dir,
f'genomeSize={genome_size}',
f'maxThreads={threads}',
mode, reads
]
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode != 0:
raise RuntimeError(f"Canu failed: {result.stderr}")
assembly = f"{output_dir}/assembly.contigs.fasta"
return assembly
# Use
# assembly = run_canu("reads.fastq", genome_size="5m")
""")
print("\n=== Parse Assembly ===")
print("""
from Bio import SeqIO
def parse_assembly(fasta_file):
\"\"\"Parse assembly FASTA.\"\"\"
records = list(SeqIO.parse(fasta_file, "fasta"))
total_len = sum(len(r.seq) for r in records)
print(f"Contigs: {len(records)}")
print(f"Total length: {total_len:,} bp")
print(f"Longest: {max(len(r.seq) for r in records):,} bp")
return records
def compute_n50(lengths):
\"\"\"Compute N50.\"\"\"
lengths = sorted(lengths, reverse=True)
total = sum(lengths)
cumsum = 0
for length in lengths:
cumsum += length
if cumsum >= total / 2:
return length
return 0
# Use
# records = parse_assembly("contigs.fasta")
# n50 = compute_n50([len(r.seq) for r in records])
""")
print("\n=== Assembly Stats ===")
print("""
from Bio import SeqIO
import matplotlib.pyplot as plt
def assembly_stats(fasta_file):
\"\"\"Compute assembly statistics.\"\"\"
records = list(SeqIO.parse(fasta_file, "fasta"))
lengths = [len(r.seq) for r in records]
lengths_sorted = sorted(lengths, reverse=True)
total = sum(lengths)
# N50
cumsum = 0
n50 = 0
for l in lengths_sorted:
cumsum += l
if cumsum >= total / 2:
n50 = l
break
# N90
cumsum = 0
n90 = 0
for l in lengths_sorted:
cumsum += l
if cumsum >= total * 0.9:
n90 = l
break
stats = {
'contigs': len(records),
'total_length': total,
'longest': max(lengths),
'shortest': min(lengths),
'N50': n50,
'N90': n90,
'GC': sum(r.seq.count('G') + r.seq.count('C')
for r in records) / total * 100
}
return stats, lengths
# Use
# stats, lengths = assembly_stats("contigs.fasta")
# print(stats)
""")
print("\n=== Plot Assembly ===")
print("""
def plot_assembly(lengths, output="assembly.png"):
\"\"\"Plot assembly contig lengths.\"\"\"
lengths_sorted = sorted(lengths, reverse=True)
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 5))
# Contig length distribution
ax1.hist(lengths, bins=50, color='teal', alpha=0.7)
ax1.set_xlabel("Contig length (bp)")
ax1.set_ylabel("Count")
ax1.set_title("Contig Length Distribution")
ax1.set_xscale('log')
# Cumulative
cumsum = np.cumsum(lengths_sorted)
total = cumsum[-1]
ax2.plot(range(1, len(cumsum)+1), cumsum/total*100, color='teal')
ax2.axhline(50, color='red', linestyle='--', label='N50')
ax2.set_xlabel("Contig rank")
ax2.set_ylabel("Cumulative %")
ax2.set_title("Cumulative Assembly")
ax2.legend()
plt.tight_layout()
plt.savefig(output)
plt.show()
# Use
# plot_assembly(lengths)
""")
print("\n=== Complete Pipeline ===")
print("""
import subprocess
from Bio import SeqIO
def assembly_pipeline(reads_1, reads_2=None, long_reads=None,
output_dir="assembly_output",
assembler="spades", threads=4):
\"\"\"Complete assembly pipeline.\"\"\"
# Choose assembler
if assembler == "spades" and reads_2:
cmd = ['spades.py', '-1', reads_1, '-2', reads_2,
'-o', output_dir, '-t', str(threads), '--careful']
elif assembler == "flye" and long_reads:
cmd = ['flye', '--pacbio-raw', long_reads,
'--out-dir', output_dir, '--threads', str(threads),
'--genome-size', '5m']
else:
raise ValueError("Invalid assembler or missing reads")
# Run
print(f"Running {assembler}...")
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode != 0:
print(f"Error: {result.stderr}")
return None
# Parse
if assembler == "spades":
fasta = f"{output_dir}/contigs.fasta"
else:
fasta = f"{output_dir}/assembly.fasta"
records = list(SeqIO.parse(fasta, "fasta"))
lengths = [len(r.seq) for r in records]
print(f"Assembly complete: {len(records)} contigs")
print(f"N50: {compute_n50(lengths):,} bp")
return fasta
# Use
# assembly = assembly_pipeline("r1.fastq", "r2.fastq", assembler="spades")
""")π Quality Assessment
π― Is My Assembly Good?
Assessing assembly quality is critical. Metrics include N50, BUSCO, QV, and LAI.
Quality Metrics
Contiguity: N50. Completeness: BUSCO. Accuracy: QV. Scaffolding: LAI. Gene: Completeness. MapQ: Read mapping.
# Quality Assessment
print("=== N50 / N90 ===")
print("""
N50:
- 50% of genome in contigs β₯ N50
- Higher = more contiguous
- Not a quality measure
N90:
- 90% of genome in contigs β₯ N90
- Lower than N50
Example:
Contigs: 100, 200, 300, 400, 500
Total: 1500
N50: 400 (cumsum: 500+400+300+200 = 1400 β₯ 750)
N90: 100 (cumsum: 500+400+300+200+100 = 1500 β₯ 1350)
""")
print("\n=== BUSCO ===")
print("""
BUSCO (Benchmarking Universal Single-Copy Orthologs):
- Completeness
- Single-copy
- Duplicated
- Fragmented
- Missing
Example:
C:95.0% [S:92.0%, D:3.0%]
F:2.0%
M:3.0%
Interpretation:
- C > 95%: good
- D > 10%: possible duplication
- M < 5%: good
Tools:
- busco
- compleasm
""")
print("\n=== QV (Quality Value) ===")
print("""
QV:
- Phred-scaled error rate
- QV 30 = 99.9% accuracy
- QV 40 = 99.99%
- QV 50 = 99.999%
Tools:
- Merqury (k-mer)
- yak
- Jellyfish
Example:
merqury.sh kmer.meryl assembly.fasta
""")
print("\n=== LAI (LTR Assembly Index) ===")
print("""
LAI:
- LTR retrotransposon completeness
- Assembly quality
- Plant genomes
Scores:
- LAI < 10: draft
- 10-20: good
- LAI > 20: reference
Tools:
- LTR_retriever
""")
print("\n=== QUAST ===")
print("""
QUAST:
- Assembly statistics
- N50, N90
- Misassemblies
- Genome coverage
- Comparison
Command:
quast.py assembly.fasta -o quast_output
Metrics:
- # contigs
- Largest contig
- Total length
- N50, N90
- L50, L90
- # misassemblies
- Genome fraction
""")
print("\n=== Mapping Rate ===")
print("""
Mapping rate:
- Map reads back
- Check coverage
- Uniformity
Tools:
- BWA
- Bowtie2
- samtools
Expected:
- > 95% mapping
- Uniform coverage
- No bias
""")
print("\n=== Best Practices ===")
print("""
1. Use multiple metrics
2. Compare to reference
3. Check conserved genes
4. Validate with Hi-C
5. Check telomeres/centromeres
6. Manual inspection
7. Report all metrics
""")βοΈ Tool Comparison
π― Which Assembler?
Choosing the right assembler depends on read type, genome size, and desired contiguity.
Comparison
SPAdes: Short. Flye: Long. Canu: Long. Hifiasm: HiFi. Unicycler: Hybrid. MEGAHIT: Meta.
| Tool | Read Type | Speed | Contiguity | Best For |
|---|---|---|---|---|
| SPAdes | Short | Fast | Good | Bacteria, small genomes |
| Flye | Long | Fast | Excellent | Large genomes, metagenome |
| Canu | Long | Slow | Excellent | High accuracy |
| Hifiasm | HiFi | Fast | Best | Human, large genomes |
| Unicycler | Hybrid | Medium | Excellent | Bacterial complete |
| MEGAHIT | Short | Fast | Good | Metagenome |
| Shasta | Nanopore | Fast | Good | Large genomes |
| wtdbg2 | Long | Fast | Good | Quick draft |
# Decision Guide
print("=== Choose Tool by Data Type ===")
print("""
Short reads (Illumina):
β SPAdes (best)
β ABySS
β MEGAHIT (meta)
Long reads (PacBio CLR):
β Flye
β Canu
β wtdbg2
Long reads (Nanopore):
β Flye
β Canu
β Shasta
HiFi (PacBio):
β Hifiasm (best)
β Flye
β Peregrine
Hybrid:
β Unicycler
β SPAdes (hybrid)
β MaSuRCA
""")
print("\n=== Choose Tool by Genome Size ===")
print("""
< 10 Mb (bacteria):
β SPAdes (short)
β Flye (long)
β Unicycler (hybrid)
10-100 Mb (fungi, plants):
β Flye
β Canu
β Hifiasm
> 1 Gb (mammals):
β Hifiasm (HiFi)
β Flye (Nanopore)
β Shasta
""")
print("\n=== Speed Comparison ===")
print(f"{'Tool':<20} {'10 Mb':<15} {'100 Mb':<15} {'1 Gb':<15}")
print("-" * 65)
print(f"{'SPAdes':<20} {'2 min':<15} {'30 min':<15} {'10+ hours':<15}")
print(f"{'Flye':<20} {'5 min':<15} {'1 hour':<15} {'5 hours':<15}")
print(f"{'Canu':<20} {'30 min':<15} {'5 hours':<15} {'Days':<15}")
print(f"{'Hifiasm':<20} {'2 min':<15} {'20 min':<15} {'2 hours':<15}")
print(f"{'Shasta':<20} {'1 min':<15} {'10 min':<15} {'1 hour':<15}")
print("\n=== Contiguity Comparison ===")
print(f"{'Tool':<20} {'N50 (10 Mb)':<20} {'N50 (100 Mb)':<20}")
print("-" * 60)
print(f"{'SPAdes':<20} {'100 kb':<20} {'50 kb':<20}")
print(f"{'Flye':<20} {'1 Mb':<20} {'500 kb':<20}")
print(f"{'Canu':<20} {'1 Mb':<20} {'500 kb':<20}")
print(f"{'Hifiasm':<20} {'5 Mb':<20} {'2 Mb':<20}")
print(f"{'Unicycler':<20} {'Complete':<20} {'N/A':<20}")
print("\n=== When to Use Which ===")
print("""
USE SPADES:
β Bacterial genomes
β Short reads
β Metagenome
β Fast draft
USE FLYE:
β Long reads
β Large genomes
β Metagenome
β Fast
USE CANU:
β High accuracy
β Long reads
β Small genomes
β Slow but sure
USE HIFIASM:
β HiFi reads
β Large genomes
β Phasing
β Best contiguity
USE UNICYCLER:
β Complete bacterial
β Hybrid
β Plasmids
β Small genomes
""")πΌ Use Cases
π― Where Assembly Is Used
Genome assembly is used in virtually every area of biology: reference genomes, clinical genomics, metagenomics, and more.
Use Cases
Reference: Gold standard. Clinical: Disease. Metagenome: Community. Pangenome: Diversity. SV: Structural. Annotation: Genes.
# Use Cases
print("=== 1. Reference Genome ===")
print("""
Use case:
- Build reference for species
- Gold standard
- Used by community
Workflow:
1. Collect DNA
2. Sequence (short + long)
3. QC
4. Assemble (hybrid)
5. Scaffold (Hi-C)
6. Polish
7. Assess
Examples:
- Human T2T
- Mouse
- Arabidopsis
- E. coli
Tools:
- SPAdes + Flye + Hi-C
- Hifiasm + Hi-C
""")
print("\n=== 2. Clinical Genomics ===")
print("""
Use case:
- Rare disease
- Cancer
- Pharmacogenomics
Workflow:
1. Patient DNA
2. Sequence
3. Assemble
4. Variant calling
5. Clinical report
Examples:
- CYP2D6
- HLA
- BRCA1/2
- Cancer SVs
Tools:
- GATK
- Sniffles
- Manta
""")
print("\n=== 3. Metagenomics ===")
print("""
Use case:
- Microbiome
- Environmental
- Unculturable
Workflow:
1. Sample
2. DNA extraction
3. Sequence
4. Assemble
5. Binning
6. Annotation
Examples:
- Gut microbiome
- Soil
- Ocean
- Wastewater
Tools:
- SPAdes (meta)
- MEGAHIT
- MetaBAT
- CheckM
""")
print("\n=== 4. Pangenomics ===")
print("""
Use case:
- Multiple genomes
- Graph
- Diversity
Workflow:
1. Assemble each genome
2. Build graph
3. Align
4. Analyze variation
Examples:
- Human pangenome
- Plant pangenome
- Bacterial pangenome
Tools:
- minigraph
- vg
- PanSN
- Odgi
""")
print("\n=== 5. Structural Variation ===")
print("""
Use case:
- Large variants
- Disease
- Evolution
Workflow:
1. Assemble genome
2. Compare to reference
3. Call SVs
4. Validate
Examples:
- Deletions
- Duplications
- Inversions
- Translocations
Tools:
- Assemblytics
- SyRI
- Sniffles
""")
print("\n=== 6. Gene Annotation ===")
print("""
Use case:
- Find genes
- Functional
- Regulatory
Workflow:
1. Assemble
2. Repeat mask
3. Predict genes
4. Annotate
5. Curate
Tools:
- BRAKER
- MAKER
- AUGUSTUS
- NCBI PGAP
""")
print("\n=== 7. Comparative Genomics ===")
print("""
Use case:
- Synteny
- Orthologs
- Evolution
Workflow:
1. Assemble genomes
2. Annotate
3. Compare
4. Analyze
Tools:
- MCScanX
- OrthoFinder
- SyMap
""")
print("\n=== 8. Crop Improvement ===")
print("""
Use case:
- Plant breeding
- Trait mapping
- Genome selection
Workflow:
1. Assemble crop genome
2. Annotate
3. GWAS
4. Breeding
Examples:
- Rice
- Maize
- Wheat
- Tomato
""")
print("\n=== Comparison ===")
print(f"{'Use Case':<25} {'Tool':<20} {'Output':<20}")
print("-" * 65)
print(f"{'Reference genome':<25} {'Hifiasm + Hi-C':<20} {'Chromosomes':<20}")
print(f"{'Clinical':<25} {'GATK + Sniffles':<20} {'Variants':<20}")
print(f"{'Metagenome':<25} {'SPAdes meta':<20} {'MAGs':<20}")
print(f"{'Pangenome':<25} {'minigraph':<20} {'Graph':<20}")
print(f"{'SV':<25} {'SyRI':<20} {'SVs':<20}")
print(f"{'Annotation':<25} {'BRAKER':<20} {'Genes':<20}")
print(f"{'Comparative':<25} {'OrthoFinder':<20} {'Orthologs':<20}")
print(f"{'Crop':<25} {'Hifiasm':<20} {'Genome':<20}")β FAQ
π― Frequently Asked Questions
Answers to common questions about genome assembly.
What is genome assembly?
Genome assembly is the process of reconstructing a genome from millions of short sequencing reads. It involves overlapping reads, building contigs, scaffolding, and polishing to produce a consensus sequence representing the original genome.
What is the difference between de novo and reference-guided assembly?
De novo assembly reconstructs a genome without a reference, using only the reads. Reference-guided assembly aligns reads to a closely related reference genome, which is faster and easier but can introduce reference bias.
Which assembler should I use?
Use SPAdes for short reads (Illumina), Flye or Canu for long reads (PacBio/Nanopore), and Hifiasm for PacBio HiFi. For hybrid data, try MaSuRCA or Unicycler. For small genomes, SPAdes or ABySS work well.
What is a de Bruijn graph?
A de Bruijn graph is a data structure used in short-read assembly. Nodes are k-mers (substrings of length k), and edges connect overlapping k-mers. Assembly is finding a path through the graph that represents the genome. It's memory-efficient for short reads.
What is N50 and how is it used?
N50 is a contiguity metric: the length of the shortest contig in the set of largest contigs that covers 50% of the genome. A higher N50 means a more contiguous assembly. It's one of many metrics (along with BUSCO, QUAST) for assessing assembly quality.
What is the difference between contigs and scaffolds?
Contigs are contiguous sequences assembled from reads. Scaffolds are ordered and oriented contigs with gaps (N's) between them, created using mate-pair, paired-end, or long-read information. Scaffolds are longer but contain gaps.
How do I know if my assembly is good?
Check: (1) N50 (contiguity), (2) BUSCO (completeness), (3) QV (accuracy), (4) LAI (LTR completeness), (5) Mapping rate (read support), (6) Conserved synteny (compared to reference). There's no single perfect assembly β it depends on the analysis.
What is polishing in assembly?
Polishing corrects errors in the assembly using reads. Long-read assemblies have indel errors; short-read assemblies may have consensus errors. Tools like Racon, Medaka, and Pilon re-align reads and call consensus to improve accuracy.
Can I assemble a human genome?
Yes. Use Hifiasm with PacBio HiFi reads (30-40x), or Flye with Nanopore (50x+). Add Hi-C for chromosome-scale scaffolding. The Telomere-to-Telomere (T2T) consortium has shown complete human genomes are possible.
What is the difference between assembly and mapping?
Mapping aligns reads to an existing reference. Assembly reconstructs the genome from scratch. Mapping is faster and easier but requires a reference; assembly is harder but discovers novel sequence and structural variation.
# Quick Reference
print("=== Quick Answers ===")
print("""
Q: What is assembly?
A: Reconstruct genome from reads.
Q: De novo vs reference?
A: De novo no reference; guided uses reference.
Q: Best tool short reads?
A: SPAdes.
Q: Best tool long reads?
A: Flye, Canu.
Q: Best tool HiFi?
A: Hifiasm.
Q: What is de Bruijn graph?
A: K-mer graph for short reads.
Q: What is N50?
A: Contiguity metric; higher is better.
Q: What is BUSCO?
A: Completeness metric.
Q: What is polishing?
A: Correcting assembly errors.
Q: Can I assemble human?
A: Yes, with HiFi + Hi-C.
Q: Free tools?
A: Yes β all major tools are free.
""")π Future
π― Where Assembly Is Going
The future is telomere-to-telomere, pangenomic, AI-augmented, and clinical-grade.
Future Directions
T2T: Complete genomes. Pangenome: Graph. AI: Learned assembly. Clinical: Routine. Cloud: Serverless. Integration: Unified.
# Future of Genome Assembly
print("=== 1. Telomere-to-Telomere (T2T) ===")
print("""
Trend: Complete genomes
Current:
- Draft genomes
- Gaps
- Missing repeats
T2T:
- Complete chromosomes
- No gaps
- Telomeres
- Centromeres
Achievements:
- Human T2T-CHM13 (2022)
- Complete human genome
Future:
- Routine T2T
- All species
- Clinical
""")
print("\n=== 2. Pangenomics ===")
print("""
Trend: Graph genomes
Current:
- Linear reference
- Single genome
Pangenome:
- Multiple genomes
- Graph representation
- Captures diversity
Examples:
- Human pangenome
- Plant pangenome
- Bacterial pangenome
Tools:
- minigraph
- vg
- Odgi
- PanSN
""")
print("\n=== 3. AI-Augmented Assembly ===")
print("""
Trend: Deep learning
Ideas:
- Learned assembly
- Neural polishing
- Transformer assembly
- Protein language models
Examples:
- DeepConsensus (PacBio)
- Bonito (Nanopore)
- DeepPolisher
- AlphaFold
Future:
- Learned graph
- Better repeats
- Faster
- More accurate
""")
print("\n=== 4. Clinical-Grade Assembly ===")
print("""
Trend: Routine clinical
Current:
- Research
- Specialized
Future:
- Clinical routine
- Rare disease
- Cancer
- Pharmacogenomics
Examples:
- CYP2D6
- HLA
- BRCA1/2
- Cancer SVs
Requirements:
- Accuracy
- Speed
- Cost
- Regulation
""")
print("\n=== 5. Cloud-Native ===")
print("""
Trend: Cloud assembly
Current:
- Self-managed
- Manual scaling
Future:
- Serverless
- Auto-scaling
- Pay per use
- Global
Examples:
- AWS HealthOmics
- Google Cloud Life Sciences
- Azure Genomics
- Terra
""")
print("\n=== 6. Integration ===")
print("""
Trend: Unified pipelines
Current:
- Separate tools
- Manual pipelines
Future:
- Integrated platforms
- Workflow managers
- Reproducible science
- ML-ready
Examples:
- Galaxy
- Nextflow
- Snakemake
- Terra
- nf-core
""")
# TIMELINE
print("\n=== Timeline ===")
print("""
Past:
1977: Sanger
1995: First bacterial genome
2001: Human draft
2005: NGS
2010: PacBio
2014: Nanopore
2019: T2T start
2022: Complete human
Present:
2025: Routine T2T
2026: Pangenomes
Future:
2030: Clinical-grade?
2035: AI assembly?
2040: Quantum assembly?
""")
print("\n=== Final Thoughts ===")
print("""
Genome assembly is:
- Fundamental to genomics
- Needed for all analyses
- Rapidly improving
- Becoming routine
The future is:
- T2T
- Pangenome
- AI-augmented
- Clinical-grade
- Cloud-native
"The genome is the book of life.
Assembly is how we read it."
Keep exploring. Keep building.
""")