JBrowse 2 · Linear Genome View examples

Flip regions

Reverse-complement the whole view, or mix orientations across multiple displayed regions.

Horizontally flip the view

Regions can render reversed (3’→5’), which is what you want for a gene on the negative strand or a synteny-style layout. Two ways in:

  • imperatively, view.horizontallyFlip() — for your own toolbar button or keyboard shortcut;
  • declaratively, [rev] appended to a locstring (init: { loc: 'ctgA:1,000..5,000[rev]' }), so the view opens flipped.

The button takes the engine as a plain prop rather than a ref to one, which is what useCreateViewState buys: the engine exists before the first render, so there is no RefObject to thread down and no ?. at the call.

To flip only some regions of a multi-region view, see mixing orientations.

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

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

import type { ViewModel } from '@jbrowse/react-linear-genome-view2'

const assembly = {
  name: 'volvox',
  uri: 'https://jbrowse.org/genomes/volvox/volvox.2bit',
}

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

// imperative toggle via the view's horizontallyFlip() action. The engine is
// built by the hook and passed down as a plain value, so this takes a
// ViewModel rather than a ref to one: `<LinearGenomeView ref>` would hand it
// over a render later, which is a RefObject to thread through and a `?.` at
// every use for a value that is never actually absent here.
function FlipButton({ viewState }: { viewState: ViewModel }) {
  const [error, setError] = useState<unknown>()
  return (
    <div>
      <button
        onClick={() => {
          try {
            viewState.session.view.horizontallyFlip()
          } catch (e) {
            setError(e)
          }
        }}
      >
        Horizontally flip
      </button>
      {error ? <ErrorBanner error={error} /> : null}
    </div>
  )
}

export default function HorizontallyFlip() {
  const state = useCreateViewState({
    assembly,
    tracks,
    init: { loc: 'ctgA:1-50000' },
  })
  const flipped = useCreateViewState({
    assembly,
    tracks,
    // the same view, opened already reversed: [rev] is part of the locstring,
    // so it travels through a saved session or a shared URL like any other
    init: { loc: 'ctgA:1-50000[rev]' },
  })
  return (
    <div>
      <h3>Flip imperatively from a button</h3>
      <FlipButton viewState={state} />
      <JBrowseLinearGenomeView viewState={state} />
      <h3>Open already flipped via a [rev] locstring</h3>
      <JBrowseLinearGenomeView viewState={flipped} />
    </div>
  )
}

Multiple displayed regions, some flipped

A space-separated multi-region locstring in init.loc shows several regions at once.

Orientation is per region — a [rev] suffix reverse-complements just that one, so the regions on screen can differ. view.horizontallyFlip() reverses the whole arrangement: the regions swap order and each flips its own reversed, which is why there is no single “is it flipped” flag to read back — on these two regions displayedRegions[0].reversed is false before the click and false after it. Watch the scalebar instead. Multi-region views are the building block for gene-centric layouts and synteny ribbons.

See horizontally flip for the single-region cases.

View source — 60 lines
import {
  JBrowseLinearGenomeView,
  useCreateViewState,
} from '@jbrowse/react-linear-genome-view2'

export default function WithMultipleDisplayedRegionsFlipped() {
  const state = useCreateViewState({
    assembly: {
      name: 'GRCh38',
      uri: 'https://s3.amazonaws.com/jbrowse.org/genomes/GRCh38/fasta/GRCh38.fa.gz',
      aliases: ['hg38'],
      refNameAliases: {
        uri: 'https://s3.amazonaws.com/jbrowse.org/genomes/GRCh38/hg38_aliases.txt',
      },
    },
    tracks: [
      {
        type: 'FeatureTrack',
        trackId: 'ncbi-refseq-genes',
        name: 'NCBI RefSeq Genes',
        category: ['Genes'],
        assemblyNames: ['GRCh38'],
        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',
        },
      },
    ],
    defaultSession: {
      name: 'Multi-region flipped example',
      view: {
        type: 'LinearGenomeView',
        init: {
          // two displayed regions, the second reverse-complemented via its own
          // [rev] suffix — orientation is per-region, so they can differ
          loc: 'chr1:113073119..113073695 chr1:113091267..113091433[rev]',
          assembly: 'GRCh38',
          tracks: ['ncbi-refseq-genes'],
        },
      },
    },
  })
  return (
    <div>
      {/* horizontallyFlip() reverses the *arrangement*: the regions swap
          places and each one's own `reversed` flips with them. So there is no
          "is the view flipped" bit to read back — with these two regions,
          region 0 is forward-facing both before and after. The scalebar is
          what shows it */}
      <button
        onClick={() => {
          state.session.view.horizontallyFlip()
        }}
      >
        Flip horizontally
      </button>
      <JBrowseLinearGenomeView viewState={state} />
    </div>
  )
}