Synteny visualization (pairwise minimap2)
TL;DR: align two assemblies with minimap2 -c --eqx, load the PAF as a
synteny track, and read it whole-genome in a dotplot and base-level in the
linear synteny view. add-track -a takes query,target, the reverse of the
minimap2 argument order.
Prerequisites
- a JBrowse 2 instance (see the web quickstart, or the desktop quickstart; the steps below are identical on both, and on Desktop the FASTAs and alignments are local files)
- minimap2
samtools- htslib (
bgzip,tabix) unzip- the NCBI
datasetsCLI, which fetches the three assemblies and their gene annotations node, for the JBrowse CLI
On Debian/Ubuntu, apt install minimap2 samtools tabix unzip covers most of
these. The NCBI datasets CLI is a single-binary download, and node comes
from nodejs.org.
Where the data comes from
Three H. pylori RefSeq assemblies, each fetched by accession with the
datasets CLI.
-
26695: https://ftp.ncbi.nlm.nih.gov/genomes/all/GCF/000/307/795/GCF_000307795.1_ASM30779v1/
-
CHC155: https://ftp.ncbi.nlm.nih.gov/genomes/all/GCF/025/998/455/GCF_025998455.1_ASM2599845v1/
-
J99: https://ftp.ncbi.nlm.nih.gov/genomes/all/GCF/000/982/695/GCF_000982695.1_ASM98269v1/
-
the 26695 strain's gene annotation, rehosted so the color-by-attribute figure loads without rerunning the pipeline: https://jbrowse.org/demos/hpylori/hpylori_26695.gff.gz
Three strains, stacked
This tutorial follows three Helicobacter pylori strains (26695, CHC155, and J99) from raw assemblies to a stacked three-genome synteny view. The steps work the same on any pair of assemblies you have.
Aligning the assemblies
minimap2 -c -x asm20 --eqx hpylori_j99.fa hpylori_26695.fa > 26695_vs_j99.paf
The flags each do one thing:
-x asm20is the whole-genome assembly preset, sized to how divergent the two genomes are.asm5covers up to about 5% divergence; these H. pylori strains are the same species but diverge well past that, so they needasm20.-cemits the base-level CIGAR the linear synteny view draws from.--eqxsplits CIGAR matches (=) from mismatches (X). The ribbon band treats both as matches, and the same track opened in a plain linear genome view draws theXoperations as per-base mismatches, the way a read pileup does. Color by → Identity reads the PAF's own divergence tag, or its 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
Both genomes have to be assemblies before the alignment can reference them:
jbrowse add-assembly hpylori_26695.fa --load copy
jbrowse add-assembly hpylori_j99.fa --load copy
jbrowse add-track 26695_vs_j99.paf -a hpylori_26695,hpylori_j99 --load copy
The -a order is query,target, which is the reverse of the minimap2 argument
order: minimap2 target.fa query.fa becomes add-track -a query,target. Here
26695 was the query and J99 the target, so 26695 comes first.
Reading the whole genome in a dotplot
Add → Dotplot view opens the import form. The track just added is in the config, so the form opens in Quick start: pick it and click Launch. Swap transposes the axes, since a synteny track is queryable in either direction. Manual is where you pick 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 three strains
A band is drawn between adjacent rows only, so a 26695 / CHC155 / J99 stack needs the two adjacent alignments:
minimap2 -c -x asm20 --eqx hpylori_chc155.fa hpylori_26695.fa > 26695_vs_chc155.paf
minimap2 -c -x asm20 --eqx hpylori_j99.fa hpylori_chc155.fa > chc155_vs_j99.paf
Add the third assembly and 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 three strains stack in one view.
Open each strain's gene track from its own track selector; conserved genes then line up down the stack ribbon by ribbon.
Each panel is a full linear genome view, so search boxes, zooming, and the track selector work per genome. See Linear synteny view for ribbon coloring, curved ribbons, and the rest of the view's options, and URL parameters → linear synteny view for building one from a session-spec URL.
Coloring genes by ortholog
The ribbons connect aligned sequence, and the gene tracks color independently.
In bacteria the gene symbol is effectively the ortholog id, since NCBI reuses
standardized symbols across strains. On each gene track, open the track menu and
pick Color by... → Attribute..., then enter gene. The dialog prints the
expression it is about to write, and every distinct value of that attribute gets
its own deterministic color, so an ortholog carries one color down all three
panels.
Features with no value for that attribute are painted a neutral grey; most of the genes in this window carry only a locus tag.
The dialog writes a display color expression, which is one line of config:
{
"type": "FeatureTrack",
"trackId": "hpylori_26695.gff",
"name": "H. pylori 26695 genes",
"assemblyNames": ["hpylori_26695"],
"adapter": {
"type": "Gff3TabixAdapter",
"uri": "https://jbrowse.org/demos/hpylori/hpylori_26695.gff.gz"
},
"displayDefaults": {
"showOnlyGenes": true,
"color": "jexl:randomColor(get(feature,'gene'))"
}
}
jbrowse add-track https://jbrowse.org/demos/hpylori/hpylori_26695.gff.gz \
--trackId hpylori_26695.gff \
--name "H. pylori 26695 genes" \
--assemblyNames hpylori_26695 \
--displayDefaults "{\"showOnlyGenes\":true,\"color\":\"jexl:randomColor(get(feature,'gene'))\"}"
Using PIF for large genomes
A bacterial PAF is small enough to load whole. For a large whole-genome alignment, convert it 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 copy
Troubleshooting
assemblyNames in the wrong order is the common one, and JBrowse checks for it
once at view load: it asks the adapter which chromosomes belong to the top row
and compares them against that assembly's own. When they belong to the other row
instead, a warning appears in the view header, and the dialog behind it names
the remedy.
A view that draws but scatters its blocks randomly comes from the alignment: a
preset too tight for the divergence leaves only short spurious anchors. Raise
it, asm5 up to about 5% and asm10/asm20 past that, and check -c --eqx
were passed.
Reproduce it end to end
One script builds everything above,
build_hpylori_synteny.sh:
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 URL
It downloads the three RefSeq assemblies, aligns all three strain pairs with
minimap2, downloads JBrowse, and writes a config.json with the three
assemblies, a gene track per strain, the three pairwise synteny tracks, and a
default session that stacks all three in one linear synteny view. It needs the
same tools listed under Prerequisites.
See also
- Synteny track
- Dotplot view
- Linear synteny view
- Synteny on genomes.jbrowse.org
- Comparing one genome's two haplotypes (T2T-HG002)
- Synteny visualization (all-vs-all minimap2)
- Synteny from an ortholog table (grape, peach, cacao)
- MAF track
References
- 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.