Synteny from a Cactus alignment (T2T apes)
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 stack ape genomes under a human locus in the order of their family tree and compare each genome with the one above it, so a change of orientation shows up between the two lineages that differ. The comparisons come from the Cactus alignment of the telomere-to-telomere ape genomes, whose authors publish a chain for every pair of genomes in it. We:
- extract the chains between neighbouring genomes into one indexed file
- load them as one multi-way synteny track over the apes, each lane drawing the RefSeq genes of that ape's hub on genomes.jbrowse.org
- color the ribbons by strand to read orientation at TP53 and at a block on 17q12
- count the 17q12 block's aligned bases out of the file
Prerequisites
- chain2paf, built with
cargo install --path .from its checkout - The JBrowse CLI, for
jbrowse make-pif - htslib (
tabix) andpython3, for the check at the end - A running JBrowse instance (the web quickstart or the desktop quickstart)
# Debian/Ubuntu
sudo apt install tabix
# or conda, which has every tool above
conda install -c bioconda -c conda-forge htslib
# any platform
npm install -g @jbrowse/cliThe data
The Cactus alignment of hg38 and the T2T ape assemblies (Yoo et al. 2025), built with Progressive Cactus (Armstrong et al. 2020).
You don't need these files to follow the page: the track configs below read the hosted results. The build script fetches them to rebuild those results. The chain steps take your own chains.
| What it is | File |
|---|---|
Chains between every pair of genomes in the 8-way alignment, one <genome>_vs_<genome>.chain.gz per pair | chains/ |
Read by URL (no download needed)
| What it is | File |
|---|---|
| The pairs the track uses, as one indexed alignment | apes.pif.gz |
Chains between neighbours, from one alignment
Each lane reads two chains from the file. The chain between hg38 and that ape places the lane under the human window, and the chain between that ape and the one above it draws the ribbons between them. The pairs cover every ape in the stack:
- hg38 against each ape
- chimpanzee against bonobo, bonobo against gorilla, gorilla against the Sumatran orangutan, the Sumatran against the Bornean orangutan, and the Bornean orangutan against the siamang
All of them come out of one multiple alignment, so the chimpanzee in the hg38 pair and the chimpanzee in the bonobo pair are aligned the same way.
chain2paf reads a chain uncompressed:
gzip -dc genomeA_vs_genomeB.chain.gz > pair.chainchain2paf writes the chain's query (genomeB) as each PAF row's first
sequence and its target (genomeA) as the second. A PanSN prefix on each name
(genome#haplotype#contig) tells JBrowse which genome a sequence belongs to, so
every pair can go into one file:
# the prefix is the assembly name JBrowse knows each genome by
chain2paf -i pair.chain \
| awk -F'\t' -v q=genomeB -v t=genomeA 'BEGIN { OFS = "\t" } { $1 = q "#0#" $1; $6 = t "#0#" $6; print }' \
>> apes.pafmake-pif sorts and indexes the concatenated pairs, writing each row twice so a
query from either genome is one tabix lookup:
jbrowse make-pif apes.paf --out apes.pif.gzmake-pif warns that the file states only some of its pairs. The missing ones
are the pairs no two neighbouring lanes need, such as chimpanzee against the
siamang.
One track over the apes
A MultiGenomeIndexedPAFAdapter reads the file and finds each genome by its
PanSN prefix. rows.domain stacks the lanes in tree order, so each lane's
neighbour above it is the genome its ribbons were aligned to. The assemblies and
gene tracks come from each genome's hub unchanged, as in the hosted config.
Goes in the tracks array of config.json. See Tracks.
{
"type": "SyntenyTrack",
"trackId": "t2t_apes_cactus",
"name": "T2T apes (Cactus alignment)",
"assemblyNames": [
"hg38",
"GCF_028858775.2",
"GCF_029289425.2",
"GCF_029281585.2",
"GCF_028885655.2",
"GCF_028885625.2",
"GCF_028878055.3"
],
"adapter": {
"type": "MultiGenomeIndexedPAFAdapter",
"uri": "https://jbrowse.org/demos/t2t_apes_cactus/apes.pif.gz",
"assemblyNames": [
"hg38",
"GCF_028858775.2",
"GCF_029289425.2",
"GCF_029281585.2",
"GCF_028885655.2",
"GCF_028885625.2",
"GCF_028878055.3"
]
},
"displays": [
{
"type": "MultiWaySyntenyDisplay",
"displayId": "t2t_apes_cactus-MultiWaySyntenyDisplay",
"rows": {
"domain": [
"GCF_028858775.2",
"GCF_029289425.2",
"GCF_029281585.2",
"GCF_028885655.2",
"GCF_028885625.2",
"GCF_028878055.3"
]
}
}
]
}jbrowse add-track-json '{
"type": "SyntenyTrack",
"trackId": "t2t_apes_cactus",
"name": "T2T apes (Cactus alignment)",
"assemblyNames": [
"hg38",
"GCF_028858775.2",
"GCF_029289425.2",
"GCF_029281585.2",
"GCF_028885655.2",
"GCF_028885625.2",
"GCF_028878055.3"
],
"adapter": {
"type": "MultiGenomeIndexedPAFAdapter",
"uri": "https://jbrowse.org/demos/t2t_apes_cactus/apes.pif.gz",
"assemblyNames": [
"hg38",
"GCF_028858775.2",
"GCF_029289425.2",
"GCF_029281585.2",
"GCF_028885655.2",
"GCF_028885625.2",
"GCF_028878055.3"
]
},
"displays": [
{
"type": "MultiWaySyntenyDisplay",
"displayId": "t2t_apes_cactus-MultiWaySyntenyDisplay",
"rows": {
"domain": [
"GCF_028858775.2",
"GCF_029289425.2",
"GCF_029281585.2",
"GCF_028885655.2",
"GCF_028885625.2",
"GCF_028878055.3"
]
}
}
]
}'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": "t2t_apes_cactus",
"name": "T2T apes (Cactus alignment)",
"assemblyNames": [
"hg38",
"GCF_028858775.2",
"GCF_029289425.2",
"GCF_029281585.2",
"GCF_028885655.2",
"GCF_028885625.2",
"GCF_028878055.3"
],
"adapter": {
"type": "MultiGenomeIndexedPAFAdapter",
"uri": "https://jbrowse.org/demos/t2t_apes_cactus/apes.pif.gz",
"assemblyNames": [
"hg38",
"GCF_028858775.2",
"GCF_029289425.2",
"GCF_029281585.2",
"GCF_028885655.2",
"GCF_028885625.2",
"GCF_028878055.3"
]
},
"displays": [
{
"type": "MultiWaySyntenyDisplay",
"displayId": "t2t_apes_cactus-MultiWaySyntenyDisplay",
"rows": {
"domain": [
"GCF_028858775.2",
"GCF_029289425.2",
"GCF_029281585.2",
"GCF_028885655.2",
"GCF_028885625.2",
"GCF_028878055.3"
]
}
}
]
}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 TP53 down the tree
Opened on hg38 around TP53, the track draws a lane per ape under human, each
in that genome's own coordinates. Each lane header names the chromosome and the
span the lane shows, with [rev] where the lane runs against human.
The ribbons color by strand by default (Color by... → Strand, under Ribbons in the track menu): each ribbon shows whether its two lanes agree in orientation. The session below opens on it:
Goes at the top level of config.json, replacing any defaultSession there. See Default session.
{
"defaultSession": {
"name": "TP53 neighbourhood across seven apes",
"views": [
{
"type": "LinearGenomeView",
"assembly": "hg38",
"loc": "chr17:7,400,000-7,700,000",
"tracks": [
"hg38-ncbiRefSeq",
{
"trackId": "t2t_apes_cactus",
"type": "MultiWaySyntenyDisplay",
"ribbonColor": { "field": "strand" },
"height": 600
}
]
}
]
}
}jbrowse set-default-session --session - << 'EOF'
{
"name": "TP53 neighbourhood across seven apes",
"views": [
{
"type": "LinearGenomeView",
"assembly": "hg38",
"loc": "chr17:7,400,000-7,700,000",
"tracks": [
"hg38-ncbiRefSeq",
{
"trackId": "t2t_apes_cactus",
"type": "MultiWaySyntenyDisplay",
"ribbonColor": { "field": "strand" },
"height": 600
}
]
}
]
}
EOFA block on 17q that splits the African apes
Navigate to chr17:33,200,000-35,800,000, on 17q12.
Down the stack, the orientation changes from human to chimpanzee and back from gorilla to the Sumatran orangutan, so chimpanzee, bonobo and gorilla have the block in one orientation and human, both orangutans and the siamang in the other.
Checking the 17q block against the chains
The hg38 rows of the file give each ape's orientation over the window directly. A Cactus chain spans gaps, and a reversed chain often sits inside the gap of a forward one, so the script counts the bases each chain aligns inside the window:
# aligned bases per genome and strand over hg38 chr17:33.2-35.8 Mb
import re
import subprocess
from collections import Counter
PIF = 'https://jbrowse.org/demos/t2t_apes_cactus/apes.pif.gz'
START, END = 33_200_000, 35_800_000
# rows keyed on hg38 ('t' prefix): one per chain against each ape
rows = subprocess.run(
['tabix', PIF, f'thg38#0#chr17:{START}-{END}'],
capture_output=True, text=True, check=True,
).stdout.splitlines()
aligned = Counter()
for row in rows:
f = row.split('\t')
pos, strand, genome = int(f[2]), f[4], f[5].split('#')[0]
cigar = next(x[5:] for x in f[12:] if x.startswith('cg:Z:'))
for n, op in re.findall(r'(\d+)([MID])', cigar):
n = int(n)
if op == 'M':
aligned[genome, strand] += max(0, min(pos + n, END) - max(pos, START))
if op != 'I':
pos += n
for (genome, strand), n in sorted(aligned.items()):
if n > 100_000:
print(genome, strand, n)Chimpanzee (GCF_028858775.2), bonobo (GCF_029289425.2) and gorilla
(GCF_029281585.2) align the window on the reverse strand of hg38, and both
orangutans (GCF_028885655.2, GCF_028885625.2) and the siamang
(GCF_028878055.3) on the forward strand, each with nearly all of its aligned
bases on one strand.
Reproduce it end to end
The script works in four steps:
- Fetch each genome's hub config from genomes.jbrowse.org, which gives its lane the assembly and the NCBI RefSeq gene track.
- Download the chains: hg38 against each ape, and each ape against the next one down the tree.
- Convert each chain to PAF with PanSN names and index them all as one file.
- Write the config, with the lanes stacked in tree order.
curl -fO https://raw.githubusercontent.com/GMOD/jbrowse-components/main/scripts/build_t2t_apes_cactus_multiway.sh
bash build_t2t_apes_cactus_multiway.sh # writes ./t2t_apes_cactus_build/config.jsonSee also
- Tutorial: Synteny from liftOver chains (hg38 and eight vertebrates)
- Tutorial: Synteny from gene symbols (eight primates)
- Tutorial: Pangenome (Minigraph-Cactus)
- Tutorial: Synteny visualization (all-vs-all minimap2)
External links
- Cactus T2T ape alignments: https://cglgenomics.ucsc.edu/february-2024-t2t-apes
- The T2T primates project: https://github.com/marbl/Primates
- chain2paf: https://github.com/AndreaGuarracino/chain2paf
Citations
- Yoo D, Rhie A, Hebbar P, et al. Complete sequencing of ape genomes. Nature (2025). https://doi.org/10.1038/s41586-025-08816-3
- Armstrong J, Hickey G, Diekhans M, et al. Progressive Cactus is a multiple-genome aligner for the thousand-genome era. Nature (2020). https://doi.org/10.1038/s41586-020-2871-y
Feedback on this tutorial is welcome: contact us.