JBrowse 2 · Linear Genome View examples

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 — keep height, scroll for the overflow (the default)
  • grow — grow tall enough to show every row at full size
  • fit — scale rows down until they all fit inside height

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' }],
            },
          },
        ],
      }}
    />
  )
}