JBrowse 2 · Linear Genome View examples

View setup

Render the component and give it a starting state, declaratively, in shorthand, or through the useCreateViewState hook.

The simplest example

The smallest working embed: one component, three props. assembly names the reference sequence and where to fetch it, tracks declares what is available, and init says where to open and which of those tracks to show. The component creates and owns its view state — no store, no provider.

assembly.uri points at a .2bit here; .fa with a .fai, .fa.gz with .fai+.gzi, and a chrom.sizes-only assembly all work through the same field. Adapters take the same uri shorthand, so a .gff3.gz finds its .gff3.gz.tbi without the nested index form. init.loc is a 1-based locstring, the same thing a user types into the location box.

View source — 26 lines
import { LinearGenomeView } from '@jbrowse/react-linear-genome-view2'

export default function OneLinearGenomeView() {
  return (
    <LinearGenomeView
      assembly={{
        name: 'volvox',
        uri: 'https://jbrowse.org/genomes/volvox/volvox.2bit',
      }}
      tracks={[
        {
          type: 'FeatureTrack',
          trackId: 'volvox_gff3',
          name: 'Volvox genes',
          assemblyNames: ['volvox'],
          adapter: {
            type: 'Gff3TabixAdapter',
            uri: 'https://jbrowse.org/code/jb2/main/test_data/volvox/volvox.sort.gff3.gz',
          },
        },
      ]}
      // loc is a 1-based locstring
      init={{ loc: 'ctgA:1105..1221', tracks: ['volvox_gff3'] }}
    />
  )
}

Tracks as an id and a uri

The tracks prop takes the same entries a config.json does, and the shortest of them is an id and a uri. The guess behind it is the one the app’s “Add track” dialog runs — what each extension resolves to is listed in supported file types.

assemblyNames is the key worth knowing about. This component stamps on the assembly it was given, and a config.json supplies it wherever the file declares exactly one assembly. Nothing implies it for a track handed to session.addTrackConf or arriving through &sessionTracks=: that one keeps the empty list it was built with, belongs to no assembly, and appears in no track selector.

Spell type and adapter out when the file name does not decide the format — a .txt.gz that is not Pan-UKBB GWAS summary statistics — or when an adapter slot has to be set. A key written beside uri lands on the track rather than inside the adapter, so csi: true for a CSI index needs the full form. index is the exception, for an index that is not the sibling the guess would derive.

View source — 35 lines
import { LinearGenomeView } from '@jbrowse/react-linear-genome-view2'

const base = 'https://jbrowse.org/code/jb2/main/test_data/volvox'

// A track is its id and its file. JBrowse reads the track type and the adapter
// off the extension — .gff3.gz a FeatureTrack over Gff3TabixAdapter, .bw a
// QuantitativeTrack over BigWigAdapter, .vcf.gz a VariantTrack over
// VcfTabixAdapter — derives each index sibling, and names the track after the
// file. This embed has one assembly, so the tracks are on it without saying so.
export default function WithTrackShorthand() {
  return (
    <LinearGenomeView
      assembly={{
        name: 'volvox',
        uri: 'https://jbrowse.org/genomes/volvox/volvox.2bit',
      }}
      tracks={[
        { trackId: 'genes', uri: `${base}/volvox.sort.gff3.gz` },
        { trackId: 'microarray', uri: `${base}/volvox_microarray.bw` },
        // any key beside uri wins over the guess, so the shorthand does not
        // run out when one track needs a name and a color of its own
        {
          trackId: 'duplications',
          uri: `${base}/volvox.dup.vcf.gz`,
          name: 'Duplications',
          displayDefaults: { color: 'purple' },
        },
      ]}
      init={{
        loc: 'ctgA:1..50,000',
        tracks: ['genes', 'microarray', 'duplications'],
      }}
    />
  )
}

Declarative init

The same call against a real assembly. init is the recommended way to embed: a starting locstring and the trackIds to open on first paint. init.loc takes any locstring, including space-separated multi-region ones ('chr1:100-200 chr1:500-600'). It is the same shape JBrowse Web serializes into its ?session=spec-… URL query parameter.

init runs once, when the view is created — think of an input’s defaultValue. Re-rendering with a different loc won’t move a view the user has panned; to drive it after mount, take a ref and call navigation actions.

Three of the assembly fields in the source start mattering past a toy genome:

  • refNameAliases resolves chr1, 1 and NC_000001.11 to the same contig. Point it at UCSC’s chromAlias and differently-named tracks still line up.
  • chromSizes gives the sequence adapter chromosome lengths directly, so the view lays out the genome without reading the .2bit first.
  • csi: true selects a .csi index instead of Tabix .tbi, required past ~512 Mb.

See advanced init for per-track display snapshots, and the config guide for the full track/assembly shape.

View source — 35 lines
import { LinearGenomeView } from '@jbrowse/react-linear-genome-view2'

export default function WithInit() {
  return (
    <LinearGenomeView
      assembly={{
        name: 'hg38',
        uri: 'https://jbrowse.org/genomes/GRCh38/fasta/hg38.prefix.fa.gz',
        refNameAliases: {
          uri: 'https://jbrowse.org/genomes/GRCh38/hg38_aliases.txt',
        },
        cytobands: {
          uri: 'https://jbrowse.org/genomes/GRCh38/cytoBand.txt',
        },
      }}
      tracks={[
        {
          type: 'FeatureTrack',
          trackId: 'hg38-ncbi-refseq-curated',
          name: 'NCBI RefSeq Curated',
          assemblyNames: ['hg38'],
          adapter: {
            type: 'Gff3TabixAdapter',
            uri: 'https://jbrowse.org/ucsc/hg38/ncbiRefSeqCurated.gff.gz',
            csi: true,
          },
        },
      ]}
      init={{
        loc: 'chr7:155,799,529..155,812,871',
        tracks: ['hg38-ncbi-refseq-curated'],
      }}
    />
  )
}

useCreateViewState

createViewState builds a MobX-state-tree instance — an expensive stateful object that must not be rebuilt on every render, or each parent re-render throws away the view’s scroll position, open tracks and in-flight data. useCreateViewState memoizes it for the component’s lifetime, and <JBrowseLinearGenomeView viewState={state}> renders it.

It takes the same options the managed <LinearGenomeView> takes, init included, so choosing it costs no extra setup — and it hands you the engine on the first render, where a ref on that component arrives one render later. Two things need it: reading the view while rendering (a button of yours that depends on view state), and destroying the engine when you discard it.

location is a shorthand for init.loc that also accepts a { refName, start, end } object (0-based), handier when you already have structured coordinates than the 1-based locstring.

View source — 52 lines
import { useState } from 'react'

import {
  JBrowseLinearGenomeView,
  useCreateViewState,
} from '@jbrowse/react-linear-genome-view2'

// This component renders the genome view. Because it uses useCreateViewState,
// parent re-renders (e.g. from the counter above) do not reset the browser.
function GenomeView() {
  const state = useCreateViewState({
    assembly: {
      name: 'volvox',
      uri: 'https://jbrowse.org/genomes/volvox/volvox.2bit',
    },
    tracks: [
      {
        type: 'FeatureTrack',
        trackId: 'volvox_gff3',
        name: 'Volvox genes',
        assemblyNames: ['volvox'],
        adapter: {
          type: 'Gff3TabixAdapter',
          uri: 'https://jbrowse.org/code/jb2/main/test_data/volvox/volvox.sort.gff3.gz',
        },
      },
    ],
    location: 'ctgA:1105..1221',
  })
  return <JBrowseLinearGenomeView viewState={state} />
}

export default function UseCreateViewState() {
  const [count, setCount] = useState(0)
  return (
    <div>
      <p>
        Parent render count: {count} — clicking the button triggers a parent
        re-render, but the genome view state is preserved because{' '}
        <code>useCreateViewState</code> creates the state only once.
      </p>
      <button
        onClick={() => {
          setCount(c => c + 1)
        }}
      >
        Re-render parent
      </button>
      <GenomeView />
    </div>
  )
}