A selected haplotype (Dog10K)
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.
Dogs differ in body size more than any other mammal, and a haplotype (a stretch of neighbouring variants inherited together) at the growth-factor gene IGF1 is a major reason. Breeds at the two ends of the size range differ in allele frequency there, which Fst measures on a scale from 0 to 1. In the Dog10K collection of sequenced dogs and wolves, from a genome-wide scan down to IGF1 on chr15, we:
- load a windowed Fst scan between toy and giant breeds as a Manhattan track, with a reference line at a percentile cutoff
- load the IGF1 peak, sliced out of the SNV callset, as a variant track whose rows a sample sheet colors by size class
- cluster the rows with Clustering → Cluster rows by genotype... to find the haplotype each size class has and where the wolves fall
Prerequisites
- the
UU_Cfam_GSD_1.0dog assembly (UCSC's canFam4) set up in JBrowse. The canFam4 hub on genomes.jbrowse.org is a config that loads it with its gene and repeat tracks, and the assemblies guide builds one by hand. This track reads itschrom.sizesalone. bcftoolsbuilt with libcurlcurlpython3- htslib (
tabix)
# Debian/Ubuntu
sudo apt install bcftools tabix
# or conda, which has every tool above
conda install -c bioconda -c conda-forge bcftools htslibThe scripts write local files, which JBrowse Desktop opens by path and JBrowse Web takes through Add track.
The data
The Dog10K consortium's public share (Meadows et al. 2023), read directly over HTTP with no local copy of either callset.
The tracks below read local files that the build script writes from these, so run it first, or rerun the scan and the slice with groups and regions of your own, as Scanning for peaks in another trait lists. The script fetches everything itself.
| What it is | File |
|---|---|
| The phased imputation panel, scored window by window for the Fst scan | AutoAndXPAR.Dog10K.phased.bcf |
| The SNV/indel callset the IGF1 window is sliced from | AutoAndXPAR.SNPs.vqsr99.vcf.gz |
| The sample table, which the scripts derive the breed groups and the wolf outgroup from | dog10K-alignment-sample-table.2022-02-23-v7.txt |
Loading the UU_Cfam_GSD_1.0 dog assembly
The tracks name UU_Cfam_GSD_1.0, the Dog10K reference that UCSC calls canFam4.
We load it from UCSC's 2bit, with the alias file that maps the chr names to
GenBank accessions:
Goes in the assemblies array of config.json. See Assemblies.
{
"name": "UU_Cfam_GSD_1.0",
"aliases": ["canFam4"],
"sequence": {
"adapter": {
"type": "TwoBitAdapter",
"uri": "https://hgdownload.soe.ucsc.edu/goldenPath/canFam4/bigZips/canFam4.2bit"
}
},
"refNameAliases": {
"uri": "https://hgdownload.soe.ucsc.edu/goldenPath/canFam4/bigZips/canFam4.chromAlias.txt"
}
}jbrowse add-assembly https://hgdownload.soe.ucsc.edu/goldenPath/canFam4/bigZips/canFam4.2bit \
--name UU_Cfam_GSD_1.0 \
--alias canFam4 \
--refNameAliases https://hgdownload.soe.ucsc.edu/goldenPath/canFam4/bigZips/canFam4.chromAlias.txtThe figures also show NCBI's RefSeq genes as a track:
Goes in the tracks array of config.json. See Tracks.
{
"type": "FeatureTrack",
"trackId": "canFam4_ncbi_refseq",
"name": "NCBI RefSeq genes (canFam4)",
"assemblyNames": ["UU_Cfam_GSD_1.0"],
"adapter": {
"type": "Gff3TabixAdapter",
"gffGzLocation": {
"uri": "https://jbrowse.org/ucsc/canFam4/ncbiRefSeq.gff.gz"
},
"index": {
"indexType": "CSI",
"location": {
"uri": "https://jbrowse.org/ucsc/canFam4/ncbiRefSeq.gff.gz.csi"
}
}
}
}jbrowse add-track-json '{
"type": "FeatureTrack",
"trackId": "canFam4_ncbi_refseq",
"name": "NCBI RefSeq genes (canFam4)",
"assemblyNames": ["UU_Cfam_GSD_1.0"],
"adapter": {
"type": "Gff3TabixAdapter",
"gffGzLocation": {
"uri": "https://jbrowse.org/ucsc/canFam4/ncbiRefSeq.gff.gz"
},
"index": {
"indexType": "CSI",
"location": {
"uri": "https://jbrowse.org/ucsc/canFam4/ncbiRefSeq.gff.gz.csi"
}
}
}
}'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": "canFam4_ncbi_refseq",
"name": "NCBI RefSeq genes (canFam4)",
"assemblyNames": ["UU_Cfam_GSD_1.0"],
"adapter": {
"type": "Gff3TabixAdapter",
"gffGzLocation": {
"uri": "https://jbrowse.org/ucsc/canFam4/ncbiRefSeq.gff.gz"
},
"index": {
"indexType": "CSI",
"location": {
"uri": "https://jbrowse.org/ucsc/canFam4/ncbiRefSeq.gff.gz.csi"
}
}
}
}Scanning the genome for toy-versus-giant Fst peaks
Body size is the trait, so the two groups are the breeds at its extremes: every
animal of the toy and small breeds against every animal of the giant breeds.
Hudson Fst (Hudson et al. 1992)
scores how far apart the two groups' allele frequencies sit, computed per window
over the Dog10K phased imputation panel as a ratio of averages
(Bhatia et al. 2013).
build_dog10k_size_fst.sh
writes one BED line per window.
A Manhattan track expects a -log10(p) column, and this file has an Fst column.
GWASAdapter takes the column to read as the score
(scoreColumn) and the transform
to apply to it
(scoreTransform) as separate
settings, so naming the column is enough: Fst is already on the scale the plot
draws.
Goes in the tracks array of config.json. See Tracks.
{
"type": "GWASTrack",
"trackId": "dog10k_size_fst",
"name": "Fst, toy/small vs giant breeds (200 kb windows)",
"assemblyNames": ["UU_Cfam_GSD_1.0"],
"adapter": {
"type": "GWASAdapter",
"uri": "dog10k_size_fst.bed.gz",
"columnNames": ["chrom", "chromStart", "chromEnd", "name", "fst", "sites"],
"scoreColumn": "fst"
},
"displayDefaults": {
"encoding": {
"y": {
"axis": { "title": "Hudson Fst" },
"rules": [
{
"value": 0.295,
"color": "rgb(200,60,60)",
"label": "99.9th percentile"
}
]
}
}
}
}jbrowse add-track-json '{
"type": "GWASTrack",
"trackId": "dog10k_size_fst",
"name": "Fst, toy/small vs giant breeds (200 kb windows)",
"assemblyNames": ["UU_Cfam_GSD_1.0"],
"adapter": {
"type": "GWASAdapter",
"uri": "dog10k_size_fst.bed.gz",
"columnNames": ["chrom", "chromStart", "chromEnd", "name", "fst", "sites"],
"scoreColumn": "fst"
},
"displayDefaults": {
"encoding": {
"y": {
"axis": { "title": "Hudson Fst" },
"rules": [
{
"value": 0.295,
"color": "rgb(200,60,60)",
"label": "99.9th percentile"
}
]
}
}
}
}'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": "GWASTrack",
"trackId": "dog10k_size_fst",
"name": "Fst, toy/small vs giant breeds (200 kb windows)",
"assemblyNames": ["UU_Cfam_GSD_1.0"],
"adapter": {
"type": "GWASAdapter",
"uri": "dog10k_size_fst.bed.gz",
"columnNames": ["chrom", "chromStart", "chromEnd", "name", "fst", "sites"],
"scoreColumn": "fst"
},
"displayDefaults": {
"encoding": {
"y": {
"axis": { "title": "Hudson Fst" },
"rules": [
{
"value": 0.295,
"color": "rgb(200,60,60)",
"label": "99.9th percentile"
}
]
}
}
}
}dog10k_size_fst.bed.gz is relative to a config.json. Replace it with its URL or its path on this computer.
Opening the assembly with no location shows all of its regions at once, so the
display lays the autosomes out side by side. The red line is a rule on
encoding.y, the y scale; Y axis... → Reference lines adds one to a track
already open.
Rerunning the same script over one region rebins it, which is the lower half of
the figure below: the same panel and the same estimator at 20 kb over two
megabases, where the peak resolves into a sweep. WINDOW is the bin width,
REGIONS any bcftools -r target, and OUTBED the output name:
curl -fO https://raw.githubusercontent.com/GMOD/jbrowse-components/main/scripts/build_dog10k_size_fst.sh
WINDOW=20000 REGIONS=chr15:40600000-42600000 \
OUTBED=dog10k_size_fst_igf1_20kb.bed \
bash build_dog10k_size_fst.shFst has no p-value, so the cutoff is a reference line at the 99.9th percentile of the scan's windows, which the build script prints beside the ranked windows.1 The percentile depends on the window size, so a rebinned scan needs a new one. The tallest labelled peak, on chr10, is HMGA2, one of the six variants Rimbault et al. 2013 fit to about half the size variation across breeds.
Slicing the IGF1 window out of the SNV callset
Small breeds share a haplotype at IGF1 that large breeds largely lack
(Sutter et al. 2007). The samples are
the two groups the scan compared plus the Greek gray wolves, taken from the
Dog10K sample table by breed name. They include whole breeds, because several
breeds depart from the pattern one animal at a time and the clustering below has
to show that variation. The SNV callset is a single large VCF over every
sequenced canid with a tabix index beside it, and bcftools reads only the
window:
SNVS=https://kiddlabshare.med.umich.edu/dog10K/SNP_and_indel_calls_2021-10-17/AutoAndXPAR.SNPs.vqsr99.vcf.gz
# --force-samples: proceed even if a name in igf1.samples isn't in the VCF's
# sample list, instead of exiting
# -f PASS: keep only sites that passed every quality filter
# -q 0.05:minor (second pass): drop sites where the minor allele is under 5%
# frequency in these samples, since most sites in a callset this size are rare
bcftools view -r chr15:41350000-41750000 -S igf1.samples --force-samples \
-f PASS "$SNVS" \
| bcftools view -q 0.05:minor -Oz -o dog10k_igf1.vcf.gz
tabix -p vcf dog10k_igf1.vcf.gzA site that is reference in every animal draws an empty column, so the second
bcftools view drops it.
Loading the IGF1 slice with a sample-metadata TSV
The display draws one row per sample. For this many samples, point the adapter at a TSV whose first column is the sample name and whose other columns are attributes; the display colors and orders rows by any of them:
name breed size
CHIH000005 Chihuahua Toy/small
STBD000001 Saint Bernard Giant
CLUPGR000001 Greek gray wolf Gray wolfrows.color is a color scale on each row's label bar, and here it names the
column that paints the swatch:
Goes in the tracks array of config.json. See Tracks.
{
"type": "VariantTrack",
"trackId": "dog10k_igf1_haplotype",
"name": "Dog10K SNVs across IGF1 (toy, giant, wolf)",
"assemblyNames": ["UU_Cfam_GSD_1.0"],
"adapter": {
"type": "VcfTabixAdapter",
"uri": "dog10k_igf1.vcf.gz",
"samplesTsvLocation": { "uri": "dog10k_igf1_samples.tsv" }
},
"displays": [
{
"type": "LinearVariantDisplay",
"rows": { "color": "size" },
"height": 760
}
]
}jbrowse add-track-json '{
"type": "VariantTrack",
"trackId": "dog10k_igf1_haplotype",
"name": "Dog10K SNVs across IGF1 (toy, giant, wolf)",
"assemblyNames": ["UU_Cfam_GSD_1.0"],
"adapter": {
"type": "VcfTabixAdapter",
"uri": "dog10k_igf1.vcf.gz",
"samplesTsvLocation": { "uri": "dog10k_igf1_samples.tsv" }
},
"displays": [
{
"type": "LinearVariantDisplay",
"rows": { "color": "size" },
"height": 760
}
]
}'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": "VariantTrack",
"trackId": "dog10k_igf1_haplotype",
"name": "Dog10K SNVs across IGF1 (toy, giant, wolf)",
"assemblyNames": ["UU_Cfam_GSD_1.0"],
"adapter": {
"type": "VcfTabixAdapter",
"uri": "dog10k_igf1.vcf.gz",
"samplesTsvLocation": { "uri": "dog10k_igf1_samples.tsv" }
},
"displays": [
{
"type": "LinearVariantDisplay",
"rows": { "color": "size" },
"height": 760
}
]
}dog10k_igf1.vcf.gz, dog10k_igf1_samples.tsv are relative to a config.json. Replace each with its URL or its path on this computer.
Clustering the IGF1 rows by genotype
The build script prints which sites separate the two size classes. Frame the
view on that span with a margin of undifferentiated sequence on each side, as
chr15:41,348,000-41,752,000 does, so Fst drops back to near zero at both
edges.
Rows arrive in the VCF's order, which is the order the sample list was built in, so they start out grouped by breed. Clustering reads the region on screen, and over the whole window the undifferentiated sites dilute the separating columns, so we cluster the core first:
- Zoom to the core,
chr15:41,440,000-41,580,000. - Choose Clustering → Cluster rows by genotype... in the track menu, then Run clustering. The rows reorder by genotype similarity and a dendrogram appears in the sidebar.
- Widen back out to see how far the block runs.
The display applies the size-class color from the sample table after clustering,
so the order comes from genotypes alone. A session can set the region directly
with clusterRegion beside runClustering, as the figure below does:
Goes at the top level of config.json, replacing any defaultSession there. See Default session.
{
"defaultSession": {
"name": "IGF1 haplotypes",
"views": [
{
"id": "igf1_lgv",
"type": "LinearGenomeView",
"assembly": "UU_Cfam_GSD_1.0",
"loc": "chr15:41,348,000-41,752,000",
"tracks": [
{
"type": "VariantTrack",
"configuration": "dog10k_igf1_haplotype",
"displays": [
{
"type": "LinearVariantDisplay",
"configuration": "dog10k_igf1_haplotype-LinearVariantDisplay",
"runClustering": true,
"clusterRegion": "chr15:41,440,000-41,580,000"
}
]
}
]
}
]
}
}jbrowse set-default-session --session - << 'EOF'
{
"name": "IGF1 haplotypes",
"views": [
{
"id": "igf1_lgv",
"type": "LinearGenomeView",
"assembly": "UU_Cfam_GSD_1.0",
"loc": "chr15:41,348,000-41,752,000",
"tracks": [
{
"type": "VariantTrack",
"configuration": "dog10k_igf1_haplotype",
"displays": [
{
"type": "LinearVariantDisplay",
"configuration": "dog10k_igf1_haplotype-LinearVariantDisplay",
"runClustering": true,
"clusterRegion": "chr15:41,440,000-41,580,000"
}
]
}
]
}
]
}
EOFThe IGF1 haplotype block in toy, giant and wolf genotypes
The build script also scores Fst one site at a time over the slice, with the
scan's estimator and size classes, and writes it as dog10k_igf1_fst.bed.gz. It
loads like the genome scan, as a GWASTrack whose GWASAdapter takes
scoreColumn fst and columnNames chrom, chromStart, chromEnd, name,
fst, freqToySmall, freqGiant.
Open chr15:41,348,000-41,752,000 with that Fst track above the clustered
variant track:
Reading the matrix against the Fst track above it:
- Clustering on genotypes alone recovers the size split. Both ends of the block fall inside the window, and the block is a run of columns where one class is enriched, since the classes differ by a shift in allele frequency.
- The Fst track has one point per matrix column. The matrix gives each record equal width and the Fst track keeps genomic spacing, so sloped lines tie each column to its coordinate.
- Rows depart from their size-class color in both directions: single orange rows sit within the giant cluster and single blue rows within the small one.
- The wolves form a contiguous band directly below the toy and small block, and have part of its haplotype.
Scanning for peaks in another trait
The Fst scan and the IGF1 slice take the same two inputs, a pair of groups and a region, so any trait the sample table records can substitute. To scan another trait:
- Edit the
SMALLandGIANTbreed lists in the script's panel step and rerun it to find new peaks. - Change
REGIONSto a peak and slice that window with thebcftoolscommand above. - Add a column to the samples TSV to color by.
Schall and Kidd (2025) list structural variants whose frequencies track breed clades, and those slice from their SV callsets the same way.
Reproduce it end to end
Two scripts, in order:
build_dog10k_size_fst.shruns the scan. It corrects each class's allele frequency for that class's sample size, so the unequal classes do not tilt the score, skips windows with too few sites to score, and prints the percentiles behind the reference line.build_dog10k_igf1.shslices the IGF1 window for those samples and scores each site with the scan's estimator.
The two scripts take their breed groups from the Dog10K sample table by breed name, so a sample's class never depends on its genotype.
BASE=https://raw.githubusercontent.com/GMOD/jbrowse-components/main/scripts
curl -fO $BASE/build_dog10k_size_fst.sh
curl -fO $BASE/build_dog10k_igf1.sh
bash build_dog10k_size_fst.sh # writes ./dog10k_size_fst_build/
bash build_dog10k_igf1.sh # writes ./dog10k_igf1_build/See also
- Tutorial: A loss-of-function allele across breeds (Dog10K)
- Tutorial: Structural variants (Dog10K)
- Tutorial: Local ancestry (Dog10K)
- Tutorial: Selection scans (Drosophila DGRP)
- Tutorial: QTL mapping (BXD mice)
- User guide: Variant sample rows
- User guide: GWAS / Manhattan track
- Config guide: Variant track
Citations
- Bhatia et al. (2013). Estimating and interpreting FST: the impact of rare variants
- Hudson et al. (1992). Estimation of levels of gene flow from DNA sequence data
- Rimbault et al. (2013). Derived variants at six genes explain nearly half of size reduction in dog breeds
- Schall & Kidd (2025). Integrative genotyping and analysis of canine structural variation using long-read and short-read data
- Sutter et al. (2007). A single IGF1 allele is a major determinant of small size in dogs
- Meadows et al. (2023). Genome sequencing of 2000 canids by the Dog10K consortium advances the understanding of demography, genome function and architecture
Notes
-
Breeds are closed populations, so drift (random change in allele frequency) inside one large breed raises Fst just as differentiation between the groups does. Pooling many breeds on each side dilutes drift in any one breed. ↩
Feedback on this tutorial is welcome: contact us.