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.13. Desktop beta builds are coming soon.
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. In the Dog10K collection of sequenced dogs and wolves, we:
- scan every window of the genome for Fst, a 0-to-1 measure of how far apart two groups' allele frequencies sit, between fourteen toy breeds and eleven giant breeds, and draw it as a Manhattan track
- slice the IGF1 peak out of the 397 GB SNV callset over HTTP and load it as a multi-sample variant track with a sample-metadata TSV
- cluster the animals by genotype to see 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)
On Debian/Ubuntu, apt install bcftools tabix curl python3 covers it; the
packaged bcftools is linked against libcurl, so it can read the remote
callset. The scripts write local files, which
JBrowse Desktop opens by path and JBrowse Web takes
through Add track.
Where the data comes from
The Dog10K consortium's public share (Meadows et al. 2023), read directly over HTTP with no local copy of either callset.
The build script takes these files from their URLs, so there is nothing to download by hand.
- the phased imputation panel, scored window by window for the Fst scan: kiddlabshare.med.umich.edu/…/AutoAndXPAR.Dog10K.phased.bcfhttps://kiddlabshare.med.umich.edu/dog10K/phased-imputation-panel/AutoAndXPAR.Dog10K.phased.bcf
- the SNV/indel callset the IGF1 window is sliced from: kiddlabshare.med.umich.edu/…/AutoAndXPAR.SNPs.vqsr99.vcf.gzhttps://kiddlabshare.med.umich.edu/dog10K/SNP_and_indel_calls_2021-10-17/AutoAndXPAR.SNPs.vqsr99.vcf.gz
- the sample table, which the scripts derive the breed groups and the wolf outgroup from: kiddlabshare.med.umich.edu/…/dog10K-alignment-sample-table.2022-02-23-v7.txthttps://kiddlabshare.med.umich.edu/dog10K/sample-information/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.txtScanning 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 fourteen toy or small breeds against every animal of eleven 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": {
"scales": {
"y": {
"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": {
"scales": {
"y": {
"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": {
"scales": {
"y": {
"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
scales.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 twelve 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 397 GB VCF over
1,987 canids 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 all 167 animals 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 wolfrowColor 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": "LinearMultiSampleVariantDisplay",
"rowColor": "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": "LinearMultiSampleVariantDisplay",
"rowColor": "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": "LinearMultiSampleVariantDisplay",
"rowColor": "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.
Framing IGF1 on the sites that separate toy from giant
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 in the session below does, so Fst drops back to
near zero at both edges of the figure further down.
Clustering the IGF1 rows by genotype
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 140 kb 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": "LinearMultiSampleVariantDisplay",
"configuration": "dog10k_igf1_haplotype-LinearMultiSampleVariantDisplay",
"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": "LinearMultiSampleVariantDisplay",
"configuration": "dog10k_igf1_haplotype-LinearMultiSampleVariantDisplay",
"runClustering": true,
"clusterRegion": "chr15:41,440,000-41,580,000"
}
]
}
]
}
]
}
EOFThe IGF1 haplotype block in toy, giant and wolf genotypes
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 is the same Hudson Fst as the genome scan, between the same two size classes, computed one site at a time over this VCF, with 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 of their own directly below the toy and small block, and carry part of its haplotype.
The build script writes the Fst track 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.
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 associated with breed clades.
Reproduce it end to end
Two scripts, in order:
build_dog10k_size_fst.shruns the scan. It corrects each class's allele frequency for its own 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.
Both take their breed groups from the Dog10K sample table by breed name, so genotype plays no part in who sits in which class.
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: Multi-sample variant display
- 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 fourteen breeds against eleven dilutes drift in any one breed. ↩
Feedback on this tutorial is welcome: contact us.