Synteny visualization (pairwise minimap2)
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.15. Desktop beta builds are coming soon.
We compare three Helicobacter pylori strains (26695, CHC155 and J99) by aligning their assemblies with minimap2. The steps work the same on any pair of assemblies. We:
- align each pair of genomes and load the assemblies and the PAF
- open the whole-genome alignment in a dotplot
- stack the strains in a linear synteny view, and color genes by ortholog
- index a large alignment as PIF
Aligning each pair of genomes separately is one of two routes to a stacked view. The other aligns every genome against every other in one minimap2 run, and Synteny visualization (all-vs-all minimap2) follows it through five E. coli strains.
Prerequisites
- a JBrowse instance (web or desktop quickstart); the steps are identical on both, and Desktop reads the alignments as local files
- minimap2
python3, which the build script uses to copy the hub configsnode, for the JBrowse CLI
# Debian/Ubuntu
sudo apt install minimap2 nodejs
# or conda, which has every tool above
conda install -c bioconda -c conda-forge minimap2 nodejs
# any platform
npm install -g @jbrowse/cliThe data
Three H. pylori RefSeq assemblies and their genome hubs on genomes.jbrowse.org (26695, CHC155, J99). Each hub serves the sequence minimap2 aligns and a config holding the assembly and its NCBI RefSeq genes.
The tracks below read local files that the build script writes from these, so run it first, or run Aligning the assemblies on any pair of assemblies of your own. The script fetches everything itself.
| What it is | File |
|---|---|
| 26695 GCF_000307795.1 sequence | GCF_000307795.1.fa.gz |
| CHC155 GCF_025998455.1 sequence | GCF_025998455.1.fa.gz |
| J99 GCF_000982695.1 sequence | GCF_000982695.1.fa.gz |
Aligning the assemblies
minimap2 -c -x asm20 --eqx hpylori_j99.fa.gz hpylori_26695.fa.gz > 26695_vs_j99.paf-x asm20is the assembly preset for strains this diverged.-cemits the base-level CIGAR the linear synteny view draws from.--eqxsplits CIGAR matches (=) from mismatches (X). Color by value → Identity reads the PAF's divergence tag or match counts.
JBrowse also loads MUMmer .delta and UCSC
.chain files directly, and
paftools.js has
delta2paf and chain2paf for converting them.
Loading the assemblies and the alignment
We'll load each strain's assembly from its hub. Each strain's hub config.json
holds a whole JBrowse assembly: the 2bit sequence, an alias table and the NCBI
RefSeq gene track. The build adds the old short name as an alias, so a session
can still say hpylori_26695:
{
"name": "GCF_000307795.1",
"displayName": "H. pylori 26695",
"aliases": ["hpylori_26695"],
"sequence": {
"type": "ReferenceSequenceTrack",
"trackId": "GCF_000307795.1-ReferenceSequenceTrack",
"adapter": {
"type": "TwoBitAdapter",
"uri": "https://hgdownload.soe.ucsc.edu/hubs/GCF/000/307/795/GCF_000307795.1/GCF_000307795.1.2bit",
"chromSizes": "https://hgdownload.soe.ucsc.edu/hubs/GCF/000/307/795/GCF_000307795.1/GCF_000307795.1.chrom.sizes.txt"
}
},
"refNameAliases": {
"adapter": {
"type": "RefNameAliasAdapter",
"refNameColumnHeaderName": "ucsc",
"uri": "https://hgdownload.soe.ucsc.edu/hubs/GCF/000/307/795/GCF_000307795.1/GCF_000307795.1.chromAlias.txt"
}
}
}refNameColumnHeaderName makes the UCSC name canonical, so the views read
NC_018939v1 where the FASTA and the PAF say NC_018939.1; the alias table
maps one to the other. CHC155 (GCF_025998455.1) and J99 (GCF_000982695.1)
load the same way from their hubs.
For your own genomes, the FASTA is the assembly. The .fai and .gzi sit
beside a bgzipped FASTA, and its sequence names are the ones your PAF uses, so
no alias table is needed:
Goes in the assemblies array of config.json. See Assemblies.
{
"name": "strainA",
"uri": "strainA.fa.gz"
}jbrowse add-assembly strainA.fa.gz \
--name strainA \
--load copyIn 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:
strainA.fa.gz
strainA.fa.gz.fai
strainA.fa.gz.gziJBrowse reads the format off the file name. Then fill in:
- Genome name:
strainA
strainA.fa.gz is relative to a config.json. Replace it with its URL or its path on this computer.
The alignment then goes on under the assembly names. assemblyNames runs
query,target, the reverse of the minimap2 argument order:
minimap2 target.fa query.fa becomes ["query", "target"]. A PAF that is not
indexed needs only its uri; swap in your own file.
Goes in the tracks array of config.json. See Tracks.
{
"type": "SyntenyTrack",
"trackId": "26695_vs_j99",
"name": "26695 vs J99",
"assemblyNames": ["GCF_000307795.1", "GCF_000982695.1"],
"adapter": {
"type": "PAFAdapter",
"uri": "26695_vs_j99.paf"
}
}jbrowse add-track 26695_vs_j99.paf \
--trackId 26695_vs_j99 \
--name "26695 vs J99" \
--assemblyNames GCF_000307795.1,GCF_000982695.1 \
--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": "26695_vs_j99",
"name": "26695 vs J99",
"assemblyNames": ["GCF_000307795.1", "GCF_000982695.1"],
"adapter": {
"type": "PAFAdapter",
"uri": "26695_vs_j99.paf"
}
}26695_vs_j99.paf 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.
A track whose assemblyNames are in the wrong order draws an empty band and
shows a warning in the view header:
Reading the whole genome in a dotplot
Add → Dotplot view opens the import form in Quick start: pick the track just added and click Launch. Swap transposes the axes. Manual picks each axis and a synteny file by hand.
To open any of those pieces at base resolution, drag a box across it, then right-click inside the box and choose Linear synteny view.
Stacking the strains
A synteny band joins matching regions of two adjacent rows only, so a 26695 / CHC155 / J99 stack needs the two adjacent alignments:
minimap2 -c -x asm20 --eqx hpylori_chc155.fa.gz hpylori_26695.fa.gz > 26695_vs_chc155.paf
minimap2 -c -x asm20 --eqx hpylori_j99.fa.gz hpylori_chc155.fa.gz > chc155_vs_j99.pafA single all-vs-all PAF is the alternative to one file per pair: every band of the stack reads the same file, in any row order, at the cost of renaming each genome's sequences to PanSN names before aligning (Synteny visualization (all-vs-all minimap2)).
Take the third assembly from its hub and add both alignments the same way as above, then:
- Add → Linear synteny view, then switch to Manual.
- Pick an assembly per row, with Add row for the third.
- Click the arrow between each adjacent pair to choose that band's synteny track: 26695 against CHC155, then CHC155 against J99.
- Click Launch, and all the strains stack in one view.
Zoom each row in once with its magnifier, then open each strain's gene track, NCBI RefSeq - RefSeq All (GFF), from the track selector for that row.
J99 has a short inversion that 26695 and CHC155 lack. To frame it, type one
window into each row's search box, top to bottom; [rev] flips the 26695 row,
which runs opposite to the other two strains here:
NC_018939v1:1,489,400-1,509,400[rev]
NZ_AP026446v1:99,000-119,000
NZ_CP011330v1:1,238,100-1,258,100Coloring genes by ortholog
NCBI reuses standardized gene symbols across bacterial strains, so the symbol is
effectively an ortholog id. In
grammar-of-graphics terms, a track's color
is a color scale, a field mapped to colors. Pick Color by... →
Attribute... on each gene track's menu and enter gene as the field. An
ortholog is one color down all the panels, and features with no gene value
(most genes here have only a locus tag) stay grey. Inside the inversion, rsmA
and rlmN trade places in J99. Advanced → Edit plot... in the same menu
shows the setting as text and applies edits live.
The config below is the same setting on the hub's gene track:
Goes in the tracks array of config.json. See Tracks.
{
"type": "FeatureTrack",
"trackId": "GCF_000307795.1-ncbiGff",
"name": "NCBI RefSeq - RefSeq All (GFF)",
"assemblyNames": ["GCF_000307795.1"],
"adapter": {
"type": "Gff3TabixAdapter",
"uri": "https://jbrowse.org/hubs/genark/GCF/000/307/795/GCF_000307795.1/GCF_000307795.1_ASM30779v1_genomic.gff.gz",
"index": {
"location": {
"uri": "https://jbrowse.org/hubs/genark/GCF/000/307/795/GCF_000307795.1/GCF_000307795.1_ASM30779v1_genomic.gff.gz.csi"
},
"indexType": "CSI"
}
},
"displayDefaults": {
"filter": { "genes": "only" },
"color": { "field": "gene" }
}
}jbrowse add-track-json '{
"type": "FeatureTrack",
"trackId": "GCF_000307795.1-ncbiGff",
"name": "NCBI RefSeq - RefSeq All (GFF)",
"assemblyNames": ["GCF_000307795.1"],
"adapter": {
"type": "Gff3TabixAdapter",
"uri": "https://jbrowse.org/hubs/genark/GCF/000/307/795/GCF_000307795.1/GCF_000307795.1_ASM30779v1_genomic.gff.gz",
"index": {
"location": {
"uri": "https://jbrowse.org/hubs/genark/GCF/000/307/795/GCF_000307795.1/GCF_000307795.1_ASM30779v1_genomic.gff.gz.csi"
},
"indexType": "CSI"
}
},
"displayDefaults": {
"filter": { "genes": "only" },
"color": { "field": "gene" }
}
}'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": "GCF_000307795.1-ncbiGff",
"name": "NCBI RefSeq - RefSeq All (GFF)",
"assemblyNames": ["GCF_000307795.1"],
"adapter": {
"type": "Gff3TabixAdapter",
"uri": "https://jbrowse.org/hubs/genark/GCF/000/307/795/GCF_000307795.1/GCF_000307795.1_ASM30779v1_genomic.gff.gz",
"index": {
"location": {
"uri": "https://jbrowse.org/hubs/genark/GCF/000/307/795/GCF_000307795.1/GCF_000307795.1_ASM30779v1_genomic.gff.gz.csi"
},
"indexType": "CSI"
}
},
"displayDefaults": {
"filter": { "genes": "only" },
"color": { "field": "gene" }
}
}Indexing large alignments as PIF
A bacterial PAF is small enough to load whole. For a large whole-genome alignment, convert the PAF to PIF (Pairwise Indexed Format) so JBrowse fetches only the alignments in the current viewport:
jbrowse make-pif alignment.paf
jbrowse add-track alignment.pif.gz -a query,target --load copyReproduce it end to end
One script builds everything above,
build_hpylori_synteny.sh,
in three steps:
- Download each strain's sequence and config from its genome hub, so the alignments and the assemblies come from the same files.
- Align 26695 to CHC155, CHC155 to J99 and 26695 to J99 with
minimap2 -x asm20 --eqx. - Write the config with the hub assemblies and gene tracks, the pairwise synteny tracks, and a default session stacking all the strains.
curl -fO https://raw.githubusercontent.com/GMOD/jbrowse-components/main/scripts/build_hpylori_synteny.sh
bash build_hpylori_synteny.sh # builds ./hpylori_synteny_build/jbrowse2
npx --yes serve hpylori_synteny_build/jbrowse2 # then open the printed URLSee also
- Tutorial: Synteny on genomes.jbrowse.org
- Tutorial: Comparing one genome's two haplotypes (T2T-HG002)
- Tutorial: Synteny visualization (all-vs-all minimap2)
- Tutorial: Synteny from an ortholog table (grape, peach, cacao)
- Tutorial: Rearrangements between genomes by type (SyRI)
- Tutorial: Synteny on a circle (human and mouse)
- User guide: Dotplot view
- User guide: Linear synteny view
- Config guide: Synteny track
- Config guide: MAF track
Citations
- Diesh et al. (2024). Setting Up the JBrowse 2 Genome Browser
- Diesh et al. (2023). JBrowse 2: A Modular Genome Browser with Views of Synteny and Structural Variation
Feedback on this tutorial is welcome: contact us.