Pangenome (pggb)
3 videos in this tutorial
The tutorials target the JBrowse v5 beta, and the v4.3.0 release
on the download page lacks some of what they show. To install the
beta of JBrowse Web, run npm install -g @jbrowse/cli@next, then
jbrowse create jbrowse2 --branch v5.0.0-beta.13. Desktop beta builds are coming soon.
A pangenome graph stores the sequence several genomes share once, as a path every genome follows, and branches where they differ. We build one of five E. coli strains with pggb and turn its outputs into JBrowse tracks on the K12 genome. Most are linear projections, which flatten the graph onto K12's coordinates so it loads as an ordinary track:
- synteny between the strains
- the variants the graph calls against K12
- the whole-genome alignment
- depth and per-strain presence, which show the core and accessory genome
- the graph itself, drawn as a track you browse by locus
The graph view is a beta plugin. We welcome your feedback.
Prerequisites
dockerorsingularity, for the pggb imagesamtools, htslib (bgzip,tabix),python3andunzipbedGraphToBigWig(UCSC kentUtils)minimap2, for the reads that check the depth tracknode, for the JBrowse CLI- the NCBI
datasetsCLI gfa-to-tabix0.12.0 or later, for the graph track- the GraphGenomeView plugin, for the same track. In your own JBrowse, install it from the plugin store
apt install samtools tabix unzip python3 covers four of those on
Debian/Ubuntu, and datasets and bedGraphToBigWig are each a
single-binary download.
Where the data comes from
The build script fetches the five E. coli RefSeq
assemblies by accession with the NCBI datasets CLI. The nanopore reads are the
one file to download by hand, with the curl under
Testing the CPZ-55 depth trough with nanopore reads.
- K12: ftp.ncbi.nlm.nih.gov/…/GCF_000005845.2_ASM584v2https://ftp.ncbi.nlm.nih.gov/genomes/all/GCF/000/005/845/GCF_000005845.2_ASM584v2/
- Sakai: ftp.ncbi.nlm.nih.gov/…/GCF_000008865.2_ASM886v2https://ftp.ncbi.nlm.nih.gov/genomes/all/GCF/000/008/865/GCF_000008865.2_ASM886v2/
- CFT073: ftp.ncbi.nlm.nih.gov/…/GCF_000007445.1_ASM744v1https://ftp.ncbi.nlm.nih.gov/genomes/all/GCF/000/007/445/GCF_000007445.1_ASM744v1/
- NCTC86: ftp.ncbi.nlm.nih.gov/…/GCF_002007705.1_ASM200770v1https://ftp.ncbi.nlm.nih.gov/genomes/all/GCF/002/007/705/GCF_002007705.1_ASM200770v1/
- IAI39: ftp.ncbi.nlm.nih.gov/…/GCF_000026345.1_ASM2634v1https://ftp.ncbi.nlm.nih.gov/genomes/all/GCF/000/026/345/GCF_000026345.1_ASM2634v1/
- nanopore reads from an unrelated isolate, E. coli E146: ftp.sra.ebi.ac.uk/…/DRR193901_1.fastq.gzhttps://ftp.sra.ebi.ac.uk/vol1/fastq/DRR193/DRR193901/DRR193901_1.fastq.gz
Building the graph
pggb takes one FASTA of all the genomes, with
PanSN names,
sample#haplotype#contig. Concatenate the five haploid strains as haplotype 1
and index the result:
for strain in K12 Sakai CFT073 NCTC86 IAI39; do
awk -v s="$strain" '/^>/{print ">" s "#1#chr"; next} {print}' "$strain.fa"
done > all.fa
bgzip all.fa
samtools faidx all.fa.gzThe pggb image includes every tool below,
odgi among them, so wrap docker run once
and run pggb:
in_pggb() {
docker run --rm -u "$(id -u):$(id -g)" -w /data -v "$PWD":/data \
ghcr.io/pangenome/pggb:202603141454453ade6b "$@"
}
# -n: haplotype count
# -c: mappings kept per segment; raise it along with -n
# -p: minimum identity; -s: segment length
# -V K12:10000: a VCF against the K12 path; -M: a MAF
in_pggb pggb -i /data/all.fa.gz -o /data/pggb \
-n 5 -c 4 -p 90 -s 5000 -V K12:10000 -M -t "$(nproc)"
og=$(ls pggb/*.smooth.final.og)Under singularity,
singularity exec --bind "$PWD":/data --pwd /data docker://<image> replaces the
wrapper body.
Load the genomes
Every projection is a track on a strain's assembly, and each strain's FASTA
holds one sequence named chr, the refName the graph's paths are renamed to
below. We'll add K12, the reference the projections land on, from a
bgzip-compressed, indexed FASTA:
Goes in the assemblies array of config.json. See Assemblies.
{
"name": "K12",
"uri": "https://jbrowse.org/demos/ecoli_pangenome/K12.fa.gz"
}jbrowse add-assembly https://jbrowse.org/demos/ecoli_pangenome/K12.fa.gz \
--name K12In JBrowse Desktop, Open new genome on the start screen (or File → Open genome... in a session), then Open from a URL and paste, one per line:
https://jbrowse.org/demos/ecoli_pangenome/K12.fa.gz
https://jbrowse.org/demos/ecoli_pangenome/K12.fa.gz.fai
https://jbrowse.org/demos/ecoli_pangenome/K12.fa.gz.gziJBrowse reads the format off the file name. Then fill in:
- Genome name:
K12
Sakai, CFT073, NCTC86 and IAI39 load the same way, named as in the
assemblyNames of the tracks below.
Synteny between the strains (wfmash)
pggb's first step is an all-vs-all alignment by wfmash, which JBrowse reads as a
synteny track once jbrowse make-pif indexes it:
cp pggb/*.alignments.wfmash.paf ecoli_pggb_ava.paf
jbrowse make-pif ecoli_pggb_ava.pafGoes in the tracks array of config.json. See Tracks.
{
"type": "SyntenyTrack",
"trackId": "ecoli_pggb_ava",
"name": "pggb graph: all-vs-all synteny (wfmash)",
"assemblyNames": ["K12", "Sakai", "CFT073", "NCTC86", "IAI39"],
"adapter": {
"type": "MultiGenomeIndexedPAFAdapter",
"uri": "ecoli_pggb_ava.pif.gz",
"assemblyNames": ["K12", "Sakai", "CFT073", "NCTC86", "IAI39"]
}
}jbrowse add-track ecoli_pggb_ava.pif.gz \
--trackId ecoli_pggb_ava \
--name "pggb graph: all-vs-all synteny (wfmash)" \
--assemblyNames K12,Sakai,CFT073,NCTC86,IAI39 \
--adapterType MultiGenomeIndexedPAFAdapter \
--load copyIn JBrowse Desktop, or in any running JBrowse Web session, open a view on this track’s assembly, then File → Open track..., choose Add track from pasted JSON, and paste:
{
"type": "SyntenyTrack",
"trackId": "ecoli_pggb_ava",
"name": "pggb graph: all-vs-all synteny (wfmash)",
"assemblyNames": ["K12", "Sakai", "CFT073", "NCTC86", "IAI39"],
"adapter": {
"type": "MultiGenomeIndexedPAFAdapter",
"uri": "ecoli_pggb_ava.pif.gz",
"assemblyNames": ["K12", "Sakai", "CFT073", "NCTC86", "IAI39"]
}
}ecoli_pggb_ava.pif.gz is relative to a config.json. Replace it with its URL or its path on this computer.
That shows it in the linear view. For the synteny view, open Add → Linear synteny view, pick the track under Quick start, and click Launch.
Stack the five strains with Add → Linear synteny view, whose Quick start fills in a row per assembly the track lists.
Select a span on K12's ruler and pick Launch → Linear synteny view to stack the strains over that span alone. The same selection on another strain's row, with Replace current view, re-anchors the stack on that strain:
Synteny read out of the graph with odgi untangle
odgi untangle
follows each strain's path and reports which stretch of the K12 path it
traverses, so this synteny comes from the graph itself. -p writes it as a PAF,
which make-pif indexes the same way:
printf 'K12#1#chr\n' > target.txt
printf 'Sakai#1#chr\nCFT073#1#chr\nNCTC86#1#chr\nIAI39#1#chr\n' > query.txt
# -m merges runs shorter than this into the previous segment
# -j is the minimum jaccard similarity for a match
# -e forces a segment boundary every N bp; omit it on graphs with many haplotypes
in_pggb odgi untangle -i "/data/$og" \
-R /data/target.txt -Q /data/query.txt -m 1000 -j 0.5 -e 5000 -p -t "$(nproc)" \
> ecoli_pggb_untangle.paf
jbrowse make-pif ecoli_pggb_untangle.pafGoes in the tracks array of config.json. See Tracks.
{
"type": "SyntenyTrack",
"trackId": "ecoli_pggb_untangle",
"name": "pggb graph: synteny from the graph (odgi untangle)",
"assemblyNames": ["K12", "Sakai", "CFT073", "NCTC86", "IAI39"],
"adapter": {
"type": "MultiGenomeIndexedPAFAdapter",
"uri": "ecoli_pggb_untangle.pif.gz",
"assemblyNames": ["K12", "Sakai", "CFT073", "NCTC86", "IAI39"]
}
}jbrowse add-track ecoli_pggb_untangle.pif.gz \
--trackId ecoli_pggb_untangle \
--name "pggb graph: synteny from the graph (odgi untangle)" \
--assemblyNames K12,Sakai,CFT073,NCTC86,IAI39 \
--adapterType MultiGenomeIndexedPAFAdapter \
--load copyIn JBrowse Desktop, or in any running JBrowse Web session, open a view on this track’s assembly, then File → Open track..., choose Add track from pasted JSON, and paste:
{
"type": "SyntenyTrack",
"trackId": "ecoli_pggb_untangle",
"name": "pggb graph: synteny from the graph (odgi untangle)",
"assemblyNames": ["K12", "Sakai", "CFT073", "NCTC86", "IAI39"],
"adapter": {
"type": "MultiGenomeIndexedPAFAdapter",
"uri": "ecoli_pggb_untangle.pif.gz",
"assemblyNames": ["K12", "Sakai", "CFT073", "NCTC86", "IAI39"]
}
}ecoli_pggb_untangle.pif.gz is relative to a config.json. Replace it with its URL or its path on this computer.
That shows it in the linear view. For the synteny view, open Add → Linear synteny view, pick the track under Quick start, and click Launch.
untangle_to_bed.py turns the same PAF into a BED with a strain column, so
one track can draw every strain on K12's axis. In grammar-of-graphics terms,
rows assigns one row per strain, and color is a color scale that here uses
scale: "identity" for the colors the file states, red where the strain runs
inverted:
curl -fO https://raw.githubusercontent.com/GMOD/jbrowse-components/main/scripts/untangle_to_bed.py
python3 untangle_to_bed.py ecoli_pggb_untangle.paf chr > ecoli_pggb_untangle_rows.bed
jbrowse sort-bed ecoli_pggb_untangle_rows.bed | bgzip > ecoli_pggb_untangle_rows.bed.gz
tabix -p bed ecoli_pggb_untangle_rows.bed.gzGoes in the tracks array of config.json. See Tracks.
{
"type": "FeatureTrack",
"trackId": "ecoli_pggb_untangle_rows",
"name": "pggb graph: untangle per strain (orientation, vs K12)",
"uri": "ecoli_pggb_untangle_rows.bed.gz",
"assemblyNames": ["K12"],
"displays": [
{
"type": "LinearMultiRowFeatureDisplay",
"rows": {
"field": "strain",
"domain": ["Sakai", "CFT073", "NCTC86", "IAI39"]
},
"color": {
"scale": "identity",
"domain": ["rgb(153,153,153)", "rgb(214,39,40)"],
"labels": ["Same orientation as K12", "Inverted"]
}
}
]
}jbrowse add-track-json '{
"type": "FeatureTrack",
"trackId": "ecoli_pggb_untangle_rows",
"name": "pggb graph: untangle per strain (orientation, vs K12)",
"uri": "ecoli_pggb_untangle_rows.bed.gz",
"assemblyNames": ["K12"],
"displays": [
{
"type": "LinearMultiRowFeatureDisplay",
"rows": {
"field": "strain",
"domain": ["Sakai", "CFT073", "NCTC86", "IAI39"]
},
"color": {
"scale": "identity",
"domain": ["rgb(153,153,153)", "rgb(214,39,40)"],
"labels": ["Same orientation as K12", "Inverted"]
}
}
]
}'In JBrowse Desktop, or in any running JBrowse Web session, open a view on this track’s assembly, then File → Open track..., choose Add track from pasted JSON, and paste:
{
"type": "FeatureTrack",
"trackId": "ecoli_pggb_untangle_rows",
"name": "pggb graph: untangle per strain (orientation, vs K12)",
"uri": "ecoli_pggb_untangle_rows.bed.gz",
"assemblyNames": ["K12"],
"displays": [
{
"type": "LinearMultiRowFeatureDisplay",
"rows": {
"field": "strain",
"domain": ["Sakai", "CFT073", "NCTC86", "IAI39"]
},
"color": {
"scale": "identity",
"domain": ["rgb(153,153,153)", "rgb(214,39,40)"],
"labels": ["Same orientation as K12", "Inverted"]
}
}
]
}ecoli_pggb_untangle_rows.bed.gz is relative to a config.json. Replace it with its URL or its path on this computer.
Variants against K12 (pggb -V)
pggb -V wrote a VCF of every variant the graph decomposes against the K12
path, genotyped in the other four strains. Its CHROM is the PanSN path,
K12#1#chr, so rename it to the assembly's chr:
printf 'K12#1#chr\tchr\n' > rename_chrs.tsv
in_pggb bash -c "bcftools annotate --rename-chrs /data/rename_chrs.tsv \
/data/pggb/*.smooth.final.K12.decomposed.vcf \
| bcftools sort -Oz -o /data/ecoli_pggb.vcf.gz && tabix -p vcf /data/ecoli_pggb.vcf.gz"Each strain is one haplotype, so unit: "haplotype" draws one row per strain,
colored by that strain's allele:
Goes in the tracks array of config.json. See Tracks.
{
"type": "VariantTrack",
"trackId": "ecoli_pggb_variants",
"name": "pggb graph: pangenome variants (vs K12)",
"assemblyNames": ["K12"],
"adapter": {
"type": "VcfTabixAdapter",
"uri": "ecoli_pggb.vcf.gz"
},
"displays": [
{ "type": "LinearMultiSampleVariantDisplay", "unit": "haplotype" }
]
}jbrowse add-track-json '{
"type": "VariantTrack",
"trackId": "ecoli_pggb_variants",
"name": "pggb graph: pangenome variants (vs K12)",
"assemblyNames": ["K12"],
"adapter": {
"type": "VcfTabixAdapter",
"uri": "ecoli_pggb.vcf.gz"
},
"displays": [
{ "type": "LinearMultiSampleVariantDisplay", "unit": "haplotype" }
]
}'In JBrowse Desktop, or in any running JBrowse Web session, open a view on this track’s assembly, then File → Open track..., choose Add track from pasted JSON, and paste:
{
"type": "VariantTrack",
"trackId": "ecoli_pggb_variants",
"name": "pggb graph: pangenome variants (vs K12)",
"assemblyNames": ["K12"],
"adapter": {
"type": "VcfTabixAdapter",
"uri": "ecoli_pggb.vcf.gz"
},
"displays": [
{ "type": "LinearMultiSampleVariantDisplay", "unit": "haplotype" }
]
}ecoli_pggb.vcf.gz is relative to a config.json. Replace it with its URL or its path on this computer.
With a length after the path name, as in -V K12:10000, pggb runs
vcfbub and
vcfwave over the VCF to decompose large
sites into smaller variants, giving *.decomposed.vcf.
The undecomposed *.smooth.final.K12.vcf keeps one record per bubble (where
paths split and rejoin) for the
graph track to read.
Whole-genome alignment onto K12 (MAF)
pggb -M wrote the multiple alignment as a MAF. Re-root every block on K12,
rename the rows to sample.chr, and blank the padding smoothxg writes around
each row, then convert the MAF to the tabix-indexed BED that
MafTabixAdapter reads:
curl -fO https://raw.githubusercontent.com/GMOD/jbrowse-components/main/scripts/reroot_maf.py
# all.fa.gz is the pggb input: the padding sits on either end of a row, so
# only the genome says which bases are the row's own
python3 reroot_maf.py pggb/*.smooth.maf ecoli_pggb.maf all.fa.gz K12#1#chrcurl -fO https://raw.githubusercontent.com/GMOD/jbrowse-components/main/scripts/maf_to_bed.py
python3 maf_to_bed.py ecoli_pggb.maf ecoli_pggb.maf.bed
bgzip ecoli_pggb.maf.bed
tabix -p bed ecoli_pggb.maf.bed.gzTo order the rows by how much graph each pair of strains shares, build a tree
from
odgi similarity
and point nhLocation at it:
curl -fO https://raw.githubusercontent.com/GMOD/jbrowse-components/main/scripts/odgi_similarity_to_newick.py
in_pggb odgi similarity -i "/data/$og" -D '#' -p 1 > ecoli_pggb_similarity.tsv
python3 odgi_similarity_to_newick.py ecoli_pggb_similarity.tsv ecoli_pggb.nhGoes in the tracks array of config.json. See Tracks.
{
"type": "MafTrack",
"trackId": "ecoli_pggb_maf",
"name": "pggb graph: whole-genome alignment (MAF, vs K12)",
"assemblyNames": ["K12"],
"adapter": {
"type": "MafTabixAdapter",
"samples": ["K12", "Sakai", "CFT073", "NCTC86", "IAI39"],
"nhLocation": { "uri": "ecoli_pggb.nh" },
"uri": "ecoli_pggb.maf.bed.gz"
}
}jbrowse add-track-json '{
"type": "MafTrack",
"trackId": "ecoli_pggb_maf",
"name": "pggb graph: whole-genome alignment (MAF, vs K12)",
"assemblyNames": ["K12"],
"adapter": {
"type": "MafTabixAdapter",
"samples": ["K12", "Sakai", "CFT073", "NCTC86", "IAI39"],
"nhLocation": { "uri": "ecoli_pggb.nh" },
"uri": "ecoli_pggb.maf.bed.gz"
}
}'In JBrowse Desktop, or in any running JBrowse Web session, open a view on this track’s assembly, then File → Open track..., choose Add track from pasted JSON, and paste:
{
"type": "MafTrack",
"trackId": "ecoli_pggb_maf",
"name": "pggb graph: whole-genome alignment (MAF, vs K12)",
"assemblyNames": ["K12"],
"adapter": {
"type": "MafTabixAdapter",
"samples": ["K12", "Sakai", "CFT073", "NCTC86", "IAI39"],
"nhLocation": { "uri": "ecoli_pggb.nh" },
"uri": "ecoli_pggb.maf.bed.gz"
}
}ecoli_pggb.nh, ecoli_pggb.maf.bed.gz are relative to a config.json. Replace each with its URL or its path on this computer.
Drag across the rows, and the menu on release lists each strain the selection covers under two submenus:
- Open aligned genome at the matching region opens that strain's genome at the aligned stretch
- Linear synteny view, K12 vs... opens K12 and that strain as a linear synteny view
Pangenome depth: core versus accessory sequence
odgi depth
counts how many paths cross each K12 window: about five over core sequence and
one over sequence only K12 has. Make 500 bp windows, count, and write a bigWig:
reflen=$(awk -v p="K12#1#chr" '$1 == p {print $2}' all.fa.gz.fai)
awk -v p="K12#1#chr" -v len="$reflen" -v w=500 \
'BEGIN { for (s = 0; s < len; s += w) { e = s + w; if (e > len) e = len
print p "\t" s "\t" e } }' > depth_windows.bed
in_pggb odgi depth -i "/data/$og" -b /data/depth_windows.bed |
awk -v p="K12#1#chr" -v OFS='\t' '$1 == p && $4 + 0 == $4 { print "chr", $2, $3, $4 }' |
sort -k1,1 -k2,2n > ecoli_pggb_depth.bedgraph
printf 'chr\t%s\n' "$reflen" > chrom.sizes
bedGraphToBigWig ecoli_pggb_depth.bedgraph chrom.sizes ecoli_pggb_depth.bwThe config draws reference lines at the strain count and at 1:
Goes in the tracks array of config.json. See Tracks.
{
"type": "QuantitativeTrack",
"trackId": "ecoli_pggb_depth",
"name": "pggb graph: pangenome depth (paths over K12)",
"assemblyNames": ["K12"],
"adapter": {
"type": "BigWigAdapter",
"uri": "ecoli_pggb_depth.bw"
},
"displayDefaults": {
"scales": {
"y": {
"title": "paths",
"rules": [
{ "value": 5, "label": "all five strains" },
{ "value": 1, "label": "K12 alone" }
]
}
}
}
}jbrowse add-track ecoli_pggb_depth.bw \
--trackId ecoli_pggb_depth \
--name "pggb graph: pangenome depth (paths over K12)" \
--assemblyNames K12 \
--displayDefaults '{"scales":{"y":{"title":"paths","rules":[{"value":5,"label":"all five strains"},{"value":1,"label":"K12 alone"}]}}}' \
--load copyIn JBrowse Desktop, or in any running JBrowse Web session, open a view on this track’s assembly, then File → Open track..., choose Add track from pasted JSON, and paste:
{
"type": "QuantitativeTrack",
"trackId": "ecoli_pggb_depth",
"name": "pggb graph: pangenome depth (paths over K12)",
"assemblyNames": ["K12"],
"adapter": {
"type": "BigWigAdapter",
"uri": "ecoli_pggb_depth.bw"
},
"displayDefaults": {
"scales": {
"y": {
"title": "paths",
"rules": [
{ "value": 5, "label": "all five strains" },
{ "value": 1, "label": "K12 alone" }
]
}
}
}
}ecoli_pggb_depth.bw is relative to a config.json. Replace it with its URL or its path on this computer.
The curve rises past the strain-count line over the rRNA operons (repeated ribosomal RNA genes), because the graph collapses their copies into one.
Per-strain presence
odgi pav
splits depth per strain, as the fraction of each window that the strain's path
crosses. Write one bigWig per strain other than K12:
in_pggb odgi pav -i "/data/$og" -b /data/depth_windows.bed > pav.tsv
for strain in Sakai CFT073 NCTC86 IAI39; do
awk -F'\t' -v OFS='\t' -v g="${strain}#1#chr" \
'$5 == g && $6 + 0 == $6 { print "chr", $2, $3, $6 }' pav.tsv |
sort -k1,1 -k2,2n > "pav_${strain}.bedgraph"
bedGraphToBigWig "pav_${strain}.bedgraph" chrom.sizes "ecoli_pggb_pav_${strain}.bw"
doneThe four bigWigs load as one heatmap track, a row per strain, where a white column is a stretch that strain lacks:
Goes in the tracks array of config.json. See Tracks.
{
"type": "MultiQuantitativeTrack",
"trackId": "ecoli_pggb_pav",
"name": "pggb graph: per-strain presence (odgi pav, vs K12)",
"assemblyNames": ["K12"],
"adapter": {
"type": "MultiWiggleAdapter",
"subadapters": [
{
"type": "BigWigAdapter",
"name": "Sakai",
"uri": "ecoli_pggb_pav_Sakai.bw"
},
{
"type": "BigWigAdapter",
"name": "CFT073",
"uri": "ecoli_pggb_pav_CFT073.bw"
},
{
"type": "BigWigAdapter",
"name": "NCTC86",
"uri": "ecoli_pggb_pav_NCTC86.bw"
},
{
"type": "BigWigAdapter",
"name": "IAI39",
"uri": "ecoli_pggb_pav_IAI39.bw"
}
]
},
"displayDefaults": { "mark": "span" }
}jbrowse add-track-json '{
"type": "MultiQuantitativeTrack",
"trackId": "ecoli_pggb_pav",
"name": "pggb graph: per-strain presence (odgi pav, vs K12)",
"assemblyNames": ["K12"],
"adapter": {
"type": "MultiWiggleAdapter",
"subadapters": [
{
"type": "BigWigAdapter",
"name": "Sakai",
"uri": "ecoli_pggb_pav_Sakai.bw"
},
{
"type": "BigWigAdapter",
"name": "CFT073",
"uri": "ecoli_pggb_pav_CFT073.bw"
},
{
"type": "BigWigAdapter",
"name": "NCTC86",
"uri": "ecoli_pggb_pav_NCTC86.bw"
},
{
"type": "BigWigAdapter",
"name": "IAI39",
"uri": "ecoli_pggb_pav_IAI39.bw"
}
]
},
"displayDefaults": { "mark": "span" }
}'In JBrowse Desktop, or in any running JBrowse Web session, open a view on this track’s assembly, then File → Open track..., choose Add track from pasted JSON, and paste:
{
"type": "MultiQuantitativeTrack",
"trackId": "ecoli_pggb_pav",
"name": "pggb graph: per-strain presence (odgi pav, vs K12)",
"assemblyNames": ["K12"],
"adapter": {
"type": "MultiWiggleAdapter",
"subadapters": [
{
"type": "BigWigAdapter",
"name": "Sakai",
"uri": "ecoli_pggb_pav_Sakai.bw"
},
{
"type": "BigWigAdapter",
"name": "CFT073",
"uri": "ecoli_pggb_pav_CFT073.bw"
},
{
"type": "BigWigAdapter",
"name": "NCTC86",
"uri": "ecoli_pggb_pav_NCTC86.bw"
},
{
"type": "BigWigAdapter",
"name": "IAI39",
"uri": "ecoli_pggb_pav_IAI39.bw"
}
]
},
"displayDefaults": { "mark": "span" }
}ecoli_pggb_pav_Sakai.bw, ecoli_pggb_pav_CFT073.bw, ecoli_pggb_pav_NCTC86.bw, ecoli_pggb_pav_IAI39.bw are relative to a config.json. Replace each with its URL or its path on this computer.
Open chr:450,000-590,000 with the K12 genes on. The figure shades
chr:501,500-539,000.
Testing the CPZ-55 depth trough with nanopore reads
We'll check the depth trough at CPZ-55, a cryptic prophage found in K12 alone, with nanopore reads from E. coli E146, an isolate outside the graph. Download them:
curl -fO https://ftp.sra.ebi.ac.uk/vol1/fastq/DRR193/DRR193901/DRR193901_1.fastq.gzMap them onto K12:
minimap2 -ax map-ont K12.fa DRR193901_1.fastq.gz | samtools sort -o ecoli_e146_ont.bam
samtools index ecoli_e146_ont.bamGoes in the tracks array of config.json. See Tracks.
{
"trackId": "ecoli_e146_ont",
"name": "E146 nanopore reads (vs K12)",
"uri": "ecoli_e146_ont.bam",
"assemblyNames": ["K12"]
}jbrowse add-track ecoli_e146_ont.bam \
--trackId ecoli_e146_ont \
--name "E146 nanopore reads (vs K12)" \
--assemblyNames K12 \
--load copyIn JBrowse Desktop, or in any running JBrowse Web session, open a view on this track’s assembly, then File → Open track... and, in Add a track from file or URL, enter:
- Main file:
ecoli_e146_ont.bam
Click Next. JBrowse reads the adapter and track type off the file name. Then fill in:
- Track name:
E146 nanopore reads (vs K12) - Assembly:
K12
Click Add.
ecoli_e146_ont.bam is relative to a config.json. Replace it with its URL or its path on this computer.
Type chr:2,554,000-2,570,000. Reads long enough to cross the trough show it as
a single labelled deletion.
The graph as a track
The graph genome view plugin draws the
graph itself as a track of the linear view.
gfa-to-tabix build indexes it by
following the K12 path, and takes the bubbles from pggb's undecomposed VCF,
renamed like the decomposed one:
in_pggb bash -c "bcftools annotate --rename-chrs /data/rename_chrs.tsv \
/data/pggb/*.smooth.final.K12.vcf \
| bcftools sort -Oz -o /data/ecoli_pggb_snarls.vcf.gz && tabix -p vcf /data/ecoli_pggb_snarls.vcf.gz"
cargo install gfa-to-tabix
gfa-to-tabix build pggb/*.smooth.final.gfa -o ecoli_pggb --reference K12 --snarls ecoli_pggb_snarls.vcf.gzThe command writes the segments and links, a coarse tier with variants under 50
bp folded into the reference, and ecoli_pggb.config.json. The uris below are
our hosted copy; a local build uses ecoli_pggb:
Goes in the tracks array of config.json. See Tracks.
{
"type": "GraphTrack",
"trackId": "ecoli_pggb_segments",
"name": "pggb graph segments (whole graph, by locus)",
"assemblyNames": ["K12"],
"adapter": {
"type": "RgfaTabixAdapter",
"uri": "https://jbrowse.org/demos/ecoli_pangenome/ecoli_pggb",
"coarse": {
"uri": "https://jbrowse.org/demos/ecoli_pangenome/ecoli_pggb.fold50",
"aboveBpPerPx": 5
}
},
"displayDefaults": { "showLabels": "none" },
"displays": [
{ "type": "LinearGraphDisplay" },
{ "type": "LinearBasicDisplay" }
]
}jbrowse add-track-json '{
"type": "GraphTrack",
"trackId": "ecoli_pggb_segments",
"name": "pggb graph segments (whole graph, by locus)",
"assemblyNames": ["K12"],
"adapter": {
"type": "RgfaTabixAdapter",
"uri": "https://jbrowse.org/demos/ecoli_pangenome/ecoli_pggb",
"coarse": {
"uri": "https://jbrowse.org/demos/ecoli_pangenome/ecoli_pggb.fold50",
"aboveBpPerPx": 5
}
},
"displayDefaults": { "showLabels": "none" },
"displays": [
{ "type": "LinearGraphDisplay" },
{ "type": "LinearBasicDisplay" }
]
}'In JBrowse Desktop, or in any running JBrowse Web session, open a view on this track’s assembly, then File → Open track..., choose Add track from pasted JSON, and paste:
{
"type": "GraphTrack",
"trackId": "ecoli_pggb_segments",
"name": "pggb graph segments (whole graph, by locus)",
"assemblyNames": ["K12"],
"adapter": {
"type": "RgfaTabixAdapter",
"uri": "https://jbrowse.org/demos/ecoli_pangenome/ecoli_pggb",
"coarse": {
"uri": "https://jbrowse.org/demos/ecoli_pangenome/ecoli_pggb.fold50",
"aboveBpPerPx": 5
}
},
"displayDefaults": { "showLabels": "none" },
"displays": [
{ "type": "LinearGraphDisplay" },
{ "type": "LinearBasicDisplay" }
]
}Open track... → Add pangenome graph track adds the same track from an empty session:
Type chr:1,292,500-1,307,500. Zoomed out past five bp per pixel, the track
draws the coarse tier, the graph with variants under 50 bp folded into the
reference, with charcoal where the strains differ. The tier also loads as a
separate track:
Goes in the tracks array of config.json. See Tracks.
{
"type": "GraphTrack",
"trackId": "ecoli_pggb_tier50",
"name": "pggb graph, variants under 50 bp folded (coarse tier)",
"assemblyNames": ["K12"],
"adapter": {
"type": "RgfaTabixAdapter",
"uri": "https://jbrowse.org/demos/ecoli_pangenome/ecoli_pggb.fold50"
},
"displays": [
{ "type": "LinearGraphDisplay" },
{ "type": "LinearBasicDisplay" }
]
}jbrowse add-track-json '{
"type": "GraphTrack",
"trackId": "ecoli_pggb_tier50",
"name": "pggb graph, variants under 50 bp folded (coarse tier)",
"assemblyNames": ["K12"],
"adapter": {
"type": "RgfaTabixAdapter",
"uri": "https://jbrowse.org/demos/ecoli_pangenome/ecoli_pggb.fold50"
},
"displays": [
{ "type": "LinearGraphDisplay" },
{ "type": "LinearBasicDisplay" }
]
}'In JBrowse Desktop, or in any running JBrowse Web session, open a view on this track’s assembly, then File → Open track..., choose Add track from pasted JSON, and paste:
{
"type": "GraphTrack",
"trackId": "ecoli_pggb_tier50",
"name": "pggb graph, variants under 50 bp folded (coarse tier)",
"assemblyNames": ["K12"],
"adapter": {
"type": "RgfaTabixAdapter",
"uri": "https://jbrowse.org/demos/ecoli_pangenome/ecoli_pggb.fold50"
},
"displays": [
{ "type": "LinearGraphDisplay" },
{ "type": "LinearBasicDisplay" }
]
}In the tier track's menu, Display types → Feature display draws the tier's segments as a row at any zoom. The tier marks where the strains differ, and between the tier and the graph the MAF track shows which strain, since its row breaks across each bubble it skips.
Right-click the IS5 node in the graph track and take Open in K12, the route
the HPRC page
describes for a haplotype. A segment K12 lacks has coordinates on the strain
that has it, so type chr:1,004,500-1,004,961, right-click the 75 bp CFT073
segment and pick Open in CFT073.
Coloring each segment by how many strains have it
The index records which strains pass through each segment, and a feature track over the same files colors each segment by that count:
Goes in the tracks array of config.json. See Tracks.
{
"type": "FeatureTrack",
"trackId": "ecoli_pggb_carriage",
"name": "pggb graph: strains per segment",
"assemblyNames": ["K12"],
"adapter": {
"type": "RgfaTabixAdapter",
"uri": "https://jbrowse.org/demos/ecoli_pangenome/ecoli_pggb"
},
"displayDefaults": {
"displayMode": "collapsed",
"showLabels": "none",
"color": {
"field": "sampleCount",
"domain": ["5", "4", "3", "2", "1"],
"range": ["#bdbdbd", "#fed976", "#feb24c", "#fd8d3c", "#e31a1c"],
"labels": [
"All 5 strains (core)",
"4 strains",
"3 strains",
"2 strains",
"1 strain (private)"
],
"title": "Strains"
}
}
}jbrowse add-track-json '{
"type": "FeatureTrack",
"trackId": "ecoli_pggb_carriage",
"name": "pggb graph: strains per segment",
"assemblyNames": ["K12"],
"adapter": {
"type": "RgfaTabixAdapter",
"uri": "https://jbrowse.org/demos/ecoli_pangenome/ecoli_pggb"
},
"displayDefaults": {
"displayMode": "collapsed",
"showLabels": "none",
"color": {
"field": "sampleCount",
"domain": ["5", "4", "3", "2", "1"],
"range": ["#bdbdbd", "#fed976", "#feb24c", "#fd8d3c", "#e31a1c"],
"labels": [
"All 5 strains (core)",
"4 strains",
"3 strains",
"2 strains",
"1 strain (private)"
],
"title": "Strains"
}
}
}'In JBrowse Desktop, or in any running JBrowse Web session, open a view on this track’s assembly, then File → Open track..., choose Add pangenome graph track, and fill in:
- File type:
rGFA segments (tabix BED pair) - Path:
https://jbrowse.org/demos/ecoli_pangenome/ecoli_pggb.segs.bed.gz - Track name:
pggb graph: strains per segment - Assembly:
K12
Type chr:1,299,499-1,300,693, the IS5 element. Advanced → Edit plot... in
the track menu shows the color block as text and applies edits live.
Reproduce it end to end
build_ecoli_pangenome_graph.sh
runs every step above except the E146 read mapping, downloads JBrowse, and
writes a config.json with the five assemblies, their gene tracks, every other
track on this page, and a default session:
curl -fO https://raw.githubusercontent.com/GMOD/jbrowse-components/main/scripts/build_ecoli_pangenome_graph.sh
bash build_ecoli_pangenome_graph.sh
npx --yes serve ecoli_pangenome_graph_build/jbrowse2CONTAINER=singularity forces the container runtime. To add genomes, add rows
to the strain table in the script; wfmash time grows with the square of the
genome count.
See also
- Tutorial: Pangenome (Minigraph-Cactus)
- Tutorial: Pangenome (HPRC) part 1: the graph's alleles and the haplotypes that have them
- Tutorial: Synteny visualization (all-vs-all minimap2)
- Tutorial: Synteny from gene symbols (44 E. coli genomes)
- User guide: Graph genome view
- User guide: MAF track
- User guide: Multi-sample variant display
- Developer guide: PIF (Pairwise Indexed Format)
External links
Feedback on this tutorial is welcome: contact us.