Synteny from gene symbols (eight primates)
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.
We look at one human locus across seven other primates at once. NCBI gives an orthologous gene the same symbol in every species it annotates, so an ortholog table is a join on the gene name, built from eight GFF3 files in seconds. Each primate then becomes a lane under the human view, laid out in the coordinates of its genome, with the gene models annotated there. We read the TP53 neighbourhood and a 17q window across the eight primates, then human chromosome 2 as two fused ape chromosomes.
Prerequisites
- The NCBI datasets CLI
python3- A running JBrowse instance (the web quickstart or the desktop quickstart)
Where the data comes from
Eight RefSeq assemblies, each fetched by accession with the datasets CLI: the
current human reference, the six NHGRI telomere-to-telomere ape assemblies (Yoo
et al. 2025) and the telomere-to-telomere rhesus macaque. The build downloads
the annotation and sequence report for each genome.
The build script takes these files from their URLs, so there is nothing to download by hand.
- human, GRCh38.p14: ftp.ncbi.nlm.nih.gov/…/GCF_000001405.40_GRCh38.p14https://ftp.ncbi.nlm.nih.gov/genomes/all/GCF/000/001/405/GCF_000001405.40_GRCh38.p14/
- chimpanzee: ftp.ncbi.nlm.nih.gov/…/GCF_028858775.2_NHGRI_mPanTro3-v2.1_prihttps://ftp.ncbi.nlm.nih.gov/genomes/all/GCF/028/858/775/GCF_028858775.2_NHGRI_mPanTro3-v2.1_pri/
- bonobo: ftp.ncbi.nlm.nih.gov/…/GCF_029289425.2_NHGRI_mPanPan1-v2.1_prihttps://ftp.ncbi.nlm.nih.gov/genomes/all/GCF/029/289/425/GCF_029289425.2_NHGRI_mPanPan1-v2.1_pri/
- gorilla: ftp.ncbi.nlm.nih.gov/…/GCF_029281585.2_NHGRI_mGorGor1-v2.1_prihttps://ftp.ncbi.nlm.nih.gov/genomes/all/GCF/029/281/585/GCF_029281585.2_NHGRI_mGorGor1-v2.1_pri/
- Sumatran orangutan: ftp.ncbi.nlm.nih.gov/…/GCF_028885655.2_NHGRI_mPonAbe1-v2.1_prihttps://ftp.ncbi.nlm.nih.gov/genomes/all/GCF/028/885/655/GCF_028885655.2_NHGRI_mPonAbe1-v2.1_pri/
- Bornean orangutan: ftp.ncbi.nlm.nih.gov/…/GCF_028885625.2_NHGRI_mPonPyg2-v2.1_prihttps://ftp.ncbi.nlm.nih.gov/genomes/all/GCF/028/885/625/GCF_028885625.2_NHGRI_mPonPyg2-v2.1_pri/
- siamang: ftp.ncbi.nlm.nih.gov/…/GCF_028878055.3_NHGRI_mSymSyn1-v2.1_prihttps://ftp.ncbi.nlm.nih.gov/genomes/all/GCF/028/878/055/GCF_028878055.3_NHGRI_mSymSyn1-v2.1_pri/
- rhesus macaque, T2T-MMU8v2.0: ftp.ncbi.nlm.nih.gov/…/GCF_049350105.2_T2T-MMU8v2.0https://ftp.ncbi.nlm.nih.gov/genomes/all/GCF/049/350/105/GCF_049350105.2_T2T-MMU8v2.0/
An ortholog table joined on gene names
An ortholog table in the .blocks shape has one row per orthologous group, one
column per genome and a gene id in each cell. NCBI's eukaryotic annotation
pipeline names a gene after its ortholog, so human TP53 is chimpanzee TP53
and gorilla TP53, and for genomes it annotated the table is a join on the
Name attribute of each GFF3.
The join needs only the annotations, so the download is a GFF3 and a sequence report per genome:
# one RefSeq accession per line; the first is the genome the rows are anchored on
datasets download genome accession --inputfile accessions.txt \
--include gff3,seq-report --filename genomes.zip
unzip genomes.zipsymbols_to_blocks.py reads each GFF3 once, writes a BED of its protein-coding
genes and the table, and prints the column order it used:
curl -fO https://raw.githubusercontent.com/GMOD/jbrowse-components/main/scripts/symbols_to_blocks.py
# --anchor names the genome whose genes are the rows; every other column is
# the ortholog of that gene, or a dot
python3 symbols_to_blocks.py --anchor human -o primates.blocks \
human=human.gff.gz chimp=chimp.gff.gz bonobo=bonobo.gff.gz gorilla=gorilla.gff.gz \
sumatran=sumatran.gff.gz bornean=bornean.gff.gz siamang=siamang.gff.gz macaque=macaque.gff.gzsymbols_to_blocks.py joins on the case-folded symbol and handles these cases:
- A gene named with an NCBI
LOCplaceholder joins nothing. RefSeq names the salivary amylase copies that way in the other primates. - A symbol shared by several genes in one genome gets a row per copy, because a link joins one gene to one gene. The main case is the pseudoautosomal genes, annotated on both X and Y.
- Open reading frame genes spell differently in the apes (human C1orf35 is chimp C1H1orf35), and the helper reads that back.
The helper prints how much of each column it filled.
Setting up each lane's assembly from its hub
Each genome is also a hub on genomes.jbrowse.org.
A hub's config.json holds a whole JBrowse assembly: the 2bit sequence, an
alias table that resolves the NC_ names in the BEDs, and the NCBI RefSeq
genes. Each lane takes its assembly entry and gene track from its hub, so the
ortholog table is the one file built here:
# a GenArk hub path is the accession cut into threes
curl -fO https://jbrowse.org/hubs/genark/GCF/028/858/775/GCF_028858775.2/config.jsonThe build relabels the lane and adds the short name as an alias, so a session
can still say chimp:
{
"name": "GCF_028858775.2",
"displayName": "Chimpanzee (NHGRI_mPanTro3-v2.1)",
"aliases": ["chimp"],
"sequence": {
"type": "ReferenceSequenceTrack",
"trackId": "GCF_028858775.2-ReferenceSequenceTrack",
"adapter": {
"type": "TwoBitAdapter",
"uri": "https://hgdownload.soe.ucsc.edu/hubs/GCF/028/858/775/GCF_028858775.2/GCF_028858775.2.2bit",
"chromSizes": "https://hgdownload.soe.ucsc.edu/hubs/GCF/028/858/775/GCF_028858775.2/GCF_028858775.2.chrom.sizes.txt"
}
},
"refNameAliases": {
"adapter": {
"type": "RefNameAliasAdapter",
"refNameColumnHeaderName": "ucsc",
"uri": "https://hgdownload.soe.ucsc.edu/hubs/GCF/028/858/775/GCF_028858775.2/GCF_028858775.2.chromAlias.txt"
}
}
}refNameColumnHeaderName makes the UCSC names canonical, so the lane headers
read chr19. Human is the exception: UCSC serves GRCh38 as hg38 with no
GenArk hub, so the human lane is hg38:
Goes in the assemblies array of config.json. See Assemblies.
{
"name": "hg38",
"uri": "https://jbrowse.org/genomes/GRCh38/fasta/hg38.prefix.fa.gz",
"refNameAliases": {
"uri": "https://s3.amazonaws.com/jbrowse.org/genomes/GRCh38/hg38_aliases.txt"
},
"cytobands": "https://jbrowse.org/genomes/GRCh38/cytoBand.txt"
}jbrowse add-assembly https://jbrowse.org/genomes/GRCh38/fasta/hg38.prefix.fa.gz \
--name hg38 \
--refNameAliases https://s3.amazonaws.com/jbrowse.org/genomes/GRCh38/hg38_aliases.txt \
--config '{"cytobands":"https://jbrowse.org/genomes/GRCh38/cytoBand.txt"}'hg38 is one of the genomes JBrowse Desktop hosts, with gene tracks already set up: on the start screen click Show all available genomes and pick it. To load the files of this config instead:
In 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/genomes/GRCh38/fasta/hg38.prefix.fa.gz
https://jbrowse.org/genomes/GRCh38/fasta/hg38.prefix.fa.gz.fai
https://jbrowse.org/genomes/GRCh38/fasta/hg38.prefix.fa.gz.gziJBrowse reads the format off the file name. Then fill in:
- Genome name:
hg38 - refName aliases (under More options):
https://s3.amazonaws.com/jbrowse.org/genomes/GRCh38/hg38_aliases.txt - cytobands (under More options):
https://jbrowse.org/genomes/GRCh38/cytoBand.txt
Each lane draws gene models from a gene track on its assembly. For your own annotation, add one per genome from a bgzipped, tabix-indexed GFF3 (prep) that uses the assembly's refNames:
Goes in the tracks array of config.json. See Tracks.
{
"type": "FeatureTrack",
"trackId": "chimp_genes",
"name": "chimp genes",
"assemblyNames": ["GCF_028858775.2"],
"adapter": {
"type": "Gff3TabixAdapter",
"uri": "chimp.sorted.gff3.gz"
}
}jbrowse add-track chimp.sorted.gff3.gz \
--trackId chimp_genes \
--name "chimp genes" \
--assemblyNames GCF_028858775.2 \
--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:
chimp.sorted.gff3.gz
Click Next. JBrowse reads the adapter and track type off the file name. Then fill in:
- Track name:
chimp genes - Assembly:
GCF_028858775.2
Click Add.
chimp.sorted.gff3.gz is relative to a config.json. Replace it with its URL or its path on this computer.
Loading the eight-genome ortholog track
One SyntenyTrack names all eight assemblies, and blockAssemblies and
bedLocations hold one entry per table column, in the order the helper printed.
In grammar-of-graphics terms, the display's color is a color scale, and
{ "field": "cluster" } maps each gene's ortholog group, named by its gene
symbol, to a color:
- A conserved gene is one color down the whole stack, and a lane missing it breaks the column.
- A gene no group claims is grey.
- A key naming the groups appears in the top right once the window holds few enough to list. Untick Show... → Show legend in the track menu to hide it.
Goes in the tracks array of config.json. See Tracks.
{
"type": "SyntenyTrack",
"trackId": "primate_orthologs",
"name": "Primate orthologs by gene symbol (8 genomes, RefSeq)",
"assemblyNames": [
"hg38",
"GCF_028858775.2",
"GCF_029289425.2",
"GCF_029281585.2",
"GCF_028885655.2",
"GCF_028885625.2",
"GCF_028878055.3",
"GCF_049350105.2"
],
"adapter": {
"type": "MCScanBlocksAdapter",
"mcscanBlocksLocation": { "uri": "primates.blocks.gz" },
"blockAssemblies": [
"hg38",
"GCF_028858775.2",
"GCF_029289425.2",
"GCF_029281585.2",
"GCF_028885655.2",
"GCF_028885625.2",
"GCF_028878055.3",
"GCF_049350105.2"
],
"bedLocations": [
"human.bed.gz",
"chimp.bed.gz",
"bonobo.bed.gz",
"gorilla.bed.gz",
"sumatran.bed.gz",
"bornean.bed.gz",
"siamang.bed.gz",
"macaque.bed.gz"
]
},
"displays": [
{
"type": "MultiWaySyntenyDisplay",
"color": { "field": "cluster" }
}
]
}jbrowse add-track-json '{
"type": "SyntenyTrack",
"trackId": "primate_orthologs",
"name": "Primate orthologs by gene symbol (8 genomes, RefSeq)",
"assemblyNames": [
"hg38",
"GCF_028858775.2",
"GCF_029289425.2",
"GCF_029281585.2",
"GCF_028885655.2",
"GCF_028885625.2",
"GCF_028878055.3",
"GCF_049350105.2"
],
"adapter": {
"type": "MCScanBlocksAdapter",
"mcscanBlocksLocation": { "uri": "primates.blocks.gz" },
"blockAssemblies": [
"hg38",
"GCF_028858775.2",
"GCF_029289425.2",
"GCF_029281585.2",
"GCF_028885655.2",
"GCF_028885625.2",
"GCF_028878055.3",
"GCF_049350105.2"
],
"bedLocations": [
"human.bed.gz",
"chimp.bed.gz",
"bonobo.bed.gz",
"gorilla.bed.gz",
"sumatran.bed.gz",
"bornean.bed.gz",
"siamang.bed.gz",
"macaque.bed.gz"
]
},
"displays": [
{
"type": "MultiWaySyntenyDisplay",
"color": { "field": "cluster" }
}
]
}'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": "SyntenyTrack",
"trackId": "primate_orthologs",
"name": "Primate orthologs by gene symbol (8 genomes, RefSeq)",
"assemblyNames": [
"hg38",
"GCF_028858775.2",
"GCF_029289425.2",
"GCF_029281585.2",
"GCF_028885655.2",
"GCF_028885625.2",
"GCF_028878055.3",
"GCF_049350105.2"
],
"adapter": {
"type": "MCScanBlocksAdapter",
"mcscanBlocksLocation": { "uri": "primates.blocks.gz" },
"blockAssemblies": [
"hg38",
"GCF_028858775.2",
"GCF_029289425.2",
"GCF_029281585.2",
"GCF_028885655.2",
"GCF_028885625.2",
"GCF_028878055.3",
"GCF_049350105.2"
],
"bedLocations": [
"human.bed.gz",
"chimp.bed.gz",
"bonobo.bed.gz",
"gorilla.bed.gz",
"sumatran.bed.gz",
"bornean.bed.gz",
"siamang.bed.gz",
"macaque.bed.gz"
]
},
"displays": [
{
"type": "MultiWaySyntenyDisplay",
"color": { "field": "cluster" }
}
]
}primates.blocks.gz, human.bed.gz, chimp.bed.gz, bonobo.bed.gz, gorilla.bed.gz, sumatran.bed.gz, bornean.bed.gz, siamang.bed.gz, macaque.bed.gz are relative to a config.json. Replace each 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.
Reading the TP53 neighbourhood across eight primates
In a linear genome view on human, the track draws a lane per primate under the
human axis, each in that genome's coordinates. Each lane's header names the
chromosome and span, with [rev] where the lane runs against human
(lane headers).
Color by... → Strand, under Ribbons on the track menu, colors each
ribbon by whether its two lanes agree in orientation. The session below opens
the TP53 neighbourhood with it:
Goes at the top level of config.json, replacing any defaultSession there. See Default session.
{
"defaultSession": {
"name": "TP53 neighbourhood across eight primates",
"views": [
{
"type": "LinearGenomeView",
"assembly": "hg38",
"loc": "chr17:7,400,000-7,700,000",
"tracks": [
{
"trackId": "primate_orthologs",
"type": "MultiWaySyntenyDisplay",
"ribbonColor": { "field": "strand" },
"height": 620
}
]
}
]
}
}jbrowse set-default-session --session - << 'EOF'
{
"name": "TP53 neighbourhood across eight primates",
"views": [
{
"type": "LinearGenomeView",
"assembly": "hg38",
"loc": "chr17:7,400,000-7,700,000",
"tracks": [
{
"trackId": "primate_orthologs",
"type": "MultiWaySyntenyDisplay",
"ribbonColor": { "field": "strand" },
"height": 620
}
]
}
]
}
EOFNavigate to chr17:34,000,000-38,000,000 on 17q, where the strand color
separates forward blocks from reversed ones.
Human chromosome 2 as two fused ape chromosomes
Human chromosome 2 is two ape chromosomes joined end to end. To see the join:
- Open human over chimpanzee from Add → Linear synteny view, with
primate_orthologsbetween them - Navigate the human row to
chr2and the chimpanzee row tochr12andchr13, the two chromosomes that hold its halves - Pick Target in the palette button menu, which paints each ribbon by the chimpanzee chromosome it lands on
In the multi-lane view, each ape lane picks the contig with more genes in the window and names the other in its header. Show ⟨contig⟩ in this lane on the header menu swaps the lane onto it.
Reproduce it end to end
The script needs the tools under Prerequisites and works in three steps:
- Download the eight annotations and sequence reports, and keep the genes on the assembled chromosomes each report names, so no lane lands on an unplaced scaffold.
- Join the annotations on gene symbol into one table anchored on human.
- Write the config from each genome's hub entry and gene track, plus the ortholog track.
curl -fO https://raw.githubusercontent.com/GMOD/jbrowse-components/main/scripts/build_primate_orthologs.sh
bash build_primate_orthologs.shSee also
- Tutorial: Synteny from an ortholog table (grape, peach, cacao)
- Tutorial: Synteny visualization (OrthoFinder orthogroups)
- Tutorial: Synteny from gene symbols (44 E. coli genomes)
- Tutorial: Synteny visualization (all-vs-all minimap2)
External links
- NCBI Datasets: https://www.ncbi.nlm.nih.gov/datasets/
Citations
- Yoo D, Rhie A, et al. Complete sequencing of ape genomes. Nature (2025). https://doi.org/10.1038/s41586-025-08816-3
- O'Leary NA, et al. Reference sequence (RefSeq) database at NCBI: current status, taxonomic expansion, and functional annotation. Nucleic Acids Res (2016). https://doi.org/10.1093/nar/gkv1189
Feedback on this tutorial is welcome: contact us.