JBrowse 2 · Linear Genome View examples

Nextstrain pathogens

Genes, diversity, and a per-sample genotype matrix for SARS-CoV-2, Zika, Ebola, measles, and RSV-A.

Five viral genomes — SARS-CoV-2, Zika, Ebola, measles, RSV-A — each one config object bundled with the app. The Pathogen dropdown swaps which config the view is built from; nothing else changes. Gene annotations are inline (FromConfigAdapter), while the reference (IndexedFastaAdapter) and the Shannon-entropy diversity track (BigWigAdapter) are flatfiles on jbrowse.org/demos.

Sample genotypes is a multi-sample variant matrix. The generator walks each phylogeny’s nucleotide mutations root→tip to reconstruct every tip’s genotype at every variable site, then writes a bgzipped VCF plus a samplesTsv of tip metadata, which LinearMultiSampleVariantMatrixDisplay draws as samples × sites colored by region. Zika and measles also carry a CramAdapter Published genomes track — every genome NCBI publishes, aligned with minimap2.

scripts/gen-nextstrain-demos.mjs builds all of it from the live Nextstrain datasets. Because each config is a plain JS object, your own code can import, generate or template it the same way. See react-msaview for the matching reconstructed tree and alignment.

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

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

import covid from './nextstrain_covid.json'
import ebola from './nextstrain_ebola.json'
import measles from './nextstrain_measles.json'
import rsvA from './nextstrain_rsv_a.json'
import zika from './nextstrain_zika.json'

// each config is generated by scripts/gen-nextstrain-demos.mjs from the live
// Nextstrain dataset: inline gene annotations, a hosted reference + diversity
// track, and a per-sample genotype matrix reconstructed from the phylogeny. The
// pathogen dropdown just swaps which committed config the view is built from.
const pathogens = [
  { slug: 'covid', label: 'SARS-CoV-2', config: covid },
  { slug: 'zika', label: 'Zika', config: zika },
  { slug: 'ebola', label: 'Ebola', config: ebola },
  { slug: 'measles', label: 'Measles', config: measles },
  { slug: 'rsv-a', label: 'RSV-A', config: rsvA },
]

function PathogenView({
  config,
}: {
  config: (typeof pathogens)[number]['config']
}) {
  const { assembly, tracks, defaultSession, location } = config
  const state = useCreateViewState({
    assembly,
    tracks,
    defaultSession,
    location,
  })
  // The `key` below unmounts this component on every pathogen change, so this
  // page builds and discards engines rather than keeping one for the lifetime
  // of the page. Nothing to do about it here: useCreateViewState destroys the
  // engine on unmount, so the RPC worker threads and the autoruns go with it.
  return <JBrowseLinearGenomeView viewState={state} />
}

export default function NextstrainPathogens() {
  const [slug, setSlug] = useState('covid')
  const pathogen = pathogens.find(p => p.slug === slug)!
  return (
    <div>
      <label>
        Pathogen{' '}
        <select
          value={slug}
          onChange={event => {
            setSlug(event.target.value)
          }}
        >
          {pathogens.map(p => (
            <option key={p.slug} value={p.slug}>
              {p.label}
            </option>
          ))}
        </select>
      </label>
      {/* key forces a fresh view engine when the pathogen changes */}
      <PathogenView key={slug} config={pathogen.config} />
    </div>
  )
}