Synteny from MCScan anchors (grape, peach)
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.
Grape and peach keep long runs of genes in the same order, though the genomes have diverged too far to align base by base. We load a jcvi MCScan run of the two into a synteny view, where a ribbon joins each orthologous gene pair between the grape and peach views and a bar marks each block (a run of gene pairs in conserved order), then into a dotplot.
Prerequisites
- jcvi with the LAST aligner
- Or, in place of jcvi, an existing MCScanX run: converting one needs only python3
samtools- htslib (
bgzip,tabix) wgetnode, for the JBrowse CLI- A running JBrowse instance (the web quickstart or the desktop quickstart)
On Debian/Ubuntu, apt install samtools tabix wget last-align covers the
aligner and the file tools; jcvi installs with pip install jcvi and node
comes from nodejs.org.
Where the data comes from
Grape (Jaillon et al. 2007) and peach genomes and gene annotations, Ensembl Plants release 58.
The build script takes these files from their URLs, so there is nothing to download by hand.
- grape (Vitis_vinifera, PN40024.v4) genome and CDS FASTA: ftp.ensemblgenomes.org/…/vitis_viniferahttp://ftp.ensemblgenomes.org/pub/plants/release-58/fasta/vitis_vinifera/
- grape gene annotation: ftp.ensemblgenomes.org/…/vitis_viniferahttp://ftp.ensemblgenomes.org/pub/plants/release-58/gff3/vitis_vinifera/
- peach (Prunus_persica, Prunus_persica_NCBIv2) genome and CDS FASTA: ftp.ensemblgenomes.org/…/prunus_persicahttp://ftp.ensemblgenomes.org/pub/plants/release-58/fasta/prunus_persica/
- peach gene annotation: ftp.ensemblgenomes.org/…/prunus_persicahttp://ftp.ensemblgenomes.org/pub/plants/release-58/gff3/prunus_persica/
What .anchors and .anchors.simple hold
The run writes two files that JBrowse loads as separate synteny tracks.
.anchors, via MCScanAnchorsAdapter, is the gene-pair level: each line is one
orthologous pair and its alignment score, with ### separating synteny blocks.
The sample lines and the figures below come from a Phytozome annotation of the
same genomes, so their gene ids and chromosome names differ from the ones the
script writes:
###
VIT_201s0011g00070.1 Prupe.1G290900.1 1430
VIT_201s0011g00080.1 Prupe.1G290800.1 446
VIT_201s0011g00090.1 Prupe.1G290700.1 147.anchors.simple, via MCScanSimpleAnchorsAdapter, is the same run reduced to
one line per block: the first and last gene of the block on each side, a score,
and the block's orientation:
VIT_201s0011g00070.1 VIT_201s0011g00910.1 Prupe.1G281700.1 Prupe.1G290900.1 149 -
VIT_201s0011g02000.1 VIT_201s0011g02280.2 Prupe.1G345900.1 Prupe.1G348100.1 53 -
VIT_201s0011g02300.1 VIT_201s0011g02530.1 Prupe.1G299800.1 Prupe.1G303200.1 39 +.anchors.simple draws one ribbon per block where .anchors draws one per gene
pair. The BED files supply the coordinates for both.
BED files mapping gene ids to coordinates
One BED per genome, prepared from its GFF3 before the ortholog run. The adapters read the first six columns, and column 4 must match the anchor gene ids byte for byte:
chr1 12836 26777 VIT_201s0011g00010.1 0 +
chr1 33170 35791 VIT_201s0011g00030.1 0 +Column 1 must use the same reference sequence names as the JBrowse assembly.
A gene id in the anchors file that no BED names breaks the join, and some such
mismatches load with no error; the
synteny track guide
lists which. The mismatch that matters here is jcvi stripping isoform suffixes
from the ids unless run with --no_strip_names, which the command in the next
section passes.
Producing the BEDs and anchor files with jcvi
The BEDs come from each GFF3, and one jcvi command then writes both anchor files:
python -m jcvi.formats.gff bed --type=mRNA --key=transcript_id \
--primary_only grape.gff3.gz -o grape.bed
python -m jcvi.formats.gff bed --type=mRNA --key=transcript_id \
--primary_only peach.gff3.gz -o peach.bed
python -m jcvi.formats.fasta format grape.cds.fa.gz grape.cds
python -m jcvi.formats.fasta format peach.cds.fa.gz peach.cds
python -m jcvi.compara.catalog ortholog --no_strip_names grape peachThe command writes grape.peach.anchors and grape.peach.anchors.simple to the
working directory. The adapters read anchors and BED files plain or gzipped.
Loading the grape and peach assemblies and gene tracks
We'll load the two genomes the BEDs describe. samtools faidx writes each
.fai the assembly needs beside its FASTA.
Goes in the assemblies array of config.json. See Assemblies.
{ "name": "grape", "uri": "grape.fa" }jbrowse add-assembly grape.fa \
--name grape \
--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:
grape.fa
grape.fa.faiJBrowse reads the format off the file name. Then fill in:
- Genome name:
grape
grape.fa is relative to a config.json. Replace it with its URL or its path on this computer.
Goes in the assemblies array of config.json. See Assemblies.
{ "name": "peach", "uri": "peach.fa" }jbrowse add-assembly peach.fa \
--name peach \
--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:
peach.fa
peach.fa.faiJBrowse reads the format off the file name. Then fill in:
- Genome name:
peach
peach.fa is relative to a config.json. Replace it with its URL or its path on this computer.
Each genome also gets a gene track, which the
close-up below turns to Show only
genes. Add the same track with peach.sorted.gff3.gz under peach. Swap the
uri for your own GFF3, bgzipped and tabix-indexed
(prep).
Goes in the tracks array of config.json. See Tracks.
{
"type": "FeatureTrack",
"trackId": "grape_genes",
"name": "grape genes",
"assemblyNames": ["grape"],
"adapter": {
"type": "Gff3TabixAdapter",
"uri": "grape.sorted.gff3.gz"
}
}jbrowse add-track grape.sorted.gff3.gz \
--trackId grape_genes \
--name "grape genes" \
--assemblyNames grape \
--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:
grape.sorted.gff3.gz
Click Next. JBrowse reads the adapter and track type off the file name. Then fill in:
- Track name:
grape genes - Assembly:
grape
Click Add.
grape.sorted.gff3.gz is relative to a config.json. Replace it with its URL or its path on this computer.
Loading the .anchors and .anchors.simple tracks
Each adapter takes the anchor file plus the two BEDs, and assemblyNames lists
the genomes in the order the anchor columns are in (column 1's genome first):
Goes in the tracks array of config.json. See Tracks.
{
"type": "SyntenyTrack",
"trackId": "grape_peach_anchors",
"name": "Grape peach synteny (MCScan, anchors)",
"assemblyNames": ["grape", "peach"],
"adapter": {
"type": "MCScanAnchorsAdapter",
"uri": "grape.peach.anchors.gz",
"bed1": "grape.bed.gz",
"bed2": "peach.bed.gz",
"assemblyNames": ["grape", "peach"]
}
}jbrowse add-track grape.peach.anchors.gz \
--trackId grape_peach_anchors \
--name "Grape peach synteny (MCScan, anchors)" \
--assemblyNames grape,peach \
--bed1 grape.bed.gz \
--bed2 peach.bed.gz \
--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": "grape_peach_anchors",
"name": "Grape peach synteny (MCScan, anchors)",
"assemblyNames": ["grape", "peach"],
"adapter": {
"type": "MCScanAnchorsAdapter",
"uri": "grape.peach.anchors.gz",
"bed1": "grape.bed.gz",
"bed2": "peach.bed.gz",
"assemblyNames": ["grape", "peach"]
}
}grape.peach.anchors.gz 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.
The .anchors.simple track takes the same shape with the adapter type and file
swapped:
Goes in the tracks array of config.json. See Tracks.
{
"type": "SyntenyTrack",
"trackId": "grape_peach_anchors_simple",
"name": "Grape peach synteny (MCScan, simple anchors)",
"assemblyNames": ["grape", "peach"],
"adapter": {
"type": "MCScanSimpleAnchorsAdapter",
"uri": "grape.peach.anchors.simple.gz",
"bed1": "grape.bed.gz",
"bed2": "peach.bed.gz",
"assemblyNames": ["grape", "peach"]
}
}jbrowse add-track grape.peach.anchors.simple.gz \
--trackId grape_peach_anchors_simple \
--name "Grape peach synteny (MCScan, simple anchors)" \
--assemblyNames grape,peach \
--bed1 grape.bed.gz \
--bed2 peach.bed.gz \
--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": "grape_peach_anchors_simple",
"name": "Grape peach synteny (MCScan, simple anchors)",
"assemblyNames": ["grape", "peach"],
"adapter": {
"type": "MCScanSimpleAnchorsAdapter",
"uri": "grape.peach.anchors.simple.gz",
"bed1": "grape.bed.gz",
"bed2": "peach.bed.gz",
"assemblyNames": ["grape", "peach"]
}
}grape.peach.anchors.simple.gz 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.
Both adapters read the whole file into memory, which MCScan output is small enough for.
Viewing gene pairs and blocks in one synteny view
We'll start with Add → Linear synteny view and pick peach and grape. Then:
- Turn on both MCScan tracks in the band between them.
- Turn on the simple-anchors track in each panel's track selector, where it draws as a row of bars.
The bars in each panel come from the block track's LGVSyntenyDisplay, which
draws synteny as features in an ordinary linear genome view row. Selecting it by
name needs the full displays array:
Goes in the tracks array of config.json. See Tracks.
{
"type": "SyntenyTrack",
"trackId": "grape_peach_anchors_simple",
"name": "Grape peach synteny (MCScan, simple anchors)",
"assemblyNames": ["grape", "peach"],
"adapter": {
"type": "MCScanSimpleAnchorsAdapter",
"uri": "grape.peach.anchors.simple.gz",
"bed1": "grape.bed.gz",
"bed2": "peach.bed.gz",
"assemblyNames": ["grape", "peach"]
},
"displays": [
{
"type": "LGVSyntenyDisplay",
"height": 60
}
]
}jbrowse add-track-json '{
"type": "SyntenyTrack",
"trackId": "grape_peach_anchors_simple",
"name": "Grape peach synteny (MCScan, simple anchors)",
"assemblyNames": ["grape", "peach"],
"adapter": {
"type": "MCScanSimpleAnchorsAdapter",
"uri": "grape.peach.anchors.simple.gz",
"bed1": "grape.bed.gz",
"bed2": "peach.bed.gz",
"assemblyNames": ["grape", "peach"]
},
"displays": [
{
"type": "LGVSyntenyDisplay",
"height": 60
}
]
}'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": "grape_peach_anchors_simple",
"name": "Grape peach synteny (MCScan, simple anchors)",
"assemblyNames": ["grape", "peach"],
"adapter": {
"type": "MCScanSimpleAnchorsAdapter",
"uri": "grape.peach.anchors.simple.gz",
"bed1": "grape.bed.gz",
"bed2": "peach.bed.gz",
"assemblyNames": ["grape", "peach"]
},
"displays": [
{
"type": "LGVSyntenyDisplay",
"height": 60
}
]
}grape.peach.anchors.simple.gz 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 single gene pair up close
Zoom to one block with both gene tracks on and set to Show only genes.
MCScan anchors only the pairs it could call confidently, so most genes have no ribbon.
Tandem copies sharing one ortholog
Pick Color by value → Syntenic depth on the palette button in the view
header. A ribbon stays grey where its two genes pair only with each other, and
turns orange where several genes share one ortholog, which is often a tandem
array. The count covers the whole .anchors file, so a gene whose other copies
are off screen still takes color.
Viewing the gene pairs as a dotplot
Either track also loads in a dotplot (Add → Dotplot view), where a gene pair is one point and a block a run of them. The axes start in index order; Re-order chromosomes, in the overflow menu of the dotplot header, sorts the vertical axis to follow the horizontal one.
Re-order chromosomes puts each peach chromosome's strongest grape partner on
the diagonal, and its other partners stay off it. The
script prints the same pairings off
.anchors.simple.
Converting an MCScanX run
MCScanX is a different program from jcvi's
MCScan. It writes one .collinearity holding every block, self-synteny and
cross-species together, and tells genomes apart by a two-letter tag on each
chromosome name.
mcscanx_to_anchors.py
splits a run into the four files jcvi writes, in place of the
jcvi step:
curl -fO https://raw.githubusercontent.com/GMOD/jbrowse-components/main/scripts/mcscanx_to_anchors.py
python3 mcscanx_to_anchors.py --gff xyz.gff --collinearity xyz.collinearity \
--species vv=grape --species pp=peach --strand-gff3 peach=peach.gff3.gzThe track configs above load the converted files
unchanged. --species order is the anchors column order, so it has to match the
track's assemblyNames. Two options decide whether the result draws:
--chr-prefix peach=Pp0prepends to the refNames, and--keep-chr-tagkeeps MCScanX's tag, stripped by default (vv1becomes1)--strand-gff3 peach=peach.gff3.gzrecovers strand from the annotation, so an inverted.anchorspair draws as inverted
--fai peach=peach.fa.fai checks the refNames against the assembly; an unknown
name draws empty. An anchors score becomes -log10 of MCScanX's e-value.
The number of --species names sets what the run writes:
- A third species writes an ortholog table instead, since one
.collinearitycovers every pair. See ortholog tables. - A single species keeps the blocks duplicated within that genome, which Synteny visualization (a polyploid against itself) draws as a dotplot of one assembly on both axes.
Reproduce it end to end
build_grape_peach_anchors.sh
runs everything above and writes a config.json with both assemblies, gene
tracks, both MCScan tracks and a default session opening them together:
- Download the grape and peach genomes, annotations and CDS from Ensembl Plants.
- Write a BED and a CDS file per genome keyed on transcript ids, and run jcvi
with
--no_strip_namesso the anchor ids match the BEDs. - Count anchors per peach-grape chromosome pair off
.anchors.simple, the pairing the reordered dotplot shows. - Write the config with both assemblies, gene tracks, both MCScan tracks and a session.
curl -fO https://raw.githubusercontent.com/GMOD/jbrowse-components/main/scripts/build_grape_peach_anchors.sh
bash build_grape_peach_anchors.sh
npx --yes serve grape_peach_anchors_build/jbrowse2 # then open the printed URLSee also
- Tutorial: Synteny visualization (pairwise minimap2)
- Tutorial: Synteny from an ortholog table (grape, peach, cacao)
- User guide: Linear synteny view
- Config guide: Synteny track
- Reference: MCScanAnchorsAdapter
- Reference: MCScanSimpleAnchorsAdapter
Citations
- Tang et al. (2008). Unraveling ancient hexaploidy through multiply-aligned angiosperm gene maps, the MCScan method jcvi implements
- Jaillon et al. (2007). The grapevine genome sequence suggests ancestral hexaploidization in major angiosperm phyla
Feedback on this tutorial is welcome: contact us.