Colors, labels & sizing
How a feature track looks: color and label per feature with jexl, what it does when rows overflow, and marking one feature.
Track color shorthand
Per-track appearance — color, height, display mode — belongs to a track’s
displays, the different ways a track can be drawn. Rather than writing out
the displays array, list the settings in a displayDefaults object and
JBrowse works out which display each one belongs to:
displayDefaults: { color: 'green' } on a FeatureTrack lands on that track’s
LinearBasicDisplay, with no need to name it.
A jexl: expression goes in the same slot for per-feature coloring. For full
control — two displays with different values, an explicit displayId, choosing
the default display — pass the displays array instead, per the
track config guide.
View source — 32 lines
import { LinearGenomeView } from '@jbrowse/react-linear-genome-view2'
// managed API: props are initial values, the component owns the engine — no
// createViewState / useState ceremony
export default function WithTrackColorShorthand() {
return (
<LinearGenomeView
assembly={{
name: 'volvox',
uri: 'https://jbrowse.org/genomes/volvox/volvox.2bit',
}}
tracks={[
{
type: 'FeatureTrack',
trackId: 'volvox_genes_green',
name: 'Volvox genes (green via shorthand)',
assemblyNames: ['volvox'],
adapter: {
type: 'Gff3TabixAdapter',
uri: 'https://jbrowse.org/code/jb2/main/test_data/volvox/volvox.sort.gff3.gz',
},
// list appearance settings in a `displayDefaults` object and JBrowse applies
// each one to the right display for you (here the track's LinearBasicDisplay)
// — no need to know display names or write the full `displays` array. A
// `jexl:` value works here too, e.g. "jexl:get(feature,'type')=='CDS'?'red':'blue'"
displayDefaults: { color: 'green' },
},
]}
init={{ loc: 'ctgA:1..50,000', tracks: ['volvox_genes_green'] }}
/>
)
}Jexl feature colors and labels
JBrowse evaluates a jexl: expression per feature with feature in scope, so
color and label can both come from the feature’s own attributes with no plugin
code. Here color reads strand and labels.name rewrites the displayed text:
displayDefaults: {
color: "jexl:get(feature,'strand')==1?'#1f77b4':'#d62728'",
labels: { name: "jexl:get(feature,'name')+' ['+get(feature,'type')+']'" },
}
These ride the same
displayDefaults shorthand,
landing on the track’s
LinearBasicDisplay.
The jexl callbacks guide has
the full function and variable vocabulary.
View source — 47 lines
import { LinearGenomeView } from '@jbrowse/react-linear-genome-view2'
// managed API: props are initial values, the component owns the engine — no
// createViewState / useState ceremony
export default function WithJexlFeatureColorsAndLabels() {
return (
<LinearGenomeView
assembly={{
name: 'volvox',
uri: 'https://jbrowse.org/genomes/volvox/volvox.2bit',
}}
tracks={[
{
type: 'FeatureTrack',
trackId: 'volvox_genes_jexl',
name: 'Volvox genes (jexl color + label)',
assemblyNames: ['volvox'],
adapter: {
type: 'Gff3TabixAdapter',
uri: 'https://jbrowse.org/code/jb2/main/test_data/volvox/volvox.sort.gff3.gz',
},
// `displayDefaults` shorthand routes each setting to the track's
// display. `color` and `labels.name` accept a `jexl:` expression
// evaluated per feature (`feature` is in scope) — here: color by
// strand, label with type.
displayDefaults: {
color: "jexl:get(feature,'strand')==1?'#1f77b4':'#d62728'",
labels: {
name: "jexl:get(feature,'name')+' ['+get(feature,'type')+']'",
},
},
// Equivalent explicit form (use when you need the display
// type/displayId):
// displays: [
// {
// type: 'LinearBasicDisplay',
// displayId: 'volvox_genes_jexl-LinearBasicDisplay',
// color: "jexl:get(feature,'strand')==1?'#1f77b4':'#d62728'",
// labels: { name: "jexl:get(feature,'name')+' ['+get(feature,'type')+']'" },
// },
// ],
},
]}
init={{ loc: 'ctgA:1..50,000', tracks: ['volvox_genes_jexl'] }}
/>
)
}Track sizing: grow & fit
The same crowded locus (TP53, where NCBI RefSeq stacks more isoforms than a
fixed height shows) opened twice, so the two modes sit side by side.
heightMode picks the strategy, and the track’s “Track sizing” menu switches it
at runtime:
fixed— keepheight, scroll for the overflow (the default)grow— grow tall enough to show every row at full sizefit— scale rows down until they all fit insideheight
It is a display slot, so it routes through
displayDefaults.
It sets the frame only; the per-feature size is displayMode, an independent
axis. Full options:
LinearBasicDisplay.
View source — 61 lines
import { LinearGenomeView } from '@jbrowse/react-linear-genome-view2'
// hg19 with the NCBI RefSeq gene track. The TP53 locus stacks its many
// transcript isoforms into far more rows than a fixed height can show, so the
// track-sizing strategy is visible at a glance.
const assembly = {
name: 'hg19',
aliases: ['GRCh37'],
uri: 'https://jbrowse.org/genomes/hg19/fasta/hg19.fa.gz',
refNameAliases: {
uri: 'https://s3.amazonaws.com/jbrowse.org/genomes/hg19/hg19_aliases.txt',
},
}
// The same GFF3, opened twice under different trackIds so the two track-sizing
// strategies sit side by side. `heightMode` is a display config slot, so it
// routes through the `displayDefaults` shorthand.
const adapter = {
type: 'Gff3TabixAdapter',
uri: 'https://jbrowse.org/ucsc/hg19/ncbiRefSeq.gff.gz',
csi: true,
}
const tracks = [
{
type: 'FeatureTrack',
trackId: 'refseq_grow',
name: 'NCBI RefSeq — grow (expand to fit all features)',
assemblyNames: ['hg19'],
adapter,
// grow: the track grows tall enough to show every stacked row at full size
displayDefaults: {
heightMode: 'grow',
},
},
{
type: 'FeatureTrack',
trackId: 'refseq_fit',
name: 'NCBI RefSeq — fit (squeeze all features into view)',
assemblyNames: ['hg19'],
adapter,
// fit: the rows scale down so everything fits within the fixed `height`
displayDefaults: {
heightMode: 'fit',
height: 150,
},
},
]
export default function WithTrackSizing() {
return (
<LinearGenomeView
assembly={assembly}
tracks={tracks}
init={{
loc: 'chr17:7,560,000..7,600,000',
tracks: ['refseq_grow', 'refseq_fit'],
}}
/>
)
}Highlight a feature, and sort it to the top
init.highlight paints a band over a region, across every track at once.
featureHighlights marks one feature instead: it boxes the gene, transcript
or variant at whatever row and height its own track laid it out, and it sorts
that feature to a top row of the lane and holds it there across pan and zoom. On
a dense annotation track the second half is usually the point.
Each entry names one feature, by name or by span:
featureHighlights: [
{ refName: 'chr12', name: 'KRAS' }, // exact label, case insensitive
{ refName: 'chr12', start: 25205245, end: 25250929 }, // interbase, ±1bp
]
Prefer the name. The span form is interbase (0-based, half-open) and has to
agree with the track’s own record to within a base, while a location box reads
chr12:25,205,246-25,250,929 for that same feature — 1-based and inclusive — so
coordinates copied off the screen match nothing. An entry may carry both, and
then the name is the fallback used when the span misses.
This is the same state a right-click “Highlight feature” writes, so a user can
add and clear these by hand. It rides displaySnapshot rather than the track’s
displayDefaults
because it is display state, not a config slot, and JBrowse drops a state prop
written onto a config without saying so.
View source — 44 lines
import { LinearGenomeView } from '@jbrowse/react-linear-genome-view2'
// managed API: props are initial values, the component owns the engine
export default function WithFeatureHighlights() {
return (
<LinearGenomeView
assembly={{
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',
},
}}
tracks={[
{
type: 'FeatureTrack',
trackId: 'ncbi-refseq-genes',
name: 'NCBI RefSeq Genes',
assemblyNames: ['hg38'],
adapter: {
type: 'Gff3TabixAdapter',
uri: 'https://s3.amazonaws.com/jbrowse.org/genomes/GRCh38/ncbi_refseq/GCA_000001405.15_GRCh38_full_analysis_set.refseq_annotation.sorted.gff.gz',
},
},
]}
init={{
loc: 'chr12:25,150,000-25,400,000',
tracks: [
{
trackId: 'ncbi-refseq-genes',
// `featureHighlights` is display STATE, not a config slot, so it
// goes here rather than in the track's `displayDefaults` — a state
// prop written onto a config is dropped in silence. Each entry
// boxes one feature and holds it in a top row of the track.
displaySnapshot: {
height: 220,
featureHighlights: [{ refName: 'chr12', name: 'KRAS' }],
},
},
],
}}
/>
)
}