A grammar of graphics over a BED (RepeatMasker Alu age)
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.21. Desktop beta builds for Linux and
macOS are on the releases page;
the Windows build waits on code signing.
RepeatMasker annotates Alu, a primate-specific repeat family, and its milliDiv
column records each copy's divergence from its subfamily consensus, in tenths of
a percent. Divergence grows with time, so the column is an age, and the
subfamily name (AluJ, AluS, AluY, oldest to youngest) is a coarser one. We ask
where along chromosome 1 the young copies sit. We:
- load the Alu rows of a RepeatMasker BED as a
LinearMarkDisplay, one bar per copy withmilliDivas its height and its lineage as its color - bin and count the copies per window when zoomed out, with AluY's count over the total
- count copies per kilobase over a whole chromosome into a bigWig with
jbrowse make-density - plot the AluY share per megabase as a two-color bar track under that density
LinearMarkDisplay turns the columns of a feature file into plots from a JSON
marks list. It is experimental, and its config shape may change.
Prerequisites
- a JBrowse to open the figures' sessions in (Web or Desktop)
- htslib (
bgzip,tabix) - Node.js and the JBrowse CLI, for
jbrowse make-density python3, standard library only, for the per-megabase countsbedGraphToBigWigfrom the UCSC utilities, whichmake-densityruns
# Debian/Ubuntu
sudo apt install tabix nodejs samtools
# or conda, which has every tool above
conda install -c bioconda -c conda-forge htslib nodejs ucsc-bedgraphtobigwig \
samtools
# or Linux x86_64 binaries for the tools apt lacks
wget -P ~/.local/bin \
https://hgdownload.soe.ucsc.edu/admin/exe/linux.x86_64/bedGraphToBigWig
chmod +x ~/.local/bin/bedGraphToBigWig
# any platform
npm install -g @jbrowse/cli@nextThe data
UCSC's hg38 RepeatMasker table, rehosted by genomes.jbrowse.org's hg38 with the Alu rows cut out.
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 build script takes your own RepeatMasker BED and genome FASTA as arguments and runs the same steps on them.
| What it is | File |
|---|---|
RepeatMasker, UCSC's rmsk table as BED with a column header |
rmsk.bed.gz |
| Reference lengths, for the bigWig header | hg38.chrom.sizes |
Plotting each Alu copy's divergence at one locus
We'll load hg38, the assembly the RepeatMasker coordinates are on.
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"
}Edits config.json in the current folder, creating it if there is none. See JBrowse CLI with Desktop.
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 Browse hosted genomes and pick it. To load the files of this config instead:
In JBrowse Desktop, Open your own 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
The track reads one family's rows of a RepeatMasker BED. For a genome of your
own, RepeatMasker's .out file lists class and family as one class/family
field, and splitting it under a header that names the columns gives a BED with
the same columns:
# the header names the columns, so a track or an awk filter can name repFamily
{
printf '#genoName\tgenoStart\tgenoEnd\tname\tstrand\trepFamily\trepClass\tswScore\tmilliDiv\n'
awk 'BEGIN { OFS = "\t" }
# a data row is the one starting with a bare integer, its SW score
$1 ~ /^[0-9]+$/ {
# "LINE/L1" splits; "Simple_repeat" does not, and UCSC repeats the class
# as the family for exactly those rows. Positions are 1-based inclusive
# and the strand column spells minus "C".
n = split($11, cf, "/")
print $5, $6 - 1, $7, $10, ($9 == "C") ? "-" : "+", (n > 1) ? cf[2] : cf[1], cf[1], $1, int($2 * 10 + 0.5)
}' repeats.out
} > rmsk.bed
# `sort-bed` is `sort -k1,1 -k2,2n` under LC_ALL=C, header kept on top
jbrowse sort-bed rmsk.bed | bgzip > rmsk.bed.gz
tabix -f -C -p bed rmsk.bed.gzAn awk filter on the repFamily column keeps the header line and the sort
order, so tabix indexes the cut file as it is:
# the header line names the columns, repFamily the sixth
gzip -dc rmsk.bed.gz | awk -F'\t' -v fam=Alu '/^#/ || $6 == fam' | bgzip > Alu.bed.gz
tabix -f -C -p bed Alu.bed.gzThe track reads any BED-like file, bgzipped and CSI-indexed, with a # header
line naming the columns, and a mark refers to a column by name. In
grammar-of-graphics terms, encoding maps
columns to a mark's channels, and color is a color scale from a field
through scale.domain to scale.range. The track below lists three marks:
- Per-copy bars (below
maxBpPerPx): abarper copy withmilliDivas the height. Aformulastep writes the first four characters of the name intolineage, and the ordinalscale.domainfixes the legend order - Copies per bin (past
minBpPerPx): every Alu copy counted per bin, in grey - AluY per bin: the same count behind a
filterfor AluY, in red
Goes in the tracks array of config.json. See Tracks.
{
"type": "FeatureTrack",
"trackId": "alu_age",
"name": "Alu copies",
"assemblyNames": ["hg38"],
"adapter": {
"type": "BedTabixAdapter",
"uri": "https://jbrowse.org/demos/gene_density/Alu.bed.gz",
"csi": true
},
"displays": [
{
"type": "LinearMarkDisplay",
"marks": [
{
"mark": "bar",
"transform": [
{
"type": "formula",
"expr": "jexl:substring(feature.name, 0, 4)",
"as": "lineage"
}
],
"encoding": {
"y": "milliDiv",
"color": {
"field": "lineage",
"scale": {
"type": "ordinal",
"domain": ["AluJ", "AluS", "AluY", "FLAM", "FRAM"],
"range": ["#4575b4", "#fdae61", "#d73027", "#8c8c8c", "#8c8c8c"]
},
"legend": { "title": "Alu lineage" }
}
},
"maxBpPerPx": 100
},
{
"mark": "bar",
"transform": [
{ "type": "bin", "step": "auto" },
{
"type": "aggregate",
"groupby": ["start", "end"],
"ops": [{ "op": "count" }]
}
],
"encoding": { "color": { "value": "#c0c0c0" } },
"minBpPerPx": 100
},
{
"mark": "bar",
"transform": [
{
"type": "filter",
"expr": "jexl:startsWith(feature.name, 'AluY')"
},
{ "type": "bin", "step": "auto" },
{
"type": "aggregate",
"groupby": ["start", "end"],
"ops": [{ "op": "count" }]
}
],
"encoding": { "color": { "value": "#d73027" } },
"minBpPerPx": 100
}
]
}
]
}Edits config.json in the current folder. See JBrowse CLI with Desktop.
jbrowse add-track-json '{
"type": "FeatureTrack",
"trackId": "alu_age",
"name": "Alu copies",
"assemblyNames": ["hg38"],
"adapter": {
"type": "BedTabixAdapter",
"uri": "https://jbrowse.org/demos/gene_density/Alu.bed.gz",
"csi": true
},
"displays": [
{
"type": "LinearMarkDisplay",
"marks": [
{
"mark": "bar",
"transform": [
{
"type": "formula",
"expr": "jexl:substring(feature.name, 0, 4)",
"as": "lineage"
}
],
"encoding": {
"y": "milliDiv",
"color": {
"field": "lineage",
"scale": {
"type": "ordinal",
"domain": ["AluJ", "AluS", "AluY", "FLAM", "FRAM"],
"range": ["#4575b4", "#fdae61", "#d73027", "#8c8c8c", "#8c8c8c"]
},
"legend": { "title": "Alu lineage" }
}
},
"maxBpPerPx": 100
},
{
"mark": "bar",
"transform": [
{ "type": "bin", "step": "auto" },
{
"type": "aggregate",
"groupby": ["start", "end"],
"ops": [{ "op": "count" }]
}
],
"encoding": { "color": { "value": "#c0c0c0" } },
"minBpPerPx": 100
},
{
"mark": "bar",
"transform": [
{
"type": "filter",
"expr": "jexl:startsWith(feature.name, '\''AluY'\'')"
},
{ "type": "bin", "step": "auto" },
{
"type": "aggregate",
"groupby": ["start", "end"],
"ops": [{ "op": "count" }]
}
],
"encoding": { "color": { "value": "#d73027" } },
"minBpPerPx": 100
}
]
}
]
}'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": "alu_age",
"name": "Alu copies",
"assemblyNames": ["hg38"],
"adapter": {
"type": "BedTabixAdapter",
"uri": "https://jbrowse.org/demos/gene_density/Alu.bed.gz",
"csi": true
},
"displays": [
{
"type": "LinearMarkDisplay",
"marks": [
{
"mark": "bar",
"transform": [
{
"type": "formula",
"expr": "jexl:substring(feature.name, 0, 4)",
"as": "lineage"
}
],
"encoding": {
"y": "milliDiv",
"color": {
"field": "lineage",
"scale": {
"type": "ordinal",
"domain": ["AluJ", "AluS", "AluY", "FLAM", "FRAM"],
"range": ["#4575b4", "#fdae61", "#d73027", "#8c8c8c", "#8c8c8c"]
},
"legend": { "title": "Alu lineage" }
}
},
"maxBpPerPx": 100
},
{
"mark": "bar",
"transform": [
{ "type": "bin", "step": "auto" },
{
"type": "aggregate",
"groupby": ["start", "end"],
"ops": [{ "op": "count" }]
}
],
"encoding": { "color": { "value": "#c0c0c0" } },
"minBpPerPx": 100
},
{
"mark": "bar",
"transform": [
{
"type": "filter",
"expr": "jexl:startsWith(feature.name, 'AluY')"
},
{ "type": "bin", "step": "auto" },
{
"type": "aggregate",
"groupby": ["start", "end"],
"ops": [{ "op": "count" }]
}
],
"encoding": { "color": { "value": "#d73027" } },
"minBpPerPx": 100
}
]
}
]
}Open this track in JBrowse Web ↗
Needs JBrowse Desktop 5.0 or newer. If nothing opens, copy the link and paste it into Desktop's Open JBrowse Web link..., on the start screen or under File → Session.
https://jbrowse.org/code/jb2/main/?config=https%3A%2F%2Fjbrowse.org%2Fucsc%2Fhg38%2Fconfig.json&session=spec-%7B%22sessionTracks%22%3A%5B%7B%22type%22%3A%22FeatureTrack%22%2C%22trackId%22%3A%22alu_age%22%2C%22name%22%3A%22Alu+copies%22%2C%22assemblyNames%22%3A%5B%22hg38%22%5D%2C%22adapter%22%3A%7B%22type%22%3A%22BedTabixAdapter%22%2C%22uri%22%3A%22https%3A%2F%2Fjbrowse.org%2Fdemos%2Fgene_density%2FAlu.bed.gz%22%2C%22csi%22%3Atrue%7D%2C%22displays%22%3A%5B%7B%22type%22%3A%22LinearMarkDisplay%22%2C%22marks%22%3A%5B%7B%22mark%22%3A%22bar%22%2C%22transform%22%3A%5B%7B%22type%22%3A%22formula%22%2C%22expr%22%3A%22jexl%3Asubstring%28feature.name%2C+0%2C+4%29%22%2C%22as%22%3A%22lineage%22%7D%5D%2C%22encoding%22%3A%7B%22y%22%3A%22milliDiv%22%2C%22color%22%3A%7B%22field%22%3A%22lineage%22%2C%22scale%22%3A%7B%22type%22%3A%22ordinal%22%2C%22domain%22%3A%5B%22AluJ%22%2C%22AluS%22%2C%22AluY%22%2C%22FLAM%22%2C%22FRAM%22%5D%2C%22range%22%3A%5B%22%234575b4%22%2C%22%23fdae61%22%2C%22%23d73027%22%2C%22%238c8c8c%22%2C%22%238c8c8c%22%5D%7D%2C%22legend%22%3A%7B%22title%22%3A%22Alu+lineage%22%7D%7D%7D%2C%22maxBpPerPx%22%3A100%7D%2C%7B%22mark%22%3A%22bar%22%2C%22transform%22%3A%5B%7B%22type%22%3A%22bin%22%2C%22step%22%3A%22auto%22%7D%2C%7B%22type%22%3A%22aggregate%22%2C%22groupby%22%3A%5B%22start%22%2C%22end%22%5D%2C%22ops%22%3A%5B%7B%22op%22%3A%22count%22%7D%5D%7D%5D%2C%22encoding%22%3A%7B%22color%22%3A%7B%22value%22%3A%22%23c0c0c0%22%7D%7D%2C%22minBpPerPx%22%3A100%7D%2C%7B%22mark%22%3A%22bar%22%2C%22transform%22%3A%5B%7B%22type%22%3A%22filter%22%2C%22expr%22%3A%22jexl%3AstartsWith%28feature.name%2C+%27AluY%27%29%22%7D%2C%7B%22type%22%3A%22bin%22%2C%22step%22%3A%22auto%22%7D%2C%7B%22type%22%3A%22aggregate%22%2C%22groupby%22%3A%5B%22start%22%2C%22end%22%5D%2C%22ops%22%3A%5B%7B%22op%22%3A%22count%22%7D%5D%7D%5D%2C%22encoding%22%3A%7B%22color%22%3A%7B%22value%22%3A%22%23d73027%22%7D%7D%2C%22minBpPerPx%22%3A100%7D%5D%7D%5D%7D%5D%2C%22views%22%3A%5B%7B%22type%22%3A%22LinearGenomeView%22%2C%22assembly%22%3A%22hg38%22%2C%22loc%22%3A%22chr1%3A151%2C000%2C000-151%2C030%2C000%22%2C%22tracks%22%3A%5B%22alu_age%22%5D%7D%5D%7D&sessionName=JBrowse+docs%3A+Alu+copiesThis view in a notebook, with jbrowse-anywidget. Swap a track's uri for your file.
from jbrowse_anywidget import JBrowseApp, fetch_hub
config = fetch_hub("https://jbrowse.org/ucsc/hg38/config.json")
app = JBrowseApp(
assemblies=config["assemblies"],
tracks=config.get("tracks", []) + [
{
"type": "FeatureTrack",
"trackId": "alu_age",
"name": "Alu copies",
"assemblyNames": [
"hg38"
],
"adapter": {
"type": "BedTabixAdapter",
"uri": "https://jbrowse.org/demos/gene_density/Alu.bed.gz",
"csi": True
},
"displays": [
{
"type": "LinearMarkDisplay",
"marks": [
{
"mark": "bar",
"transform": [
{
"type": "formula",
"expr": "jexl:substring(feature.name, 0, 4)",
"as": "lineage"
}
],
"encoding": {
"y": "milliDiv",
"color": {
"field": "lineage",
"scale": {
"type": "ordinal",
"domain": [
"AluJ",
"AluS",
"AluY",
"FLAM",
"FRAM"
],
"range": [
"#4575b4",
"#fdae61",
"#d73027",
"#8c8c8c",
"#8c8c8c"
]
},
"legend": {
"title": "Alu lineage"
}
}
},
"maxBpPerPx": 100
},
{
"mark": "bar",
"transform": [
{
"type": "bin",
"step": "auto"
},
{
"type": "aggregate",
"groupby": [
"start",
"end"
],
"ops": [
{
"op": "count"
}
]
}
],
"encoding": {
"color": {
"value": "#c0c0c0"
}
},
"minBpPerPx": 100
},
{
"mark": "bar",
"transform": [
{
"type": "filter",
"expr": "jexl:startsWith(feature.name, 'AluY')"
},
{
"type": "bin",
"step": "auto"
},
{
"type": "aggregate",
"groupby": [
"start",
"end"
],
"ops": [
{
"op": "count"
}
]
}
],
"encoding": {
"color": {
"value": "#d73027"
}
},
"minBpPerPx": 100
}
]
}
]
}
],
views=[
{
"type": "LinearGenomeView",
"assembly": "hg38",
"loc": "chr1:151,000,000-151,030,000",
"tracks": [
"alu_age"
]
}
],
)
app # display the widgetThis view in your React 19 app, with @jbrowse/react-app2 and @jbrowse/core. Add your own files to tracks.
import { use } from 'react'
import { JBrowse } from '@jbrowse/react-app2'
import '@jbrowse/react-app2/styles.css'
import { addRelativeUris } from '@jbrowse/core/util/addRelativeUris'
const configUrl = "https://jbrowse.org/ucsc/hg38/config.json"
const configPromise = fetch(configUrl)
.then(res => res.json())
.then(config => {
addRelativeUris(config, new URL(configUrl))
return config
})
export default function Figure() {
const config = use(configPromise)
return (
<JBrowse
assemblies={config.assemblies}
tracks={[...(config.tracks ?? []), ...[
{
"type": "FeatureTrack",
"trackId": "alu_age",
"name": "Alu copies",
"assemblyNames": [
"hg38"
],
"adapter": {
"type": "BedTabixAdapter",
"uri": "https://jbrowse.org/demos/gene_density/Alu.bed.gz",
"csi": true
},
"displays": [
{
"type": "LinearMarkDisplay",
"marks": [
{
"mark": "bar",
"transform": [
{
"type": "formula",
"expr": "jexl:substring(feature.name, 0, 4)",
"as": "lineage"
}
],
"encoding": {
"y": "milliDiv",
"color": {
"field": "lineage",
"scale": {
"type": "ordinal",
"domain": [
"AluJ",
"AluS",
"AluY",
"FLAM",
"FRAM"
],
"range": [
"#4575b4",
"#fdae61",
"#d73027",
"#8c8c8c",
"#8c8c8c"
]
},
"legend": {
"title": "Alu lineage"
}
}
},
"maxBpPerPx": 100
},
{
"mark": "bar",
"transform": [
{
"type": "bin",
"step": "auto"
},
{
"type": "aggregate",
"groupby": [
"start",
"end"
],
"ops": [
{
"op": "count"
}
]
}
],
"encoding": {
"color": {
"value": "#c0c0c0"
}
},
"minBpPerPx": 100
},
{
"mark": "bar",
"transform": [
{
"type": "filter",
"expr": "jexl:startsWith(feature.name, 'AluY')"
},
{
"type": "bin",
"step": "auto"
},
{
"type": "aggregate",
"groupby": [
"start",
"end"
],
"ops": [
{
"op": "count"
}
]
}
],
"encoding": {
"color": {
"value": "#d73027"
}
},
"minBpPerPx": 100
}
]
}
]
}
]]}
aggregateTextSearchAdapters={config.aggregateTextSearchAdapters}
configuration={config.configuration}
views={[
{
"type": "LinearGenomeView",
"assembly": "hg38",
"loc": "chr1:151,000,000-151,030,000",
"tracks": [
"alu_age"
]
}
]}
/>
)
}jbrowse-img draws this view as an SVG, no browser needed. Swap --config or a track for your own.
cat > tracks.json <<'JSON'
[
{
"type": "FeatureTrack",
"trackId": "alu_age",
"name": "Alu copies",
"assemblyNames": [
"hg38"
],
"adapter": {
"type": "BedTabixAdapter",
"uri": "https://jbrowse.org/demos/gene_density/Alu.bed.gz",
"csi": true
},
"displays": [
{
"type": "LinearMarkDisplay",
"marks": [
{
"mark": "bar",
"transform": [
{
"type": "formula",
"expr": "jexl:substring(feature.name, 0, 4)",
"as": "lineage"
}
],
"encoding": {
"y": "milliDiv",
"color": {
"field": "lineage",
"scale": {
"type": "ordinal",
"domain": [
"AluJ",
"AluS",
"AluY",
"FLAM",
"FRAM"
],
"range": [
"#4575b4",
"#fdae61",
"#d73027",
"#8c8c8c",
"#8c8c8c"
]
},
"legend": {
"title": "Alu lineage"
}
}
},
"maxBpPerPx": 100
},
{
"mark": "bar",
"transform": [
{
"type": "bin",
"step": "auto"
},
{
"type": "aggregate",
"groupby": [
"start",
"end"
],
"ops": [
{
"op": "count"
}
]
}
],
"encoding": {
"color": {
"value": "#c0c0c0"
}
},
"minBpPerPx": 100
},
{
"mark": "bar",
"transform": [
{
"type": "filter",
"expr": "jexl:startsWith(feature.name, 'AluY')"
},
{
"type": "bin",
"step": "auto"
},
{
"type": "aggregate",
"groupby": [
"start",
"end"
],
"ops": [
{
"op": "count"
}
]
}
],
"encoding": {
"color": {
"value": "#d73027"
}
},
"minBpPerPx": 100
}
]
}
]
}
]
JSON
npx @jbrowse/img --config https://jbrowse.org/ucsc/hg38/config.json \
--trackConfigs tracks.json \
--assembly hg38 --loc chr1:151,000,000-151,030,000 \
--track alu_age \
--out figure.svgFor a PNG, --out figure.png (needs rsvg-convert: apt install librsvg2-bin, brew install librsvg).
Open chr1:151,000,000-151,030,000, 30 kb of 1q21, and click a bar to open its
row of the BED.
Counting Alu copies per bin when zoomed out
Zoomed out past minBpPerPx, the track switches to the two binned marks. On a
whole chromosome it exceeds its fetch budget and shows a "region too large"
message, so a bigWig of copies per kilobase, counted once from the BED, covers
that width:
# writes Alu.bed.density.bw beside the input, in 1 kb bins
# --chrom-sizes takes a two-column name and length table;
# --assembly genome.fa reads the lengths off the FASTA's .fai instead
jbrowse make-density Alu.bed.gz --chrom-sizes hg38.chrom.sizesAdd the bigWig as a track:
Goes in the tracks array of config.json. See Tracks.
{
"trackId": "alu_per_kb",
"name": "Alu copies per kb",
"assemblyNames": ["hg38"],
"uri": "https://jbrowse.org/demos/gene_density/Alu.bed.density.bw",
"displayDefaults": { "mark": { "extent": "none" } }
}Edits config.json in the current folder. See JBrowse CLI with Desktop.
jbrowse add-track https://jbrowse.org/demos/gene_density/Alu.bed.density.bw \
--trackId alu_per_kb \
--name "Alu copies per kb" \
--assemblyNames hg38 \
--displayDefaults '{"mark":{"extent":"none"}}'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:
{
"trackId": "alu_per_kb",
"name": "Alu copies per kb",
"assemblyNames": ["hg38"],
"uri": "https://jbrowse.org/demos/gene_density/Alu.bed.density.bw",
"displayDefaults": { "mark": { "extent": "none" } }
}Open this track in JBrowse Web ↗
Needs JBrowse Desktop 5.0 or newer. If nothing opens, copy the link and paste it into Desktop's Open JBrowse Web link..., on the start screen or under File → Session.
https://jbrowse.org/code/jb2/main/?config=https%3A%2F%2Fjbrowse.org%2Fucsc%2Fhg38%2Fconfig.json&session=spec-%7B%22sessionTracks%22%3A%5B%7B%22trackId%22%3A%22alu_per_kb%22%2C%22name%22%3A%22Alu+copies+per+kb%22%2C%22assemblyNames%22%3A%5B%22hg38%22%5D%2C%22uri%22%3A%22https%3A%2F%2Fjbrowse.org%2Fdemos%2Fgene_density%2FAlu.bed.density.bw%22%2C%22displayDefaults%22%3A%7B%22mark%22%3A%7B%22extent%22%3A%22none%22%7D%7D%7D%5D%2C%22views%22%3A%5B%7B%22type%22%3A%22LinearGenomeView%22%2C%22assembly%22%3A%22hg38%22%2C%22loc%22%3A%22chr1%22%2C%22tracks%22%3A%5B%22alu_per_kb%22%5D%7D%5D%7D&sessionName=JBrowse+docs%3A+Alu+copies+per+kbThis view in a notebook, with jbrowse-anywidget. Swap a track's uri for your file.
from jbrowse_anywidget import JBrowseApp, fetch_hub
config = fetch_hub("https://jbrowse.org/ucsc/hg38/config.json")
app = JBrowseApp(
assemblies=config["assemblies"],
tracks=config.get("tracks", []) + [
{
"trackId": "alu_per_kb",
"name": "Alu copies per kb",
"assemblyNames": [
"hg38"
],
"uri": "https://jbrowse.org/demos/gene_density/Alu.bed.density.bw",
"displayDefaults": {
"mark": {
"extent": "none"
}
}
}
],
views=[
{
"type": "LinearGenomeView",
"assembly": "hg38",
"loc": "chr1",
"tracks": [
"alu_per_kb"
]
}
],
)
app # display the widgetThis view in your React 19 app, with @jbrowse/react-app2 and @jbrowse/core. Add your own files to tracks.
import { use } from 'react'
import { JBrowse } from '@jbrowse/react-app2'
import '@jbrowse/react-app2/styles.css'
import { addRelativeUris } from '@jbrowse/core/util/addRelativeUris'
const configUrl = "https://jbrowse.org/ucsc/hg38/config.json"
const configPromise = fetch(configUrl)
.then(res => res.json())
.then(config => {
addRelativeUris(config, new URL(configUrl))
return config
})
export default function Figure() {
const config = use(configPromise)
return (
<JBrowse
assemblies={config.assemblies}
tracks={[...(config.tracks ?? []), ...[
{
"trackId": "alu_per_kb",
"name": "Alu copies per kb",
"assemblyNames": [
"hg38"
],
"uri": "https://jbrowse.org/demos/gene_density/Alu.bed.density.bw",
"displayDefaults": {
"mark": {
"extent": "none"
}
}
}
]]}
aggregateTextSearchAdapters={config.aggregateTextSearchAdapters}
configuration={config.configuration}
views={[
{
"type": "LinearGenomeView",
"assembly": "hg38",
"loc": "chr1",
"tracks": [
"alu_per_kb"
]
}
]}
/>
)
}jbrowse-img draws this view as an SVG, no browser needed. Swap --config or a track for your own.
cat > tracks.json <<'JSON'
[
{
"trackId": "alu_per_kb",
"name": "Alu copies per kb",
"assemblyNames": [
"hg38"
],
"uri": "https://jbrowse.org/demos/gene_density/Alu.bed.density.bw",
"displayDefaults": {
"mark": {
"extent": "none"
}
}
}
]
JSON
npx @jbrowse/img --config https://jbrowse.org/ucsc/hg38/config.json \
--trackConfigs tracks.json \
--assembly hg38 --loc chr1 \
--track alu_per_kb \
--out figure.svgFor a PNG, --out figure.png (needs rsvg-convert: apt install librsvg2-bin, brew install librsvg).
AluY share per megabase, against the genome-wide share
The red AluY count is too small to read against a total that varies between bins. A script instead writes a BED with two log2 columns: the AluY share per megabase against the genome-wide share, and the plus-strand share against one half as a control that should show no pattern.
Fetch the script:
curl -fO https://raw.githubusercontent.com/GMOD/jbrowse-components/main/scripts/alu_young_share.py# columns: copies, young, plus, youngShare, youngLog2, strandLog2, one row per
# 1 Mb bin holding at least 50 copies; also prints the Spearman rank correlation
# of each share against copies per bin
python3 alu_young_share.py Alu.bed.gz Alu.young_share.bed AluY
bgzip -f Alu.young_share.bed
tabix -f -C -p bed Alu.young_share.bed.gzAdvanced → Edit plot... in the track menu applies edits to the cut, colors and key names live. The config below sets them in the track:
Goes in the tracks array of config.json. See Tracks.
{
"type": "FeatureTrack",
"trackId": "alu_young_share",
"name": "AluY share per Mb, against the genome",
"uri": "https://jbrowse.org/code/jb2/main/test_data/alu_age/Alu.young_share.bed.gz",
"csi": true,
"assemblyNames": ["hg38"],
"displays": [
{
"type": "LinearMarkDisplay",
"encoding": {
"y": {
"scale": { "domainMin": -1.5, "domainMax": 1.5 },
"axis": { "title": "AluY share, log2" }
}
},
"marks": [
{
"mark": "bar",
"encoding": {
"y": "youngLog2",
"color": {
"field": "youngLog2",
"scale": {
"type": "threshold",
"domain": [0],
"range": ["#4575b4", "#d73027"],
"names": ["below the genome-wide share", "above it"]
},
"legend": { "title": "AluY share" }
}
}
}
]
}
]
}Edits config.json in the current folder. See JBrowse CLI with Desktop.
jbrowse add-track-json '{
"type": "FeatureTrack",
"trackId": "alu_young_share",
"name": "AluY share per Mb, against the genome",
"uri": "https://jbrowse.org/code/jb2/main/test_data/alu_age/Alu.young_share.bed.gz",
"csi": true,
"assemblyNames": ["hg38"],
"displays": [
{
"type": "LinearMarkDisplay",
"encoding": {
"y": {
"scale": { "domainMin": -1.5, "domainMax": 1.5 },
"axis": { "title": "AluY share, log2" }
}
},
"marks": [
{
"mark": "bar",
"encoding": {
"y": "youngLog2",
"color": {
"field": "youngLog2",
"scale": {
"type": "threshold",
"domain": [0],
"range": ["#4575b4", "#d73027"],
"names": ["below the genome-wide share", "above it"]
},
"legend": { "title": "AluY share" }
}
}
}
]
}
]
}'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": "alu_young_share",
"name": "AluY share per Mb, against the genome",
"uri": "https://jbrowse.org/code/jb2/main/test_data/alu_age/Alu.young_share.bed.gz",
"csi": true,
"assemblyNames": ["hg38"],
"displays": [
{
"type": "LinearMarkDisplay",
"encoding": {
"y": {
"scale": { "domainMin": -1.5, "domainMax": 1.5 },
"axis": { "title": "AluY share, log2" }
}
},
"marks": [
{
"mark": "bar",
"encoding": {
"y": "youngLog2",
"color": {
"field": "youngLog2",
"scale": {
"type": "threshold",
"domain": [0],
"range": ["#4575b4", "#d73027"],
"names": ["below the genome-wide share", "above it"]
},
"legend": { "title": "AluY share" }
}
}
}
]
}
]
}Reproduce it end to end
build_alu_age.sh
runs every step above. It:
- fetches UCSC's hg38 RepeatMasker table and the reference lengths, or copies your own RepeatMasker BED and FASTA
- cuts out the Alu rows and indexes them
- counts the copies per kilobase into a bigWig, and per megabase into the AluY share BED
- writes a JBrowse with the copies, the bigWig and the share as tracks
curl -fO https://raw.githubusercontent.com/GMOD/jbrowse-components/main/scripts/build_alu_age.sh
bash build_alu_age.sh # builds ./alu_age_build/jbrowse2
npx --yes serve alu_age_build/jbrowse2 # then open the printed URLBy default the script builds the tracks over UCSC's table.
bash build_alu_age.sh rmsk.bed.gz genome.fa uses your own RepeatMasker BED,
and FAMILY and YOUNG pick another family and its youngest lineage.
See also
- Tutorial: Gene density and transposon density along a chromosome
- Tutorial: RepeatMasker as one row per class
- Tutorial: A grammar of graphics over a BAM (NA12878 insert size)
- Config guide: Mark display
- Docs: JBrowse web quick start
Citations
- Batzer and Deininger (2002). Alu repeats and human genomic diversity, the subfamily lineages and their ages.
- Lander et al. (2001). Initial sequencing and analysis of the human genome, where the distribution of young against old Alu copies along the genome was first described.
- Smit, Hubley and Green (2013-2015). RepeatMasker Open-4.0
Feedback on this tutorial is welcome: contact us.