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.20. Desktop beta builds for Linux and
macOS are on the releases page;
the Windows build waits on code signing.
Two assemblies of one species share most of their sequence, and an alignment between them shows where the order breaks: an inversion, a moved block, a gene only one strain has. We align three Helicobacter pylori strains (26695, CHC155 and J99) with minimap2, one pair at a time, and the steps work the same on any pair of assemblies of your own. The other route to a stack of genomes aligns every genome against every other in one run, which Synteny visualization (all-vs-all minimap2) follows through five E. coli strains. We:
- load the assemblies, and the minimap2 PAF as a synteny track
- open the whole-genome alignment in a dotplot view
- stack the strains in a linear synteny view, with a gene track on each row
- color the gene tracks by gene symbol, so an ortholog is one color down the stack
- index a large alignment as PIF
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/cli@nextThe 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 takes the target genome first and the query second, and writes one PAF row per aligned block:
# -x asm20: the assembly preset for strains this diverged
# -c: emit the base-level CIGAR the linear synteny view draws from
# --eqx: split CIGAR matches (=) from mismatches (X)
minimap2 -c -x asm20 --eqx hpylori_j99.fa.gz hpylori_26695.fa.gz > 26695_vs_j99.pafColor by value → Identity reads the PAF's divergence tag or match counts.
JBrowse also loads MUMmer .delta and UCSC
.chain files directly. To convert them to PAF instead,
paftools.js
delta2paf reads a .delta, and
chain2paf reads a .chain.
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.pafWith one file per pair, the pairs you aligned fix the row order. A single all-vs-all PAF lets every band read the same file in any row order, after renaming each genome's sequences to PanSN names (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 gene
attribute works as an ortholog id. In
grammar-of-graphics terms, a track's
encoding.color is a color scale, a field mapped to colors. On each gene
track's menu:
- pick Color by → Attribute... and enter
geneas the field - open Advanced → Edit plot... to see the setting as text, where an edit applies live
An ortholog is then one color down all the rows, and a gene with no gene value
(most genes here have only a locus tag) stays grey. Inside the inversion, rsmA
and rlmN trade places in J99.
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": ["geneLike"],
"encoding": { "color": "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": ["geneLike"],
"encoding": { "color": "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": ["geneLike"],
"encoding": { "color": "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.