JBrowse 2 combined guide

This document is a collection of all our documentation. It includes our quick start guide, user guide, configuration guide, CLI guide, developer guide, and FAQ. You can browse the other documents individually, but this page is to help simple ctrl+f searching and easy browsing. You can also download a pdf version of these same docs located at https://jbrowse.org/jb2/jbrowse2.pdf

JBrowse web quick start

In this guide, we'll get an instance of JBrowse running on your computer.

Pre-requisites

  • Ability to run commands on the command line
  • Node.js 10+
caution

If you are using apt as your package manager, we recommend not using it to install Node.js. Good alternatives include NodeSource or NVM.

Download

You can download JBrowse 2 by using the JBrowse CLI or by downloading and unpacking it manually. We recommend using the JBrowse CLI since it also includes utilities to help you configure JBrowse 2 once it is set up.

Downloading using the JBrowse CLI

The JBrowse CLI can help perform many tasks to help you manage JBrowse 2, such as:

  • create a new instance of JBrowse 2 automatically
  • update an existing instance of JBrowse 2 with the latest released version
  • configure your JBrowse 2 instance
Installing the CLI tools

To install the JBrowse CLI, run

npm install -g @jbrowse/cli

After running this command you can then test the installation with

jbrowse --version

This will output the current version of the JBrowse CLI.

note

If you can't or don't want to globally install the JBrowse CLI, you can also use the npx command, which is included with Node.js, to run JBrowse CLI without installing it. Simply replace jbrowse with npx @jbrowse/cli in any command, e.g.

npx @jbrowse/cli --version
Using jbrowse create to download JBrowse 2

In the directory where you would like to download JBrowse 2, run this command

jbrowse create jbrowse2

Downloading using the JBrowse CLI

You can also download JBrowse 2 manually. Go to the releases page of the JBrowse 2 GitHub repository and find the latest release that is tagged @jbrowse/web. Download the ZIP file from that release. Make sure it is the ZIP file that starts with jbrowse-web- and not the "Source code" ZIP file. Once you have downloaded the ZIP file, extract it to the location you would like to have JBrowse 2.

Checking the download

Whether you used the JBrowse CLI or downloaded manually, the directory where you downloaded JBrowse should look something like this:

jbrowse2/
├── a586bb28a5bad4a3aba2.worker.js
├── a586bb28a5bad4a3aba2.worker.js.LICENSE.txt
├── a586bb28a5bad4a3aba2.worker.js.map
├── asset-manifest.json
├── favicon.ico
├── index.html
├── manifest.json
├── precache-manifest.52c8ba3337cf7ae812b37d874b2de030.js
├── robots.txt
├── service-worker.js
├── static/
└── test_data/

Running JBrowse 2

JBrowse 2 requires a web server to run. It won't work if you try to directly open the index.html in your web browser. We can use a simple server to check that JBrowse 2 has been downloaded properly. Run

cd jbrowse2/
npx serve .

This will start a web server in our JBrowse 2 directory. Navigate to the location specified in the tool's output. It will look something like http://localhost:5000. Once at that page, you should see a page that says that the configuration is not found. That is expected, since we haven't configured JBrowse 2 yet. It will look something like this:

JBrowse 2 screen showing no configuration found

Go ahead an click on the sample config to see a JBrowse 2 running with a demo configuration. It should look like this:

JBrowse 2 with a sample configuration

Congratulations! You're running JBrowse 2.

Next steps

Now that JBrowse 2 is set up, you can configure it with your own genomes and tracks. There are two ways you can configure JBrowse 2: with the JBrowse CLI (guide here) or with JBrowse 2's built-in graphical configuration editing (guide here).

Config editing quick start — command-line interface

In order to display your data, JBrowse 2 needs to know about the reference genome for your organism of interest and needs to have tracks created that reference your data sources. This guide will show you how to set those up using the JBrowse CLI.

note

You can also do this configuration with graphical configuration editing interface built into JBrowse 2. See that guide here.

Pre-requisites

Adding a genome assembly

info

For this step we configure JBrowse to use files being hosted at a URL. For an example of how to use files located on your computer, see the adding a track step.

First we will configure an assembly, or reference genome, for for JBrowse 2. This usually means providing a file that describes the reference sequence for the organism, such as a FASTA or 2BIT file.

You will want to use your own data for your organism, but for this example we provide a small example reference sequence for a simulated organism, volvox mythicus, that you can use.

## Make sure you are in the directory where you have downloaded JBrowse 2
jbrowse add-assembly http://jbrowse.org.s3.amazonaws.com/genomes/volvox/volvox.fa
caution

A FASTA must have an index to work in JBrowse 2. This command assumes that the index file is the same as the FASTA but with .fai appended to the file name.

This command will generate a config file if one does not exist yet and add an assembly called "volvox" to the config file with the URLs of the FASTA and FASTA index files. The name of the assembly was guessed from the file name, but you can customize that and many other things with various flags passed to the command. You can run jbrowse add-assembly --help to get a list of all the options.

JBrowse 2 also supports other assembly file formats, such as bgzip-compressed indexed FASTA (e.g. .fa.gz, .fa.gz.fai, and .fa.gz.gzi files) and 2BIT files. See configuring assemblies for more info on formats supported for the sequence file.

note

If your FASTA is not indexed, you can use the samtools tool to index it.

samtools faidx volvox.fa
## generates volvox.fa.fai

Or if you want to compress your FASTA, you can use bgzip as well.

bgzip volvox.fa
samtools faidx volvox.fa.gz
## compresses volvox.fa to volvox.fa.gz and generates volvox.fa.gz.fai and volvox.fa.gz.gzi

For more info about bgzip and samtools, see https://www.htslib.org/.

If you have your JBrowse 2 running as described in the JBrowse web quickstart, you can refresh the page and an add a linear genome view. You will now see your config in the Assembly dropdown.

JBrowse 2 linear genome view setup with volvox in assembly dropdown

Adding a track

Now we will show you how to add an alignments track and a variant track to JBrowse 2.

info

For this step we configure JBrowse to use files located on your computer. For an example of how to use files hosted at a URL, see the adding a genome assembly step.

Adding an alignments track

For this example we will use a BAM file to add an alignments track. Again, for this example we provide a small example BAM, but for your data you will replace the file name with the names of your data files.

For this track we will assume the data is on your computer at the locations /data/volvox.bam and /data/volvox.bam.bai. You can download these file here if you want to run this example: BAM and BAM index.

To add the track, run

## Replace with the location of your BAM file
jbrowse add-track /data/volvox.bam --load copy

This will copy the BAM and BAM index into the JBrowse 2 directory and add a track pointing at those files to the config file. To see more options adding the track, such as specifying a name, run jbrowse add-track --help.

If you don't want to copy your BAM file, you can use --move to move the file into the JBrowse 2 directory or --symlink to add a symlink to the file to the JBrowse 2 directory. If you want more control over the location, you can use inPlace to point the track at the file where it is, but be careful with this option because on a traditional server you will need to ensure that the file is in a place where the web server is serving it.

note

If your BAM is not indexed, you can use the samtools tool to index it.

samtools index volvox.bam
## generates volvox.bam.bai

For more info about samtools, see https://www.htslib.org/.

If you have your JBrowse 2 running as described in the JBrowse web quickstart, you can refresh the page and an add a linear genome view of the volvox assembly. Then open track selector, and you will see the alignments track.

JBrowse 2 linear genome view with alignments track

Adding a variant track

Adding a variant track is similar to adding an alignments track. For this example, we will use a VCF file for the track. JBrowse 2 expects VCFs to be compressed with bgzip and indexed. Similar to the above example, we will assume the files are at /data/volvox.vcf.gz and /data/volvox.vcf.gz.tbi. You can download these file here: VCF and VCF index.

To add the track, run

jbrowse add-track /data/volvox.vcf.gz --load copy
note

If your VCF is not indexed, you can use the bgzip and tabix tools to compress index it.

bgzip yourfile.vcf
tabix yourfile.vcf.gz

Alternatively, you can do the same thing with the bcftools tool.

bcftools view volvox.vcf --output-type z > volvox.vcf.gz
rm volvox.vcf
bcftools index --tbi volvox.vcf.gz

For more info about bgzip, tabix, and bcftools, see https://www.htslib.org/.

If you have your JBrowse 2 running as described in the JBrowse web quickstart, you can refresh the page and an add a linear genome view of the volvox assembly. Then open track selector, and you will see the variant track.

JBrowse 2 linear genome view with variant track

Conclusion

Now that you have JBrowse configured with an assembly and a couple of tracks, you can start customizing it further. Check out the rest of the docs for more information, especially the JBrowse CLI docs for more details on some of the steps shown here.

Config editing quick start — graphical interface

In order to display your data, JBrowse 2 needs to know about the reference genome for your organism of interest and needs to have tracks created that reference your data sources. This guide will show you how to set those up using the JBrowse 2's graphical configuration editing.

note

You can also do this configuration with JBrowse CLI. See that guide here.

Pre-requisites

This tutorial requires having the following software installed

Starting JBrowse 2 admin server

The JBrowse CLI contains a tool called admin-server. This will act as a web server for JBrowse 2 and will write any changes made in JBrowse 2 to a config file. The admin-server is meant to be run only temporarily to help you set up your config, it is not used for serving your jbrowse instance in production.

The admin-server launches an instance of JBrowse 2 in "admin mode", which then lets you

  • Add and edit assemblies with the "Assembly manager"
  • Add tracks and edit tracks
  • Add and edit connections

All of these changes will be written by the server to the JBrowse config file (usually config.json) located in the JBrowse instance. This is something that can only be done while the admin-server is running, which again, is only meant to be temporary!

To start the admin-server, navigate into your JBrowse 2 directory and run

### Start the admin-server
jbrowse admin-server

This will then generate a link that you can visit in your web browser

JBrowse CLI admin-server output

warning

Note: the admin-server is meant to be used temporarily for configuration, not in production

Adding a genome assembly

A key first step in configuring a genome browser is adding an assembly to view. In order to do this, use the navigation bar to open up the Assembly Manager (Admin > Open Assembly Manager).

This opens up a table which can be used to create, edit, and delete assemblies in your application

Assembly manger

Let's add the hg38 human reference genome to our JBrowse 2 application.

Press the "Add New Assembly" button, and enter hg38 as the assembly name in the text field

Assembly manager page for adding an assembly

Click on "Create New Assembly". Great, we've added an assembly! Now, in the configuration editor, add an alias, and configure the adapter to point the hg38 genome hosted by JBrowse:

  • fasta: https://jbrowse.org/genomes/GRCh38/fasta/hg38.prefix.fa.gz
  • fasta index: https://jbrowse.org/genomes/GRCh38/fasta/hg38.prefix.fa.gz.fai
  • gzi: https://jbrowse.org/genomes/GRCh38/fasta/hg38.prefix.fa.gz.gzi

Figure showing the settings

After clicking the back arrow to return to the table of assemblies, we see that we have successfully added the hg38 assembly.

Figure showing the assembly manager

The assembly can be edited or deleted, but for now we will return to the application.

Editing a genome assembly

After you've added a genome assembly, you can use the pencil icon button in the Assembly manager to edit that assembly. You can also delete assemblies from the assembly manager.

Adding a track

To add a new track or connection, you can use the menu bar in the app to open the form for adding a track File > Open Track:

JBrowse 2 file menu with  menu item

Alternatively, you can use the action button (circular "+") inside the track selector to access the "Add track" form.

JBrowse 2 action button

In the "Add track" form, you can provide a URL to a file to load. Opening files from your local machine is not supported currently in the JBrowse 2 web app (JBrowse desktop does allow this, though, and this functionality may be added in some form in the future)

Paste a URL to a file and optionally provide an index file URL too. The following file formats are supported

  • tabix-indexed VCF
  • tabix-indexed BED
  • tabix-indexed GFF
  • indexed BAM
  • indexed CRAM
  • BigWig
  • BigBed
  • Hi-C (Juicebox)

For tabix files, TBI or CSI indexes are allowed. CSI or BAI is allowed for BAM. Only CRAI is allowed for CRAM. The index will be inferred for BAI or TBI files as e.g. filename+'.bai'. If it is different from this, make sure to specify the index file explicitly.

Editing a track

First we will open a Linear Genome View using the navigation bar (File > Add > Linear Genome View), and click on the "Select Tracks" button.

The configuration settings are accessible by clicking on the ellipses by each track.

Figure showing the configuration editor

Open the configuration editor for the track by clicking on the "Settings" button shown above. You can use the configuration editor to live-edit any configurable value for a given track.

Additional resources

There are a number of additional features for configuring JBrowse 2. Make sure to refer to the config guide for topics such as adding tracks or adding an assembly with the CLI

Conclusion

This quickstart showed how to launch the admin-server in the JBrowse CLI to perform graphical configuration of your application. Specifically, we looked at how to access and use the assembly manager, as well as how to access the configuration editor for tracks. Importantly, all tracks have different configuration options available in the configuration editor.

Make sure to take a look at any tracks you add to JBrowse 2 that you might want to further configure!

Quick start for JBrowse desktop

Important note on JBrowse desktop

We do not have downloads of JBrowse 2 Desktop yet, it is expecting a release in late 2020

Installing JBrowse desktop

This guide will walk you through installing jbrowse 2 on the desktop

JBrowse 2 desktop does not require any pre-requisites for your installation, so we can jump right in

Installing on Linux

Visit http://github.com/gmod/jbrowse-components/releases/latest

Download the latest release artifact with linux in the name

Unzip the file, open the directory, and run the file named "JBrowse 2" in the terminal with

./JBrowse\ 2
Installing on MacOS

Visit http://github.com/gmod/jbrowse-components/releases/latest and find the latest MacOS release artifact in our latest builds

You can then unzip this download and the "JBrowse 2" app will be unzipped to this folder. You can then run JBrowse 2 from clicking this file.

Finder window showing the downloaded zip file and unzipped contents

To run JBrowse 2, you can launch the unzipped app, however if you double click on the file it may give you a warning about running a program from an unauthorized developer since JBrowse 2 isn't registered with Mac's app store

In order to properly launch JBrowse 2

  1. Right-click or hold control and click "JBrowse 2" app in the Finder
  2. Select "Open" from the context menu
  3. The warning will pop up again but with the option to run icon

Reference https://support.apple.com/guide/mac-help/open-a-mac-app-from-an-unidentified-developer-mh40616/mac

The \"open app from unauthorized developer\" after right-clicking and selecting \"open\"

Installing on Windows

Visit http://github.com/gmod/jbrowse-components/releases/latest

You can then unzip this file and run the file that comes from unzipping it. Moving this file to the Applications folder is also equivalent to "installing" JBrowse 2

Then open up the Windows Explorer in the unzipped directory and run "JBrowse 2.exe". This may give a "Windows protected your PC" warning, but select "More info..." and then "Run anyway"

User guide

Navigating the UI

Linear genome view usage

To start a linear genome view, use the menu bar

File->Add->Linear genome view

Using the location search box
  • Use the search box in the LGV
  • Enter syntax chr1:1-100 or chr1:1..100
  • You can also specify an assembly name with the locstring {hg19}chr1:1-100

Note: searching by gene name is not yet available but will be added soon!

Scrolling

Mouse wheel can scroll side to side, as well as click and drag. The pan buttons also exist in the header of the linear genome view

Zooming

The zoom buttons exist in the header of the linear genome view, and there is also a slider bar to zoom in and out.

Note: You can also hold the "Ctrl" key and use your mousewheel or trackpad to scroll and this will zoom in and out

Re-ordering tracks

There is a drag handle on the track labels indicating by the six dots, clicking and dragging on this part of the track label can reorder tracks

Adding tracks

To add a new track or connection, you can use the menu bar in the app to open the form for adding a track:

File->Open Track

The \"Add track form\"

Note: There is also a circular "+" button inside the track selector menu that can also be used to access the "Add track" form.

The \"Add track button\" in the tracklist

In the "Add track" form, you can provide a URL to a file to load. Opening files from your local machine is not supported currently in the jbrowse-web app (jbrowse-desktop does allow this though, and may be added to jbrowse-web in the future)

Paste a URL to a file and optionally provide an index file URL too. The following file formats are supported

  • Tabixed VCF
  • Tabixed BED
  • Tabixed GFF
  • BAM
  • CRAM
  • BigWig
  • BigBed
  • .hic file (Juicebox)

For tabix files, TBI or CSI indexes are allowed. CSI or BAI is allowed for BAM. Only CRAI is allowed for CRAM. The index will be inferred for BAI or TBI files as filename+'.bai' for example, but if it is different than this, make sure to specify the index file explicitly.

Note: If you are an administrator, you can add tracks with the command line or with the admin server add-track or admin-server guide

Sharing sessions

The main menu bar has a "Share" button to enable users to share their sessions with other people. The share button generates a URL that can be sent to other users. It is not possible to copy your URL bar and send this to another user currently, because sessions can become too large for the address bar in many cases.

Note that you can copy and paste URLs between different tabs in your local browser though

The session URL will contain

  • what views are on the screen, and settings for the views (e.g. track labels overlapping or offset)
  • what tracks are in the view
  • extra tracks that you added with the "Add track workflow"
  • for the alignments track, the show soft clipping and sort settings on the pileup
  • etc

All this stuff gets included in the session

This means you can share links with your custom tracks with other users, without being a JBrowse admin!

Editing track configs

Currently, in order to edit a track config, you have to make a copy of the track

Figure showing how to copy a track, note that settings button is disabled because we don't \"own this track\" as a non-privileged user

After you have copied the track, you can edit the track settings

Figure showing the settings button is now enabled on the session track, and you have full control over your session tracks

Your new track is a so-called "session track" and can be shared with other users with the "Share" button

Rubberband selection

The scale bars accept a click and drag action to select a region

Rubberband selection can be performed on both the region and overview scale bars

Track label positioning

Track labels can be positioned on their own row or overlapping the data to save vertical screen space. They can also be hidden. This is done by clicking on the hamburger menu for a specific view.

Example of using the overlap and offset track label positioning options

Horizontally flip

The view can be horizontally flipped, or reverse complemented, to make the coordinates go from right to left instead of left to right

We use triangles pointing in the direction of the orientation in the overview bar to help indicate whether the app is horizontally flipped or not

Here is an example of before and after horizontally flipping the view

Before and after horizontally flipping

Alignments tracks

Visualizing alignments is an important aspect of genome browsers. This guide will go over the main features of the "Alignments track"

The alignments track is a combination of a pileup and a coverage visualization

Pileup visualization

The pileup is the lower part of the alignments track and shows each of the reads as boxes positioned on the genome.

By default the reads are colored red if they aligned to the forward strand of the reference genome, or blue if they aligned to the reverse strand.

Coverage visualization

The coverage visualization shows the depth-of-coverage of the reads at each position on the genome, and also draws using colored boxes any occurrence of mismatches between the read and the reference genome, so if 50% of the reads had a T instead of the reference A, half the height of the coverage histogram would contain a 'red' box

Screenshot showing the alignments track, which contains both a coverage view at the top and a pileup view at the bottom

Show soft clipping

If a read contains bases that do not map the the genome properly, they can either be removed from the alignment (hard clipping) or can be included, and not shown by default (soft clipping)

JBrowse 2 also contains an option to "show the soft clipping" that has occurred. This can be valuable to show the signal around a region that contains structural variation or difficult mappability

Shows what turning on soft-clipping enables for a simulated long-read dataset. There is a simulated structural variant, a deletion, at this position, so the read has bases that map to the other side of the deletion being revealed by this.

Sort by options

The alignments tracks can also be configured to "sort by" a specific attribute for reads that span the center line.

By default the center line is not shown, but by showing it (Go to the view's hamburger menu->Select "Show center line") then you will obtain a better idea of what the "sort by" option is doing

Showing the center line

Here is how to turn on the center line

  1. Open the hamburger menu in the top left of the linear genome view
  2. Select "Show center line"

Illustrates before and after turning on the center line. The center line is an indicator that shows what base pair underlies the center of the view. Note that this is used in the \"Sort by\" option discussed below; the sort is performed using properties of the feature or even exact base pair underlying the center line

Sorting by base

Sorting by base will re-arrange the pileup so that the reads that have a specific base-pair mutation at the position crossing the center line (which is 1bp wide) will be arranged in a sorted manner. To enable Sort by base

  1. Open the track menu for the specific track using the vertical '...' in the track label
  2. Select 'Sort by'->'Base pair'

Illustrating the pileup re-ordering that happens when turning on the Sort by->Base pair. The sorting is done by specifically what letter of each read underlies the current center line position (the center line is 1bp wide, so sorted by that exact letter)

There are other sorting options available and more to come. If you have any requests please drop us a line via github here

BigWig tracks

Visualizing genome signals, whether it is read depth-of-coverage or other signal, can often be done by using BigWig files

This figure shows a BigWig using the XY plot renderer

Line plot version of a BigWig

There are many options for controlling the BigWig which can be accessed from the UI. See the bigwig configuration guide

Linear synteny and dotplot views

The dotplot view is a 2D comparative view that can display alignments between different genome assemblies, or even compare a long-read or NGS short-read versus the genome

Opening a dotplot view

Currently the workflow for launching a dotplot is done by navigating in the header bar to the File->Add->Dotplot view

This will let you select the genome assemblies of interest

Then you can also provide a synteny file in the form of PAF via the Add track workflow

Then currently you must configuration edit the PAFAdapter to indicate the two assemblies in the PAFAdapter

Adding a new dotplot or synteny view via the menubar

Example of the import form for a dotplot or synteny view. Allows you to select two different assemblies and a PAF file can be supplied via a URL

Example of a dotplot visualization of the grape vs the peach genome

See the dotplot configuration for more detailed descriptions

Opening a linear synteny view

Use the main menu bar to select

File->Add->Linear synteny view

Adding a new linear-synteny-view via the menubar

Example of the import form for a synteny view allowing you to select two different assemblies and optionally adding a PAF file via a URL

Figure showing grape vs peach synteny

See the linear synteny configuration for more details on manually configuring the synteny view

Long read vs reference plots

One can also launch a dotplot view that compares a long read to the reference genome by

  • Right clicking an alignment
  • Select "Dotplot read vs ref" or "Linear read vs ref" in the context menu

Example of a dotplot of a long read vs the reference genome

Example of a \"synteny\" view of a long read vs the reference genome

Hi-C tracks

Visualizing Hi-C data can be performed with .hic files which are generated by the Juicebox software suite. It uses the hic-straw module developed by the juicebox/igv.js team to visualize it in jbrowse.

Currently configuration options are basic for Hi-C tracks, see configuration for info about configuring Hi-C

tracks

Screenshot showing a Hi-C track

SV inspector

The SV inspector is a "workflow" that is designed to help users inspect structural variant calls

Opening the SV inspector

We can start the SV inspector by launching it from the App level menu bar

The SV inspector can be launched from the main menu bar

This will bring up an "import form" that asks you for your SV evidence. This can be provided using a URL in these formats:

  • VCF (plain text VCF, not tabix VCF)
  • BEDPE
  • STAR-fusion result file
  • or other formats

SV inspector import form

Example SV inspector workflow

We can start the SV inspector workflow by opening up this file containing translocation events called from a breast cancer cell line SKBR3, based on these published data http://schatz-lab.org/publications/SKBR3/

## Example VCF for use in the SV inspector
https://jbrowse.org/genomes/hg19/skbr3/reads_lr_skbr3.fa_ngmlr-0.2.3_mapped.bam.sniffles1kb_auto_l8_s5_noalt.new.vcf

Copy this URL and paste it into the import form and select hg19

SV inspector import form with URL

SV inspector results

After loading the user's requested file, you will have a spreadsheet with each row representing a row of the file you opened, along with a whole-genome overview of the SVs on the right

SV inspector with loaded results

Now here is where things can become interesting

We can perform searching and filtering on the table, which can filter down the number of rows being displayed, and then this dynamically filters the circos view on the right also.

SV inspector with filter applied

Launching breakpoint split view

By clicking on the features in the Circos, or clicking on the triangle drop-down on the leftmost column of the spreadsheet, we can dynamically launch a new view of the data that is called the "split view" or the "breakpoint split view"

This allows us to inspect the breakpoints of the structural variant, and compare each side to the alignments.

Variant tracks

Visualizing variant tracks from the VCF format alongside the original alignment evidence track is a common workflow for validating your results. In JBrowse 2 we can open a variant track and an alignments track as shown below

Variant track indicating a SNP alongside the alignment track evidence

Variant widget

The variant features have a specialized widget that contains a table indicating all the calls that were made in a multi-sample VCF. Some VCF files, like the 1000 genomes VCF, can contain thousands of samples in a single file. This table can display the details

Future additions

We anticipate adding more features to the variant track in the future including

  1. Ability to visualize individual samples in a multi-sample VCF as subtracks of a variant track
  2. Ability to use FILTER the VCF column via the track menu

Config guide

Intro to the config.json

A JBrowse 2 configuration file, a config.json, is structured as follows

{
"configuration": {
/* global configs here */
},
"assemblies": [
/* list of assembly configurations, e.g. the genomes being viewed */
],
"tracks": [
/* array of tracks being loaded, contain reference to which assembl(y/ies)
they belong to */
],
"defaultSession": {
/* optional default session */
}
}

The most important thing to configure are your assemblies and your tracks

Configuring assemblies

An assembly configuration includes the "name" of your assembly, any "aliases" that might be associated with that assembly e.g. GRCh37 is sometimes seen as an alias for hg19, and then a "sequence" configuration containing a reference sequence track config. This is provides a special "track" that is outside the normal track config

Here is a complete config.json file containing only a hg19

{
"assemblies": [
{
"name": "hg19",
"aliases": ["GRCh37"],
"sequence": {
"type": "ReferenceSequenceTrack",
"trackId": "hg19_config",
"adapter": {
"type": "BgzipFastaAdapter",
"fastaLocation": {
"uri": "https://jbrowse.org/genomes/hg19/fasta/hg19.fa.gz"
},
"faiLocation": {
"uri": "https://jbrowse.org/genomes/hg19/fasta/hg19.fa.gz.fai"
},
"gziLocation": {
"uri": "https://jbrowse.org/genomes/hg19/fasta/hg19.fa.gz.gzi"
}
},
"rendering": {
"type": "DivSequenceRenderer"
}
},
"refNameAliases": {
"adapter": {
"type": "RefNameAliasAdapter",
"location": {
"uri": "https://s3.amazonaws.com/jbrowse.org/genomes/hg19/hg19_aliases.txt"
}
}
}
}
]
}

Configuring reference name aliasing

Reference name aliasing is a process to make chromosomes that are named slightly differently but which refer to the same thing render properly

The refNameAliases in the above config provides this functionality

"refNameAliases": {
"adapter": {
"type": "RefNameAliasAdapter",
"location": {
"uri": "https://s3.amazonaws.com/jbrowse.org/genomes/hg19/hg19_aliases.txt"
}
}
}

The hg19_aliases then is a tab delimited file that looks like this

The first column should be the names that are in your FASTA sequence, and the rest of the columns are aliases

1 chr1
2 chr2
3 chr3
4 chr4
5 chr5
6 chr6
7 chr7
8 chr8
9 chr9
10 chr10
11 chr11
12 chr12
13 chr13
14 chr14
15 chr15
16 chr16
17 chr17
18 chr18
19 chr19
20 chr20
21 chr21
22 chr22
X chrX
Y chrY
M chrM MT

Adding an assembly with the CLI

Generally we add a new assembly with the CLI using something like

## use samtools to make a fasta index for your reference genome
samtools faidx myfile.fa
## install the jbrowse CLI
npm install -g @jbrowse/cli
## add the assembly using the jbrowse CLI, this will automatically copy the
myfile.fa and myfile.fa.fai to your data folder at /var/www/html/jbrowse2
jbrowse add-assembly myfile.fa --load copy --out /var/www/html/jbrowse2

See our CLI docs for the add-assembly for more details here -- add-assembly

Note: assemblies can also be added graphically using the assembly manager when you are using the so-called admin-server. See the quickstart guide for more details.

Assembly config

Because JBrowse 2 can potentially have multiple assemblies loaded at once, it needs to make sure each track is associated with an assembly.

To do this, we make assemblies a special part of the config, and make sure each track refers to which genome assembly it uses

Example config with hg19 genome assembly loaded

Here is a complete config.json that has the hg19 genome loaded

{
"assemblies": [
{
"name": "hg19",
"aliases": ["GRCh37"],
"sequence": {
"type": "ReferenceSequenceTrack",
"trackId": "refseq_track",
"adapter": {
"type": "BgzipFastaAdapter",
"fastaLocation": {
"uri": "https://jbrowse.org/genomes/hg19/fasta/hg19.fa.gz"
},
"faiLocation": {
"uri": "https://jbrowse.org/genomes/hg19/fasta/hg19.fa.gz.fai"
},
"gziLocation": {
"uri": "https://jbrowse.org/genomes/hg19/fasta/hg19.fa.gz.gzi"
}
},
"rendering": {
"type": "DivSequenceRenderer"
}
},
"refNameAliases": {
"adapter": {
"type": "RefNameAliasAdapter",
"location": {
"uri": "https://s3.amazonaws.com/jbrowse.org/genomes/hg19/hg19_aliases.txt"
}
}
}
}
]
}

The top level config is an array of assemblies

Each assembly contains

  • name - a name to refer to the assembly by. each track that is related to this assembly references this name
  • aliases - sometimes genome assemblies have aliases like hg19, GRCh37, b37p5, etc. while there may be small differences between these different sequences, they often largely have the same coordinates, so you might want to be able to associate tracks from these different assemblies together. The assembly aliases are most helpful when loading from a UCSC trackHub which specifies the genome assembly names it uses, so you can connect to a UCSC trackHub if your assembly name or aliases match.
  • sequence - this is a complete "track" definition for your genome assembly. we specify that it is a track of type ReferenceSequenceTrack, give it a trackId, and an adapter configuration. an adapter configuration can specify IndexedFastaAdapter (fasta.fa and fasta.fai), BgzipFastaAdapter (fasta.fa.gz, fasta.fa.gz.fai, fasta.gz.gzi), ChromSizesAdapter (which fetches no sequences, just chromosome names)

ReferenceSequenceTrack

Example ReferenceSequenceTrack config, which as above, is specified as the child of the assembly section of the config

{
"type": "ReferenceSequenceTrack",
"trackId": "refseq_track",
"adapter": {
"type": "BgzipFastaAdapter",
"fastaLocation": {
"uri": "https://jbrowse.org/genomes/hg19/fasta/hg19.fa.gz"
},
"faiLocation": {
"uri": "https://jbrowse.org/genomes/hg19/fasta/hg19.fa.gz.fai"
},
"gziLocation": {
"uri": "https://jbrowse.org/genomes/hg19/fasta/hg19.fa.gz.gzi"
}
},
"rendering": {
"type": "DivSequenceRenderer"
}
}

BgzipFastaAdapter

A bgzip FASTA format file is generated by

bgzip -i sequence.fa
samtools faidx sequence.fa.gz
### above commands generate three files
sequence.fa.gz
sequence.fa.gz.gzi
sequence.fa.gz.fai

These are loaded into a BgzipFastaAdapter as follows

{
"type": "BgzipFastaAdapter",
"fastaLocation": {
"uri": "https://jbrowse.org/genomes/hg19/fasta/hg19.fa.gz"
},
"faiLocation": {
"uri": "https://jbrowse.org/genomes/hg19/fasta/hg19.fa.gz.fai"
},
"gziLocation": {
"uri": "https://jbrowse.org/genomes/hg19/fasta/hg19.fa.gz.gzi"
}
}

IndexedFastaAdapter

An indexed FASTA file is similar to the above, but the sequence is not compressed

samtools faidx sequence.fa
### above commands generate three files
sequence.fa
sequence.fa.fai

These are loaded into a IndexedFastaAdapter as follows

{
"type": "IndexedFastaAdapter",
"fastaLocation": {
"uri": "https://jbrowse.org/genomes/hg19/fasta/hg19.fa"
},
"faiLocation": {
"uri": "https://jbrowse.org/genomes/hg19/fasta/hg19.fa.fai"
}
}

TwoBitAdapter

The UCSC twoBit adapter is also supported. Note however that the 2bit format has a longer startup time than other adapters because there is a larger upfront parsing time.

{
"type": "TwoBitAdapter",
"twoBitLocation": {
"uri": "https://jbrowse.org/genomes/hg19/fasta/hg19.2bit"
}
}

Track configurations

All tracks can contain

  • trackId - internal track ID, must be unique
  • name - displayed track name
  • assemblyNames - an array of assembly names a track is associated with, often just a single assemblyName
  • category - (optional) array of categories to display in a hierarchical track selector

Example config.json containing a track config

{
"assemblies": [
{
"name": "hg19",
"aliases": ["GRCh37"],
"sequence": {
"type": "ReferenceSequenceTrack",
"trackId": "Pd8Wh30ei9R",
"adapter": {
"type": "BgzipFastaAdapter",
"fastaLocation": {
"uri": "https://jbrowse.org/genomes/hg19/fasta/hg19.fa.gz"
},
"faiLocation": {
"uri": "https://jbrowse.org/genomes/hg19/fasta/hg19.fa.gz.fai"
},
"gziLocation": {
"uri": "https://jbrowse.org/genomes/hg19/fasta/hg19.fa.gz.gzi"
}
}
}
}
],
"tracks": [
{
"type": "FeatureTrack",
"trackId": "repeats_hg19",
"name": "Repeats",
"assemblyNames": ["hg19"],
"category": ["Annotation"],
"adapter": {
"type": "BigBedAdapter",
"bigBedLocation": {
"uri": "https://jbrowse.org/genomes/hg19/repeats.bb"
}
}
}
]
}

AlignmentsTrack config

Example AlignmentsTrack config

{
"trackId": "my_alignments_track",
"name": "My Alignments",
"assemblyNames": ["hg19"],
"type": "AlignmentsTrack",
"adapter": {
"type": "BamAdapter",
"bamLocation": { "uri": "http://yourhost/file.bam" },
"index": { "location": { "uri": "http://yourhost/file.bam.bai" } }
}
}
BamAdapter configuration options
  • bamLocation - a 'file location' for the BAM
  • index: a subconfiguration schema containing
    • indexType: options BAI or CSI. default: BAI
    • location: a 'file location' of the index

Example BamAdapter config

{
"type": "BamAdapter",
"bamLocation": { "uri": "http://yourhost/file.bam" },
"index": { "location": { "uri": "http://yourhost/file.bam.bai" } }
}
CramAdapter configuration options
  • cramLocation - a 'file location' for the CRAM
  • craiLocation - a 'file location' for the CRAI

Example CramAdapter config

{
"type": "CramAdapter",
"cramLocation": { "uri": "http://yourhost/file.cram" },
"craiLocation": { "uri": "http://yourhost/file.cram.crai" }
}

HicTrack config

Example Hi-C track config

{
"type": "HicTrack",
"trackId": "hic",
"name": "Hic Track",
"assemblyNames": ["hg19"],
"adapter": {
"type": "HicAdapter",
"hicLocation": {
"uri": "https://s3.amazonaws.com/igv.broadinstitute.org/data/hic/intra_nofrag_30.hic"
}
}
}
HicAdapter config

We just simply supply a hicLocation currently for the HicAdapter

{
"type": "HicAdapter",
"hicLocation": {
"uri": "https://s3.amazonaws.com/igv.broadinstitute.org/data/hic/intra_nofrag_30.hic"
}
}
HicRenderer config
  • baseColor - the default baseColor of the Hi-C plot is red #f00, you can change it to blue so then the shading will be done in blue with #00f
  • color - this is a color callback that adapts the current Hi-C contact feature with the baseColor to generate a shaded block. The default color callback function is function(count, maxScore, baseColor) { return baseColor.alpha(Math.min(1,counts/(maxScore/20))).hsl().string() } where it receives the count for a particular block, the maxScore over the region, and the baseColor from the baseColor config

VariantTrack config

  • defaultRendering - options: 'pileup' or 'svg'. default 'svg'
  • adapter - a variant type adapter config e.g. a VcfTabixAdapter

Example config

{
"type": "VariantTrack",
"trackId": "my track",
"name": "My Variants",
"assemblyNames": ["hg19"],
"adapter": {
"type": "VcfTabixAdapter",
"vcfGzLocation": { "uri": "http://yourhost/file.vcf.gz" },
"index": { "location": { "uri": "http://yourhost/file.vcf.gz.tbi" } }
}
}
VcfTabixAdapter configuration options
  • vcfGzLocation - a 'file location' for the BigWig
  • index: a subconfiguration schema containing
    • indexType: options TBI or CSI. default TBI
    • location: the location of the index

Example VcfTabixAdapter adapter config

{
"type": "VcfTabixAdapter",
"vcfGzLocation": { "uri": "http://yourhost/file.vcf.gz" },
"index": { "location": { "uri": "http://yourhost/file.vcf.gz.tbi" } }
}

WiggleTrack config

Example WiggleTrack config

{
"trackId": "my_wiggle_track",
"name": "My Wiggle Track",
"assemblyNames": ["hg19"],
"type": "WiggleTrack",
"adapter": {
"type": "BigWig",
"bigWigLocation": { "uri": "http://yourhost/file.bw" }
}
}
General WiggleTrack options
  • scaleType - options: linear, log, to display the coverage data. default: linear
  • adapter - an adapter that returns numeric signal data, e.g. feature.get('score')
Autoscale options for WiggleTrack

Options for autoscale

  • local - min/max values of what is visible on the screen
  • global - min/max values in the entire dataset
  • localsd - mean value +- N stddevs of what is visible on screen
  • globalsd - mean value +/- N stddevs of everything in the dataset
Score min/max for WiggleTrack

These options overrides the autoscale options and provides a minimum or maximum value for the autoscale bar

  • minScore
  • maxScore
WiggleTrack drawing options
  • inverted - draws upside down
  • defaultRendering - can be density, xyplot, or line
  • summaryScoreMode - options: min, max, whiskers
WiggleTrack renderer options
  • filled - fills in the XYPlot histogram
  • bicolorPivot - options: numeric, mean, none. default: numeric
  • bicolorPivotValue - number at which the color switches from posColor to negColor. default: 0
  • color - color or color callback for drawing the values. overrides posColor/negColor. default: none
  • posColor - color to draw "positive" values. default: red
  • negColor - color to draw "negative" values. default: blue
  • clipColor - color to draw "clip" indicator. default: red
BigWigAdapter options
  • bigWigLocation - a 'file location' for the bigwig

Example BigWig adapter config

{
"type": "BigWig",
"bigWigLocation": { "uri": "http://yourhost/file.bw" }
}

SyntenyTrack config

Example SyntenyTrack config

{
"type": "SyntenyTrack",
"trackId": "dotplot_track",
"assemblyNames": ["YJM1447", "R64"],
"name": "dotplot",
"adapter": {
"type": "PAFAdapter",
"pafLocation": {
"uri": "https://s3.amazonaws.com/jbrowse.org/genomes/yeast/YJM1447_vs_R64.paf"
},
"assemblyNames": ["YJM1447", "R64"]
}
}

We can add a SyntenyTrack from PAF with the CLI e.g. with

jbrowse add-track myfile.paf --type SyntenyTrack --assemblyNames \
grape,peach --load copy --out /var/www/html/jbrowse2

DotplotView config

The configuration of a view is technically a configuration of the "state of the view" but it can be added to the defaultSession

An example of a dotplot config can help explain. This is relatively advanced so let's look at an example

{
"assemblies": [
{
"name": "grape",
"sequence": {
"trackId": "grape_seq",
"type": "ReferenceSequenceTrack",
"adapter": {
"type": "ChromSizesAdapter",
"chromSizesLocation": {
"uri": "grape.chrom.sizes"
}
}
}
},
{
"name": "peach",
"sequence": {
"trackId": "peach_seq",
"type": "ReferenceSequenceTrack",
"adapter": {
"type": "ChromSizesAdapter",
"chromSizesLocation": {
"uri": "peach.chrom.sizes"
}
}
}
}
],
"tracks": [
{
"trackId": "grape_peach_synteny_mcscan",
"type": "SyntenyTrack",
"assemblyNames": ["peach", "grape"],
"trackIds": [],
"renderDelay": 100,
"adapter": {
"mcscanAnchorsLocation": {
"uri": "grape.peach.anchors"
},
"subadapters": [
{
"type": "NCListAdapter",
"rootUrlTemplate": {
"uri": "https://jbrowse.org/genomes/synteny/peach_gene/{refseq}/trackData.json"
}
},
{
"type": "NCListAdapter",
"rootUrlTemplate": {
"uri": "https://jbrowse.org/genomes/synteny/grape_gene/{refseq}/trackData.json"
}
}
],
"assemblyNames": ["peach", "grape"],
"type": "MCScanAnchorsAdapter"
},
"name": "Grape peach synteny (MCScan)",
"category": ["Annotation"]
},
{
"trackId": "grape_peach_paf",
"type": "SyntenyTrack",
"name": "Grape vs Peach (PAF)",
"assemblyNames": ["peach", "grape"],
"adapter": {
"type": "PAFAdapter",
"pafLocation": {
"uri": "https://s3.amazonaws.com/jbrowse.org/genomes/synteny/peach_grape.paf"
},
"assemblyNames": ["peach", "grape"]
}
},
{
"type": "SyntenyTrack",
"trackId": "dotplot_track_small",
"name": "Grape vs peach small (PAF)",
"assemblyNames": ["grape", "peach"],
"adapter": {
"type": "PAFAdapter",
"pafLocation": {
"uri": "peach_grape_small.paf"
},
"assemblyNames": ["peach", "grape"]
}
}
],
"defaultSession": {
"name": "Grape vs Peach (small)",
"views": [
{
"id": "MiDMyyWpp",
"type": "DotplotView",
"assemblyNames": ["peach", "grape"],
"hview": {
"displayedRegions": [],
"bpPerPx": 100000,
"offsetPx": 0
},
"vview": {
"displayedRegions": [],
"bpPerPx": 100000,
"offsetPx": 0
},
"tracks": [
{
"type": "SyntenyTrack",
"configuration": "dotplot_track_small",
"displays": [
{
"type": "DotplotDisplay",
"configuration": "dotplot_track_small-DotplotDisplay"
}
]
}
],
"displayName": "Grape vs Peach dotplot"
}
]
}
}

Note that configuring the dotplot involves creating a "defaultSession"

Users can also open synteny views using the File->Add->Dotplot view workflow, and create their own synteny view outside of the default configuration

LinearSyntenyView config

Currently, configuring synteny is made by pre-configuring a session in the view and adding synteny tracks

{
"defaultSession": {
"name": "Grape vs Peach Demo",
"drawerWidth": 384,
"views": [
{
"type": "LinearSyntenyView",
"id": "test1",
"headerHeight": 44,
"datasetName": "grape_vs_peach_dataset",
"tracks": [
{
"type": "SyntenyTrack",
"configuration": "grape_peach_synteny_mcscan",
"displays": [
{
"configuration": "grape_peach_synteny_mcscan-LinearSyntenyDisplay",
"height": 100,
"type": "LinearSyntenyDisplay"
}
]
}
],
"height": 400,
"displayName": "Grape vs Peach",
"trackSelectorType": "hierarchical",
"views": [
{
"type": "LinearGenomeView",
"id": "test1_1",
"offsetPx": 28249,
"bpPerPx": 1000,
"displayedRegions": [
{
"refName": "Pp01",
"assemblyName": "peach",
"start": 0,
"end": 100000000
}
],
"tracks": [
{
"type": "FeatureTrack",
"configuration": "peach_genes",
"displays": [
{
"configuration": "peach_genes_linear",
"height": 100,
"type": "LinearBasicDisplay"
}
]
}
],
"hideControls": false,
"hideHeader": true,
"hideCloseButton": true,
"trackSelectorType": "hierarchical"
},
{
"type": "LinearGenomeView",
"id": "test1_2",
"offsetPx": 0,
"bpPerPx": 1000,
"displayedRegions": [
{
"refName": "chr1",
"assemblyName": "grape",
"start": 0,
"end": 100000000
}
],
"tracks": [
{
"type": "FeatureTrack",
"configuration": "grape_genes",
"displays": [
{
"configuration": "grape_genes_linear",
"height": 100,
"type": "LinearBasicDisplay"
}
]
}
],
"hideControls": false,
"hideHeader": true,
"hideCloseButton": true,
"trackSelectorType": "hierarchical"
}
]
}
],
"widgets": {},
"activeWidgets": {},
"connections": {}
},
"assemblies": [
{
"name": "grape",
"sequence": {
"trackId": "grape_seq",
"type": "ReferenceSequenceTrack",
"adapter": {
"type": "ChromSizesAdapter",
"chromSizesLocation": {
"uri": "grape.chrom.sizes"
}
}
}
},
{
"name": "peach",
"sequence": {
"trackId": "peach_seq",
"type": "ReferenceSequenceTrack",
"adapter": {
"type": "ChromSizesAdapter",
"chromSizesLocation": {
"uri": "peach.chrom.sizes"
}
}
}
}
],
"tracks": [
{
"trackId": "grape_peach_synteny_mcscan",
"type": "SyntenyTrack",
"assemblyNames": ["peach", "grape"],
"trackIds": [],
"renderDelay": 100,
"adapter": {
"mcscanAnchorsLocation": {
"uri": "grape.peach.anchors"
},
"subadapters": [
{
"type": "NCListAdapter",
"rootUrlTemplate": {
"uri": "https://jbrowse.org/genomes/synteny/peach_gene/{refseq}/trackData.json"
}
},
{
"type": "NCListAdapter",
"rootUrlTemplate": {
"uri": "https://jbrowse.org/genomes/synteny/grape_gene/{refseq}/trackData.json"
}
}
],
"assemblyNames": ["peach", "grape"],
"type": "MCScanAnchorsAdapter"
},
"name": "Grape peach synteny (MCScan)",
"category": ["Annotation"]
},
{
"trackId": "peach_genes",
"type": "FeatureTrack",
"assemblyNames": ["peach"],
"name": "mcscan",
"category": ["Annotation"],
"adapter": {
"type": "NCListAdapter",
"rootUrlTemplate": {
"uri": "https://jbrowse.org/genomes/synteny/peach_gene/{refseq}/trackData.json"
}
},
"displays": [
{
"type": "LinearBasicDisplay",
"displayId": "peach_genes_linear",
"renderer": {
"type": "PileupRenderer"
}
}
]
},
{
"trackId": "peach_genes2",
"type": "FeatureTrack",
"assemblyNames": ["peach"],
"name": "mcscan2",
"category": ["Annotation"],
"adapter": {
"type": "NCListAdapter",
"rootUrlTemplate": {
"uri": "https://jbrowse.org/genomes/synteny/peach_gene/{refseq}/trackData.json"
}
}
},
{
"trackId": "grape_genes",
"type": "FeatureTrack",
"name": "mcscan",
"assemblyNames": ["grape"],
"category": ["Annotation"],
"adapter": {
"type": "NCListAdapter",
"rootUrlTemplate": {
"uri": "https://jbrowse.org/genomes/synteny/grape_gene/{refseq}/trackData.json"
}
},
"displays": [
{
"type": "LinearBasicDisplay",
"displayId": "grape_genes_linear",
"renderer": {
"type": "PileupRenderer"
}
}
]
},
{
"trackId": "grape_genes2",
"type": "FeatureTrack",
"name": "mcscan2",
"category": ["Annotation"],
"assemblyNames": ["grape"],
"adapter": {
"type": "NCListAdapter",
"rootUrlTemplate": {
"uri": "https://jbrowse.org/genomes/synteny/grape_gene/{refseq}/trackData.json"
}
}
}
],
"configuration": {}
}

Configuring the theme

Color

The color scheme as well as some sizing options can be configured via the theme. This is done via a top-level configuration in the config file. For example:

{
"configuration": {
"theme": {
"palette": {
"primary": {
"main": "#4400a6"
}
}
}
}
}

JBrowse uses 4 colors that can be changed. For example, this is the default theme:

JBrowse using the default theme Example of the default theme

JBrowse using a customized theme Example of a customized theme

The customized theme screenshot uses the below configuration

Color codeColor
Primary#311b92Deep purple
Secondary#0097a7Cyan
Tertiary#f57c00Orange
Quaternary#d50000Red
{
"configuration": {
"theme" :{
"palette": {
"primary": {
"main": "#311b92"
},
"secondary": {
"main": "#0097a7"
},
"tertiary": {
"main": "#f57c00"
},
"quaternary": {
"main": "#d50000"
}
}
}
}

Sizing

You can also change some sizing options by specifying the "typography" (to change font size) and "spacing" (to change the amount of space between elements) options:

{
"theme": {
"typography": { "fontSize": 10 },
"spacing": 2
}
}

Advanced

JBrowse uses Material-UI for its theming. You can read more about Material-UI themes here. Generally, most options you could pass to Material-UI's createMuiTheme should work in the theme configuration.

Disabling analytics

This is done via adding a field in the global configuration in the config file. For example:

{
"configuration": {
"disableAnalytics": true
}
}

Command line tools

This document covers the CLI tools.

Installation

The command line tools can be installed using npm as follows

$ npm install -g @jbrowse/cli

You can test your installation with

$ jbrowse --version

It is also possible to do one-off executions using npx, e.g.

npx @jbrowse/cli create myfolder

It is likely preferable in most cases to install the tools first however

Commands

jbrowse add-assembly SEQUENCE

Add an assembly to a JBrowse 2 configuration

USAGE
$ jbrowse add-assembly SEQUENCE
ARGUMENTS
SEQUENCE
sequence file or URL
If TYPE is indexedFasta or bgzipFasta, the index file defaults to <location>.fai
and can be optionally specified with --faiLocation
If TYPE is bgzipFasta, the gzip index file defaults to <location>.gzi and can be
optionally specified with --gziLocation
OPTIONS
-a, --alias=alias
An alias for the assembly name (e.g. "hg38" if the name of the assembly is "GRCh38");
can be specified multiple times
-f, --force
Equivalent to `--skipCheck --overwrite`
-h, --help
show CLI help
-l, --load=copy|symlink|move|inPlace
Required flag when using a local file. Choose how to manage the data directory. Copy, symlink, or move the data
directory to the JBrowse directory. Or use inPlace to modify the config without doing any file operations
-n, --name=name
Name of the assembly; if not specified, will be guessed using the sequence file name
-t, --type=indexedFasta|bgzipFasta|twoBit|chromSizes|custom
type of sequence, by default inferred from sequence file
indexedFasta An index FASTA (e.g. .fa or .fasta) file;
can optionally specify --faiLocation
bgzipFasta A block-gzipped and indexed FASTA (e.g. .fa.gz or .fasta.gz) file;
can optionally specify --faiLocation and/or --gziLocation
twoBit A twoBit (e.g. .2bit) file
chromSizes A chromosome sizes (e.g. .chrom.sizes) file
custom Either a JSON file location or inline JSON that defines a custom
sequence adapter; must provide --name if using inline JSON
--faiLocation=faiLocation
[default: <fastaLocation>.fai] FASTA index file or URL
--gziLocation=gziLocation
[default: <fastaLocation>.gzi] FASTA gzip index file or URL
--out=out
synonym for target
--overwrite
Overwrite existing assembly if one with the same name exists
--refNameAliases=refNameAliases
Reference sequence name aliases file or URL; assumed to be a tab-separated aliases
file unless --refNameAliasesType is specified
--refNameAliasesType=aliases|custom
Type of aliases defined by --refNameAliases; if "custom", --refNameAliases is either
a JSON file location or inline JSON that defines a custom sequence adapter
--refNameColors=refNameColors
A comma-separated list of color strings for the reference sequence names; will cycle
through colors if there are fewer colors than sequences
--skipCheck
Don't check whether or not the sequence file or URL exists or if you are in a JBrowse directory
--target=target
path to config file in JB2 installation directory to write out to.
Creates ./config.json if nonexistent
EXAMPLES
$ jbrowse add-assembly GRCh38.fa --load copy
$ jbrowse add-assembly GRCh38.fasta.with.custom.extension.xyz --type indexedFasta --load move
$ jbrowse add-assembly myFile.fa.gz --name GRCh38 --alias hg38 --load inPlace
$ jbrowse add-assembly GRCh38.chrom.sizes --load inPlace
$ jbrowse add-assembly GRCh38.config.json --load copy
$ jbrowse add-assembly https://example.com/data/sample.2bit
$ jbrowse add-assembly GRCh38.fa --target /path/to/jb2/installation/customconfig.json --load copy

See code: src/commands/add-assembly.ts

jbrowse add-connection CONNECTIONURLORPATH

Add a connection to a JBrowse 2 configuration

USAGE
$ jbrowse add-connection CONNECTIONURLORPATH
ARGUMENTS
CONNECTIONURLORPATH URL of data directory
For hub file, usually called hub.txt
For JBrowse 1, location of JB1 data directory similar to http://mysite.com/jbrowse/data/
OPTIONS
-a, --assemblyName=assemblyName Assembly name of the connection If none, will default to the assembly in your config
file
-c, --config=config Any extra config settings to add to connection in JSON object format, such as
'{"uri":"url":"https://sample.com"}}'
-f, --force Equivalent to `--skipCheck --overwrite`
-h, --help show CLI help
-n, --name=name Name of the connection. Defaults to connectionId if not provided
-t, --type=type type of connection, ex. JBrowse1Connection, UCSCTrackHubConnection, custom
--connectionId=connectionId Id for the connection that must be unique to JBrowse. Defaults to
'connectionType-assemblyName-currentTime'
--out=out synonym for target
--overwrite Overwrites any existing connections if same connection id
--skipCheck Don't check whether or not the data directory URL exists or if you are in a JBrowse
directory
--target=target path to config file in JB2 installation directory to write out to.
EXAMPLES
$ jbrowse add-connection http://mysite.com/jbrowse/data/
$ jbrowse add-connection http://mysite.com/jbrowse/custom_data_folder/ --type JBrowse1Connection
$ jbrowse add-connection http://mysite.com/path/to/hub.txt --assemblyName hg19
$ jbrowse add-connection http://mysite.com/path/to/custom_hub_name.txt --type UCSCTrackHubConnection --assemblyName
hg19
$ jbrowse add-connection http://mysite.com/path/to/custom --type custom --config
'{"uri":{"url":"https://mysite.com/path/to/custom"}}' --assemblyName hg19
$ jbrowse add-connection https://mysite.com/path/to/hub.txt --connectionId newId --name newName --target
/path/to/jb2/installation/config.json

See code: src/commands/add-connection.ts

jbrowse add-track TRACK

Add a track to a JBrowse 2 configuration

USAGE
$ jbrowse add-track TRACK
ARGUMENTS
TRACK Track file or URL
OPTIONS
-a, --assemblyNames=assemblyNames Assembly name or names for track as comma separated string. If none, will
default to the assembly in your config file
-d, --description=description Optional description of the track
-f, --force Equivalent to `--skipCheck --overwrite`
-h, --help show CLI help
-l, --load=copy|symlink|move|inPlace Required flag when using a local file. Choose how to manage the track. Copy,
symlink, or move the track to the JBrowse directory. Or inPlace to leave track
alone
-n, --name=name Name of the track. Will be defaulted to the trackId if none specified
-t, --type=type Type of track, by default inferred from track file
--category=category Optional Comma separated string of categories to group tracks
--config=config Any extra config settings to add to a track. i.e '{"defaultRendering":
"density"}'
--indexFile=indexFile Optional index file for the track
--out=out synonym for target
--overwrite Overwrites existing track if it shares the same trackId
--protocol=protocol [default: uri] Force protocol to a specific value
--skipCheck Skip check for whether or not the file or URL exists or if you are in a JBrowse
directory
--subDir=subDir when using --load a file, output to a subdirectory of the target dir
--target=target path to config file in JB2 installation to write out to.
--trackId=trackId trackId for the track, by default inferred from filename, must be unique
throughout config
EXAMPLES
$ jbrowse add-track /path/to/my.bam --load copy
$ jbrowse add-track /path/to/my.bam --target /path/to/jbrowse2/installation/config.json --load symlink
$ jbrowse add-track https://mywebsite.com/my.bam
$ jbrowse add-track /path/to/my.bam --type AlignmentsTrack --name 'New Track' --load move
$ jbrowse add-track /path/to/my.bam --trackId AlignmentsTrack1 --load inPlace --overwrite
$ jbrowse add-track /path/to/my.bam --config '{"defaultRendering": "density"}'

See code: src/commands/add-track.ts

jbrowse add-track-json TRACK

Add a track configuration directly from a JSON hunk to the JBrowse 2 configuration

USAGE
$ jbrowse add-track-json TRACK
ARGUMENTS
TRACK track JSON file or command line arg blob
OPTIONS
-u, --update update the contents of an existing track, matched based on trackId
--out=out synonym for target
--target=target path to config file in JB2 installation directory to write out to.
Creates ./config.json if nonexistent
EXAMPLES
$ jbrowse add-track-json track.json
$ jbrowse add-track-json track.json --update

See code: src/commands/add-track-json.ts

jbrowse admin-server

Start up a small admin server for JBrowse configuration

USAGE
$ jbrowse admin-server
OPTIONS
-h, --help show CLI help
-p, --port=port Specifified port to start the server on;
Default is 9090.
--out=out synonym for target
--skipCheck Don't check whether or not you are in a JBrowse directory
--target=target path to config file in JB2 installation directory to write out to.
Creates ./config.json if nonexistent
EXAMPLES
$ jbrowse admin-server
$ jbrowse admin-server -p 8888

See code: src/commands/admin-server.ts

jbrowse create LOCALPATH

Downloads and installs the latest JBrowse 2 release

USAGE
$ jbrowse create LOCALPATH
ARGUMENTS
LOCALPATH Location where JBrowse 2 will be installed
OPTIONS
-f, --force Overwrites existing JBrowse 2 installation if present in path
-h, --help show CLI help
-l, --listVersions Lists out all versions of JBrowse 2
-t, --tag=tag Version of JBrowse 2 to install. Format is @jbrowse/web@0.0.1.
Defaults to latest
-u, --url=url A direct URL to a JBrowse 2 release
EXAMPLES
$ jbrowse create /path/to/new/installation
$ jbrowse create /path/to/new/installation --force
$ jbrowse create /path/to/new/installation --url url.com/directjbrowselink.zip
$ jbrowse create /path/to/new/installation --tag @jbrowse/web@0.0.1
$ jbrowse create --listVersions # Lists out all available versions of JBrowse 2

See code: src/commands/create.ts

jbrowse help [COMMAND]

display help for jbrowse

USAGE
$ jbrowse help [COMMAND]
ARGUMENTS
COMMAND command to show help for
OPTIONS
--all see all commands in CLI

See code: @oclif/plugin-help

jbrowse set-default-session

Set a default session with views and tracks

USAGE
$ jbrowse set-default-session
OPTIONS
-c, --currentSession List out the current default session
-h, --help show CLI help
-n, --name=name [default: New Default Session] Give a name for the default session
-s, --session=session set path to a file containing session in json format
-t, --tracks=tracks Track id or track ids as comma separated string to put into default session
-v, --view=view View type in config to be added as default session, i.e LinearGenomeView, CircularView,
DotplotView.
Must be provided if no default session file provided
--out=out synonym for target
--target=target path to config file in JB2 installation directory to write out to
--viewId=viewId Identifier for the view. Will be generated on default
EXAMPLES
$ jbrowse set-default-session --session /path/to/default/session.json
$ jbrowse set-default-session --target /path/to/jb2/installation/config.json --view LinearGenomeView --tracks track1,
track2, track3
$ jbrowse set-default-session --view LinearGenomeView, --name newName --viewId view-no-tracks
$ jbrowse set-default-session --currentSession # Prints out current default session

See code: src/commands/set-default-session.ts

jbrowse upgrade [LOCALPATH]

Upgrades JBrowse 2 to latest version

USAGE
$ jbrowse upgrade [LOCALPATH]
ARGUMENTS
LOCALPATH [default: .] Location where JBrowse 2 is installed
OPTIONS
-h, --help show CLI help
-l, --listVersions Lists out all versions of JBrowse 2
-t, --tag=tag Version of JBrowse 2 to install. Format is @jbrowse/web@0.0.1.
Defaults to latest
-u, --url=url A direct URL to a JBrowse 2 release
EXAMPLES
$ jbrowse upgrade # Upgrades current directory to latest jbrowse release
$ jbrowse upgrade /path/to/jbrowse2/installation
$ jbrowse upgrade /path/to/jbrowse2/installation --tag @jbrowse/web@0.0.1
$ jbrowse upgrade --listVersions # Lists out all available versions of JBrowse 2
$ jbrowse upgrade --url https://sample.com/jbrowse2.zip

See code: src/commands/upgrade.ts

Debugging

Debug logs (provided by debug) can be printed by setting the DEBUG environment variable. Setting DEBUG=* will print all debug logs. Setting DEBUG=jbrowse* will print only logs from this tool, and setting e.g. DEBUG=jbrowse:add-assembly will print only logs from the add-assembly command.

Developer guide

In this Developer Guide, will introduce the JBrowse 2 ecosystem from the developer's point of view. We'll examine the core concepts of how code is packaged and structured, and then go over how to create new plugins and pluggable elements.

Introduction and overview

Let's get a high-level view of the JBrowse 2 ecosystem.

Products and plugins

The JBrowse 2 ecosystem has two main type of top-level artifacts that are published on their own: products and plugins.

Architecture diagram of JBrowse 2, showing how plugins encapsulate views (e.g. LinearGenomeView, DotplotView etc.), tracks (AlignmentsTrack, VariantTrack, etc.), data adapters (BamAdapter, VcfTabixAdapter, etc.) and other logic like mobx state tree autoruns that add logic to other parts of the app (e.g. adding context menus)

A "product" is an application of some kind that is published on its own (a web app, an electron app, a CLI app, etc). jbrowse-web, jbrowse-desktop, and jbrowse-cli are products.

A "plugin" is a package of functionality that is designed to "plug in" to a product at runtime to add functionality. These can be written and published by anyone, not just the JBrowse core team. Not all of the products use plugins, but most of them do.

Also, most of the products are pretty standard in the way they are constructed. For example, jbrowse-web is a React web application that is made with Create React App (CRA), and jbrowse-cli is a command-line tool implemented with OCLIF.

This figure summarizes the general architecture of our state model and React component tree

What's in a plugin

A plugin is an independently distributed package of code that is designed to "plug in" to a JBrowse application.

It's implemented as a class that extends @jbrowse/core/Plugin. It gets instantiated by the application that it plugs into, and it has an install method and a configure method that the application calls. This class is distributed as a webpack bundle that exports it to a namespace on the browser's window object specifically for JBrowse plugins1.

It's common for a plugin to use have its configure method set up mobx autoruns or reactions that react to changes in the application's state to modify its behavior.

Plugins often also have their install method add "pluggable elements" into the host JBrowse application. This is how plugins can add new kinds of views, tracks, renderers, and so forth.

Pluggable elements

Pluggable elements are basic "extension points" that you can customize in JBrowse 2 plugins

The pluggable types that we have in JBrowse 2 are

  • Data adapters
  • Track types
  • Renderer types
  • Widgets
  • RPC calls
  • View types

In additional to creating plugins that create new data adapters, track types, etc. note that you can also wrap the behavior of another track so these elements are composable

For example we can have adapters that perform calculations on the results of another adapter, views that contains other subviews, and tracks that contain other tracks, leading to a lot of interesting behavior. Details and examples below

Data adapters

Data adapters basically are parsers for a given data format. We will review what data adapters the alignments plugin has (to write your own data adapter, see creating data adapters)

Example data adapters: the @jbrowse/plugin-alignments plugin creates multiple data adapter types

  • BamAdapter - This adapter uses the @gmod/bam NPM module, and adapts it for use by the browser.
  • CramAdapter - This adapter uses the @gmod/cram NPM module. Note that CramAdapter also takes a sequenceAdapter as a subadapter configuration, and uses getSubAdapter to instantiate it
  • SNPCoverageAdapter - this adapter takes a BamAdapter or CramAdapter as a subadapter, and calculates feature coverage from it

Renderers

Renderers are a new concept in JBrowse 2, and are related to the concept of server side rendering (SSR), but can be used not just on the server but also in contexts like the web worker (e.g. the webworker can draw the features to an OffscreenCanvas). For more info see creating renderers

Example renderers: the @jbrowse/plugin-alignments exports several renderer types

  • PileupRenderer - a renderer type that renders Pileup type display of alignments fetched from the BamAdapter/CramAdapter
  • SNPCoverageRenderer - a renderer that draws the coverage. Note that this renderer derives from the wiggle renderer, but does the additional step of drawing the mismatches over the coverage track

Track types

Track types are a high level type that controls how features are drawn. In most cases, a track combines a renderer and an adapter, and can do additional things like

  • Control what widget pops up on feature click
  • Add extra menu items to the track menu
  • Create subtracks (See AlignmentsTrack)
  • Choose "static-blocks" rendering styles, which keeps contents stable while the user scrolls, or "dynamic-blocks" that update on each scroll

Example tracks: the @jbrowse/plugin-alignments exports multiple track types

  • SNPCoverageTrack - this track type actually derives from the WiggleTrack type
  • PileupTrack - a track type that draws alignment pileup results
  • AlignmentsTrack - combines SNPCoverageTrack and PileupTrack as "subtracks"

Widgets

Widgets are custom info panels that can show up in side panels, modals, or other places in an app

Widgets can do multiple types of things including

  • Configuration widget
  • Feature detail widget
  • Add track widget
  • Add connection widget
  • etc.

These widgets can be extended via plugins, so for example, the @jbrowse/plugin-alignments extends the BaseFeatureDetailWidget to have custom display of the alignments

  • AlignmentsFeatureDetailWidget - this provides a custom widget for viewing the feature details of alignments features that customizes the basic feature detail widget

View types

Creating view types is one of the most powerful features of JBrowse 2, because it allows us to put entirely different visualizations in the same context as the standard linear-genome-view.

We have demonstrated a couple new view types in JBrowse 2 already including

  • LinearGenomeView - the classic linear view of a genome
  • CircularView - a Circos-style whole genome view
  • DotplotView - a comparative 2-D genome view
  • SvInspectorView - superview containing CircularView and SpreadsheetView subviews
  • And more!

We think the boundaries for this are just your imagination, and there can also be interplay between view types e.g. popup dotplot from a linear view, etc.

RPC methods

Plugins can register their own RPC methods, which can allow them to offload custom behaviors to a web-worker or server side process. The Wiggle track for example registers WiggleGetGlobalStats and WiggleGetMultiRegionStats

MenuItems

You can add menus or add items to existing menus in several places.

A MenuItem object defines the menu item's text, icon, action, and other attributes.

Types of MenuItems:

  • Normal: a standard menu item that performs an action when clicked
  • Checkbox: a menu item that has a checkbox
  • Radio: a menu item that has a radio button icon
  • Divider: a horizontal line (not clickable) that can be used to visually divide menus
  • SubHeader: text (not clickable) that can be used to visually label a section of a menu
  • SubMenu: contains menu items, for making nested menus
NameDescription
typeOptions are 'normal', 'radio', 'checkbox', 'subMenu', 'subHeader', or 'divider'. If not provided, defaults to 'normal', unless a subMenu attribute is present, in which case it defaults to 'subMenu'.
labelThe text for the menu item. Not applicable to 'divider', required for all others.
subLabelAdditional descriptive text for the menu item. Not applicable to 'divider' or 'subHeader', optional for all others.
iconAn icon for the menu item. Must be compatible with Material-UI's Icons. Not applicable to 'divider' or 'subHeader', optional for all others.
disabledWhether or not the menu item is disabled (meaning grayed out and not clickable). Not applicable to 'divider' or 'subHeader', optional for all others.
checkedWhether or not the checkbox or radio button are selected. Only applicable to 'radio' and 'checkbox'
onClickCallback of action to perform on click. Function signature is (session) => undefined. Required for 'normal', 'radio', and 'checkbox', not applicable to any others.
subMenuAn array of menu items. Applicable only to 'subMenu'.

As an example, the here is an array of MenuItems and the resulting menu:

;[
{
label: 'Normal menu item',
icon: AddIcon,
onClick: () => {},
},
{
label: 'Normal',
subLabel: 'with subLabel',
icon: AddIcon,
onClick: () => {},
},
{
label: 'Disabled menu item',
disabled: true,
icon: AddIcon,
onClick: () => {},
},
{
type: 'radio',
label: 'Radio checked',
checked: true,
onClick: () => {},
},
{
type: 'radio',
label: 'Radio unchecked',
checked: false,
onClick: () => {},
},
{
type: 'checkbox',
label: 'Checkbox checked',
checked: true,
onClick: () => {},
},
{
type: 'checkbox',
label: 'Checkbox unchecked',
checked: false,
onClick: () => {},
},
{ type: 'divider' },
{ type: 'subHeader', label: 'This is a subHeader' },
{
label: 'SubMenu',
subMenu: [
{
label: 'SubMenu item one',
onClick: () => {},
},
{
label: 'SubMenu item two',
onClick: () => {},
},
],
},
]

Demo menu Figure showing all the options for track menus, generated by the code listing

Adding a top-level menu

These are the menus that appear in the top bar of JBrowse Web and JBrowse Desktop. By default there are File and Help menus. You can add your own menu, or you can add menu items or sub-menus to the existing menus and sub-menus.

File menu with submenu

In the above screenshot, the File menu has several items and an Add sub-menu, which has more items. You can have arbitrarily deep sub-menus.

You add menus in the configure method of your plugin. Not all JBrowse products will have to-level menus, though. JBrowse Web and JBrowse Desktop have them, but something like JBrowse Linear View (which is an just a single view designed to be embedded in another page) does not. This means you need to check whether or not menus are supported using isAbstractMenuManager in the configure method. This way the rest of the plugin will still work if there is not a menu. Here's an example that adds an "Open My View" item to the File -> Add menu.

import Plugin from '@jbrowse/core/Plugin'
import { isAbstractMenuManager } from '@jbrowse/core/util'
import InfoIcon from '@material-ui/icons/Info'
class MyPlugin extends Plugin {
name = 'MyPlugin'
install(pluginManager) {
// install MyView here
}
configure(pluginManager) {
if (isAbstractMenuManager(pluginManager.rootModel)) {
pluginManager.rootModel.appendToSubMenu(['File', 'Add'], {
label: 'Open My View',
icon: InfoIcon,
onClick: session => {
session.addView('MyView', {})
},
})
}
}
}

This example uses rootModel.appendToSubMenu. These are all the menu-manipulation methods available on the root model:

appendMenu

Add a top-level menu

Parameters
NameDescription
menuNameName of the menu to insert.
Return Value

The new length of the top-level menus array

insertMenu

Insert a top-level menu

Parameters
NameDescription
menuNameName of the menu to insert.
positionPosition to insert menu. If negative, counts from the end, e.g. insertMenu('My Menu', -1) will insert the menu as the second-to-last one.
Return Value

The new length of the top-level menus array

appendToMenu

Add a menu item to a top-level menu

Parameters
NameDescription
menuNameName of the top-level menu to append to.
menuItemMenu item to append.
Return Value

The new length of the menu

insertInMenu

Insert a menu item into a top-level menu

Parameters
NameDescription
menuNameName of the top-level menu to insert into.
menuItemMenu item to insert.
positionPosition to insert menu item. If negative, counts from the end, e.g. insertMenu('My Menu', -1) will insert the menu as the second-to-last one.
Return Value

The new length of the menu

appendToSubMenu

Add a menu item to a sub-menu

Parameters
NameDescription
menuPathPath to the sub-menu to add to, starting with the top-level menu (e.g. ['File', 'Insert']).
menuItemMenu item to append.
Return Value

The new length of the sub-menu

insertInSubMenu

Insert a menu item into a sub-menu

Parameters
NameDescription
menuPathPath to the sub-menu to add to, starting with the top-level menu (e.g. ['File', 'Insert']).
menuItemMenu item to insert.
positionPosition to insert menu item. If negative, counts from the end, e.g. insertMenu('My Menu', -1) will insert the menu as the second-to-last one.
Return Value

The new length of the sub-menu

Adding menu items to a custom track

If you create a custom track, you can populate the track menu items in it using the trackMenuItems property in the track model. For example:

types
.model({
// model
})
.views(self => ({
get trackMenuItems() {
return [
{
label: 'Menu Item',
icon: AddIcon,
onClick: () => {},
},
]
},
}))

Adding track context menu items

When you right-click in a linear track, a context menu will appear if there are any menu items defined for it. It's possible to add items to that menu, and you can also have different menu items based on if the click was on a feature or not, and based on what feature is clicked. This is done by adding a callback that takes the feature and track and returns a list of menu items to add based on those. This has to be done via a mobx autorun because it needs to add the callback to tracks after they are created. Here is an example:

class SomePlugin extends Plugin {
name = 'SomePlugin'
install(pluginManager) {
// install some stuff
}
configure(pluginManager) {
const menuItemCallback = (feature, track) => {
const menuItem = {
label: 'Some menu item',
icon: SomeIcon,
onClick: session => {
// do some stuff
},
}
return [menuItem]
}
const session = pluginManager.rootModel?.session
autorun(() => {
const views = session?.views
views.forEach(view => {
if (view.type === 'LinearGenomeView') {
const { tracks } = view
tracks.forEach(track => {
if (
track.type === 'VariantTrack' &&
!track.additionalContextMenuItemCallbacks.includes(
menuItemCallback,
)
) {
track.addAdditionalContextMenuItemCallback(menuItemCallback)
}
})
}
})
})
}
}

Monorepo code organization

JBrowse 2 code is organized as a monorepo using lerna and yarn workspaces. Using a monorepo means that instead of separate GitHub repositories for each piece of JBrowse, they are all in a single place and can share code easily. In the top level of the repository there are two directories, packages/ and products/ that each contain multiple packages.

Each "package" is an npm-style (i.e. contains package.json) package. The packages in packages/ are core code, development tools, etc. The packages in plugins/ are JBrowse plugins. Most of JBrowse is written as plugins, so that is where most of the code is. The packages in products/ are user-facing products, such as JBrowse Web, JBrowse Desktop, JBrowse CLI, etc.

Monorepo packages

The following is a summary of some of the individual packages in the monorepo. It's not a comprehensive list, but will hopefully help familiarize you with how the code is organized.

products/jbrowse-web

This is the full JBrowse Web app. It is built using create-react-app.

It includes many other packages as core plugins, can load other plugins at runtime, and more.

It also currently holds the "integration tests" that we use for our code in products/jbrowse-web/src/tests.

products/jbrowse-desktop

JBrowse Desktop is our essentially the same as JBrowse Web, but packaged with electron into a desktop app. This gives it the ability to easily load and save tracks based on files on your local filesystem. It also has save sessions locally, and works offline.

products/website

This provides the docusaurus website with docs, blog, and pdf documentation

plugins/alignments

This package provides the "alignments" related features including

  • BamAdapter - our BAM parser that wraps @gmod/bam NPM module
  • CramAdapter - our CRAM parser that wraps the @gmod/cram NPM module
  • PileupTrack type - draws alignments as boxes in a "pileup" style view
  • SNPCoverageTrack - draws calculated coverage with mismatches drawn over the coverage
  • AlignmentsTrack - a "supertrack" which contains a PileupTrack and SNPCoverageTrack "subtracks"
  • AlignmentsFeatureWidget for alignments features
plugins/variants/

Provides variant features including

  • VCF tabix parser
  • VariantFeatureWidget
  • VariantTrack that is basically just a normal track, but has logic to popup the VariantFeatureWidget on feature click
plugins/hic

This provides a HicAdapter based on the .hic file format (ref)

Also a track type and renderer to visualize these

plugins/bed

Provides two bed related data adapters

  • BigBedAdapter
  • BedTabixAdapter

These can be used with the SvgFeatureRenderer

plugins/wiggle

Provides wiggle track types with different types of rendering formats including

  • XYPlotRenderer
  • LinePlotRenderer
  • DensityRenderer

The WiggleTrack type can swap out these different rendering types, and calculates stats such as max and min score over a region before the region is rendered

plugins/svg

This is the main gene glyphs, which are rendered using SVG

General usage of this involves referencing the SvgFeatureRenderer

plugins/spreadsheet-view

This provides a spreadsheet-in-the-browser that can be used as a data backend to power other views

plugins/circular-view

This provides our 'Circos-style' whole-genome overview of data, especially genomic translocations

plugins/sv-inspector

This is a "superview" type that contains a circular and spreadsheet view as child views

Plugin Build system

Plugins may be built as separate packages that can be distributed on NPM. In order to streamline development and avoid having to build every plugin before developing on e.g. JBrowse Web, however, the package.json's "main" entry by default points to the un-built code (e.g. src/index.ts). JBrowse Web then takes care of building the plugins itself (see products/jbrowse-web/rescripts/yarnWorkspacesRescript.js).

When you want to use a built plugin, you can run yarn useDist in the plugin's package.json, and then run yarn useSrc to restore it when you're done. As an example, the root-level yarn build that builds all the packages does this to build all the plugins and then build JBrowse Web and JBrowse Desktop using the built plugins.

Configuration model concepts

Configuration slot types

Our configuration system is "typed" to facilitate graphical editing of the configuration. Each configuration has a "schema" that lists what "configuration slots" it has. Each configuration slot has a name, description, a type, and a value.

Here is a mostly comprehensive list of config types

  • stringEnum - allows assigning one of a limited set of entries, becomes a dropdown box in the GUI
  • color - allows selecting a color, becomes a color picker in the GUI
  • number - allows entering any numeric value
  • string - allows entering any string
  • integer - allows entering a integer value
  • boolean
  • frozen - an arbitrary JSON can be specified in this config slot, becomes textarea in the GUI
  • fileLocation - refers to a URL, local file path on desktop, or file blob object in the browser
  • text - allows entering a string, becomes textarea in the GUI
  • stringArray - allows entering a list of strings, becomes a "todolist" style editor in the GUI where you can add or delete things
  • stringArrayMap - allows entering a list of key-value entries

Let's examine the PileupRenderer configuration as an example.

Example config with multiple slot types

This PileupRenderer config contains an example of several different slot types

import { types } from 'mobx-state-tree'
export default ConfigurationSchema('PileupRenderer', {
color: {
type: 'color',
description: 'the color of each feature in a pileup alignment',
defaultValue: `function(feature) {
var s = feature.get('strand');
return s === -1 ? '#8F8FD8': '#EC8B8B'
}`,
functionSignature: ['feature'],
},
displayMode: {
type: 'stringEnum',
model: types.enumeration('displayMode', ['normal', 'compact', 'collapse']),
description: 'Alternative display modes',
defaultValue: 'normal',
},
minSubfeatureWidth: {
type: 'number',
description: `the minimum width in px for a pileup mismatch feature. use for
increasing mismatch marker widths when zoomed out to e.g. 1px or
0.5px`,
defaultValue: 0,
},
maxHeight: {
type: 'integer',
description: 'the maximum height to be used in a pileup rendering',
defaultValue: 600,
},
})

Accessing config values

So instead of accessing config.displayMode, we say

readConfObject(config, 'displayMode')

You might also see in the code like this

getConf(track, 'maxHeight')

Which would be equivalent to calling

readConfObject(track.configuration, 'maxHeight')`

Using config callbacks

Config callbacks allow you to have a dynamic color based on some function logic you provide. All config slots can actually become config callback. The arguments that are given to the callback are listed by the 'functionSignature' but must be provided by the calling code (the code reading the config slot). To pass arguments to the a callback we say

readConfObject(config, 'color', [feature])

That implies the color configuration callback will be passed a feature, so the config callback can be a complex function determining the color to use based on various feature attributes

Example of a config callback

If you had an variant track in your config, and wanted to make a custom config callback for color, it might look like this

{
"type": "VariantTrack",
"trackId": "myvcf",
"name": "My variants",
"assemblyNames": ["h19"],
"category": ["VCF"],
"adapter": {
"type": "VcfTabixAdapter",
"vcfGzLocation": {
"uri": "test_data/volvox/volvox.filtered.vcf.gz"
},
"index": {
"location": {
"uri": "test_data/volvox/volvox.filtered.vcf.gz.tbi"
}
}
},
"renderers": {
"SvgFeatureRenderer": {
"type": "SvgFeatureRenderer",
"color": "function(feat) { return feat.get('type')==='SNV'?'green':'purple' }"
}
}
}

This draws all SNV (single nucleotide variants) as green, and other types as purple (insertion, deletion, other structural variant). Note that JSON format doesn't allow fancy multiline

Configuration internals

A configuration is a type of mobx-state-tree model, in which leaf nodes are ConfigSlot types, and other nodes are ConfigurationSchema types.

Schema
/ | \
Slot Schema Slot
| \
Slot Slot

Configurations are all descendants of a single root configuration, which is root.configuration.

Configuration types should always be created by the ConfigurationSchema factory, e.g.

import { ConfigurationSchema } from '@jbrowse/core/utils/configuration'
const ThingStateModel = types.model('MyThingsState', {
foo: 42,
configuration: ConfigurationSchema('MyThing', {
backgroundColor: {
defaultValue: 'white',
type: 'string',
},
}),
})

An example of a config schema with a sub-config schema is the BamAdapter, with the index sub-config schema

ConfigurationSchema(
'BamAdapter',
{
bamLocation: {
type: 'fileLocation',
defaultValue: { uri: '/path/to/my.bam' },
},
// this is a sub-config schema
index: ConfigurationSchema('BamIndex', {
indexType: {
model: types.enumeration('IndexType', ['BAI', 'CSI']),
type: 'stringEnum',
defaultValue: 'BAI',
},
location: {
type: 'fileLocation',
defaultValue: { uri: '/path/to/my.bam.bai' },
},
}),
},
{ explicitlyTyped: true },
)

Reading the sub-config schema is as follows

const indexType = readConfObject(config, ['index', 'indexType'])

Creating data adapters

What is a data adapter

A data adapter is essentially a class that parses your data type and returns features that jbrowse will draw

Sometimes, a data adapter can be implemented by itself, e.g. if you are adapting a storeclass that returns genes, then you can use our standard track types for that. If you are making a data adapter for some custom type of data that also needs a custom type of drawing, you may need to implement a data adapter along with a track type and/or renderer

Skeleton of a data adapter

So we see basically something like this, this is stripped down for simplicity

class MyAdapter extends BaseFeatureDataAdapter {
constructor(config) {
// config
}
async getRefNames() {
// return ref names used in your data adapter, used for refname renaming
}
getFeatures(region) {
// return features from your data adapter, using rxjs observable
}
freeResources(region) {
// can be empty
}
}

So to make a data adapter, you implement the getRefNames function (optional), the getFeatures function (returns an rxjs observable stream of features, discussed below) and freeResources (optional)

Example data adapter

To take this a little slow let's look at each function individually

This is a more complete description of the class interface that you can implement

import { BaseFeatureDataAdapter } from '@jbrowse/core/data_adapters/BaseAdapter'
import SimpleFeature from '@jbrowse/core/util/simpleFeature'
import { readConfObject } from '@jbrowse/core/configuration'
import { ObservableCreate } from '@jbrowse/core/util/rxjs'
class MyAdapter extends BaseFeatureDataAdapter {
// @param config - a configuration object
// @param getSubAdapter - function to initialize additional subadapters
constructor(config, getSubAdapter) {
const fileLocation = readConfObject(config, 'fileLocation')
const subadapter = readConfObject(config, 'sequenceAdapter')
const sequenceAdapter = getSubAdapter(subadapter)
}
// @param region - { refName:string, start:number, end:number}
// @param options - { signal: AbortSignal, bpPerPx: number }
// @return an rxjs Observable
getFeatures(region, options) {
return ObservableCreate(async observer => {
try {
const myapi = await fetch(
'http://myservice/genes/${refName}/${start}-${end}',
)
if (result.ok) const features = await result.json()
features.forEach(feature => {
observer.next(
new SimpleFeature({
uniqueID: `${feature.chr}-${feature.start}-${feature.end}`,
refName: feature.chr,
start: feature.start,
end: feature.end,
}),
)
})
observer.complete()
} catch (e) {
observer.error(e)
}
})
}
async getRefNames() {
// returns the list of refseq names in the file, used for refseq renaming
// you can hardcode this if you know it ahead of time e.g. for your own
// remote data API or fetch this from your data file e.g. from the bam header
return ['chr1', 'chr2', 'chr3'] /// etc
}
freeResources(region) {
// optionally remove cache resources for a region
// can just be an empty function
}
}

What is needed from a data adapter

getRefNames

Returns the refNames that are contained in the file, this is used for "refname renaming" and is optional but highly useful in scenarios like human chromosomes which have, for example, chr1 vs 1.

Returning the refNames used by a given file or resource allows JBrowse to automatically smooth these small naming disparities over. See reference renaming

getFeatures

A function that returns features from the file given a genomic range query e.g. getFeatures(region, options), where region is an object like

The region contains

interface Region {
refName: string
start: number
end: number
originalRefName: string
assemblyName: string
}

The options can contain any number of things

interface Options {
bpPerPx: number
signal: AbortSignal
statusCallback: Function
headers: Record<string, string>
}
  • bpPerPx - number: resolution of the genome browser when the features were fetched
  • signal - can be used to abort a fetch request when it is no longer needed, from AbortController
  • statusCallback - not implemented yet but in the future may allow you to report the status of your loading operations
  • headers - set of HTTP headers as a JSON object

We return an rxjs Observable. This is similar to a JBrowse 1 getFeatures call, where we pass each feature to a featureCallback, tell it when we are done with finishCallback, and send errors to errorCallback, except we do all those things with the Observable

Here is a "conversion" of JBrowse 1 getFeatures callbacks to JBrowse 2 observable calls

  • featureCallback(new SimpleFeature(...)) -> observer.next(new SimpleFeature(...))
  • finishCallback() -> observer.complete()
  • errorCallback(error) -> observer.error(error)
freeResources

This is uncommonly used, so most data adapters make this an empty function

Most data adapters in fact use an LRU cache to make resources go away over time instead of manually cleaning up resources

Creating a new plugin

JBrowse 2 plugins can be used to add new pluggable elements (views, tracks, data adapters, etc), and to modify behavior of the application by adding code that watches the application's state. For the full list of what kinds of pluggable element types plugins can add, see the pluggable elements page.

We will go over creating an example plugin. The first thing that we have is a src/index.js which exports a default class containing the plugin registration code

src/index.js

import AdapterType from '@jbrowse/core/pluggableElementTypes/AdapterType'
import Plugin from '@jbrowse/core/Plugin'
import { AdapterClass, configSchema } from './UCSCAdapter'
export default class UCSCPlugin extends Plugin {
name = 'UCSCPlugin'
install(pluginManager) {
pluginManager.addAdapterType(
() =>
new AdapterType({
name: 'UCSCAdapter',
configSchema,
AdapterClass,
}),
)
}
}

src/UCSCAdapter/index.ts

import {
ConfigurationSchema,
readConfObject,
} from '@jbrowse/core/configuration'
import { ObservableCreate } from '@jbrowse/core/util/rxjs'
import { BaseFeatureDataAdapter } from '@jbrowse/core/data_adapters/BaseAdapter'
import SimpleFeature from '@jbrowse/core/util/simpleFeature'
import stringify from 'json-stable-stringify'
export const configSchema = ConfigurationSchema(
'UCSCAdapter',
{
base: {
type: 'fileLocation',
description: 'base URL for the UCSC API',
defaultValue: {
uri: 'https://cors-anywhere.herokuapp.com/https://api.genome.ucsc.edu/',
},
},
track: {
type: 'string',
description: 'the track to select data from',
defaultValue: '',
},
},
{ explicitlyTyped: true },
)
export class AdapterClass extends BaseFeatureDataAdapter {
constructor(config) {
super(config)
this.config = config
}
getFeatures(region) {
const { assemblyName, start, end, refName } = region
return ObservableCreate(async observer => {
const { uri } = readConfObject(this.config, 'base')
const track = readConfObject(this.config, 'track')
try {
const result = await fetch(
`${uri}/getData/track?` +
`genome=${assemblyName};track=${track};` +
`chrom=${refName};start=${start};end=${end}`,
)
if (result.ok) {
const data = await result.json()
data[track].forEach(feature => {
observer.next(
new SimpleFeature({
...feature,
start: feature.chromStart,
end: feature.chromEnd,
refName: feature.chrom,
uniqueId: stringify(feature),
}),
)
})
observer.complete()
}
} catch (e) {
observer.error(e)
}
})
}
async getRefNames() {
const arr = []
for (let i = 0; i < 23; i++) {
arr.push(`chr${i}`)
}
return arr
}
freeResources() {}
}

Adding this track to our configuration

We can create a track.json like this

track.json

{
"type": "BasicTrack",
"trackId": "genehancer_ucsc",
"name": "UCSC GeneHancer",
"assemblyNames": ["hg38"],
"adapter": {
"type": "UCSCAdapter",
"track": "geneHancerInteractionsDoubleElite"
},
"renderer": {
"type": "SvgFeatureRenderer"
}
}

Then use the jbrowse CLI tool add-track-json

jbrowse add-track-json file.json

This will automatically add this track to the tracks array of our config.json

Alternatively, we can manually edit this JSON into the config.json.

When we open this track, we should see the GeneHancer regions are drawn as orange blocks.

Creating a custom renderer type

Let's say we want to create a track that connects a gene to it's enhancer. On UCSC the GeneHancer tracks do exactly this. An instance of the UCSC with the GeneHancer tracks is here.

We can see data that we can get for the GeneHancer interactions from the UCSC API like this

curl 'https://api.genome.ucsc.edu/getData/track?genome=hg19;\
track=geneHancerInteractionsDoubleElite;chrom=chr1;start=750000;\
end=505700000'|less

Given that the functionality of rendering arcs is so distinct from UCSC API adaptation, we can actually make this a new plugin. Let's imagine starting a new plugin from scratch again

src/index.js

import Plugin from '@jbrowse/core/Plugin'
import PluginManager from '@jbrowse/core/PluginManager'
import ArcRenderer, {
configSchema as ArcRendererConfigSchema,
ReactComponent as ArcRendererReactComponent,
} from './ArcRenderer'
export default class ArcRendererPlugin extends Plugin {
name = 'ArcPlugin'
install(pluginManager) {
pluginManager.addRendererType(
() =>
// @ts-ignore error "expected 0 arguments, but got 1"?
new ArcRenderer({
name: 'ArcRenderer',
ReactComponent: ArcRendererReactComponent,
configSchema: ArcRendererConfigSchema,
}),
)
}
}

src/ArcRenderer/index.js

import React from 'react'
// prettier-ignore
import {
ServerSideRendererType
} from '@jbrowse/core/pluggableElementTypes/renderers/ServerSideRendererType'
import {
ConfigurationSchema,
readConfObject,
} from '@jbrowse/core/configuration'
import { PrerenderedCanvas } from '@jbrowse/core/ui'
import { bpSpanPx } from '@jbrowse/core/util'
import {
createCanvas,
createImageBitmap,
} from '@jbrowse/core/util/offscreenCanvasPonyfill'
// Our config schema for arc track will be basic, include just a color
export const configSchema = ConfigurationSchema(
'ArcRenderer',
{
color: {
type: 'color',
description: 'color for the arcs',
defaultValue: 'darkblue',
},
},
{ explicitlyTyped: true },
)
// This ReactComponent is the so called "rendering" which is the component
// that contains the contents of what was rendered.
export const ReactComponent = props => {
return (
<div style={{ position: 'relative' }}>
<PrerenderedCanvas {...props} />
</div>
)
}
// Our ArcRenderer class does the main work in it's render method
// which draws to a canvas and returns the results in a React component
export default class ArcRenderer extends ServerSideRendererType {
async render(renderProps) {
const {
features,
config,
regions,
bpPerPx,
highResolutionScaling,
} = renderProps
const region = regions[0]
const width = (region.end - region.start) / bpPerPx
const height = 500
const canvas = createCanvas(
width * highResolutionScaling,
height * highResolutionScaling,
)
const ctx = canvas.getContext('2d')
ctx.scale(highResolutionScaling, highResolutionScaling)
for (const feature of features.values()) {
const [left, right] = bpSpanPx(
feature.get('start'),
feature.get('end'),
region,
bpPerPx,
)
ctx.beginPath()
ctx.strokeStyle = readConfObject(config, 'color', [feature])
ctx.lineWidth = 3
ctx.moveTo(left, 0)
ctx.bezierCurveTo(left, 200, right, 200, right, 0)
ctx.stroke()
}
const imageData = await createImageBitmap(canvas)
const element = React.createElement(
this.ReactComponent,
{
...renderProps,
width,
height,
imageData,
},
null,
)
return { element, imageData, width, height }
}
}

The above code is relatively simple but it is fairly quirky. Here are some notes:

  • renderers can be run in offscreen or even a node.js canvas, so we do not assume the document.createElement exists to create our canvas, instead using a utility function that makes a OffscreenCanvas or node-canvas (depends on context, e.g. webworker or node.js)
  • the "rendering" component contains the results of our renderer. in this case it delegates to the PrerenderedCanvas component, a component we use in other places throughout the codebase

Bringing the two together

We can bring these two contexts together with a new track in our config.json. Remember our previous track.json? Now we can edit it to use our own ArcRenderer

track.json

{
"type": "BasicTrack",
"trackId": "genehancer_ucsc",
"name": "UCSC GeneHancer",
"assemblyNames": ["hg38"],
"adapter": {
"type": "UCSCAdapter",
"track": "geneHancerInteractionsDoubleElite"
},
"renderer": {
"type": "ArcRenderer"
}
}

Then add the track

jbrowse add-track-json track.json --update

Creating custom renderers

What is a renderer

In JBrowse 1, a track type typically would directly call the data parser and do it's own rendering. In JBrowse 2, the data parsing and rendering is offloaded to a web-worker or other RPC. This allows things to be faster in many cases. This is conceptually related to "server side rendering" or SSR in React terms.

Conceptual diagram of how a track calls a renderer using the RPC

Important note: you can make custom tracks types that do not use this workflow, but it is a built in workflow that works well for the core track types in JBrowse 2.

How to create a new renderer

The fundamental aspect of creating a new renderer is creating a class that implements the "render" function. A renderer is actually a pair of a React component that contains the renderer's output, which we call the "rendering" and the renderer itself

class MyRenderer implements ServerSideRendererType {
render(props) {
const { width, height, regions, features } = props
const canvas = createCanvas(width, height)
const ctx = canvas.getContext('2d')
ctx.fillStyle = 'red'
ctx.drawRect(0, 0, 100, 100)
const imageData = createImageBitmap(canvas)
return {
element: React.createElement(this.ReactComponent, { ...props }),
imageData,
height,
width,
}
}
}

In the above simplified example, our renderer creates a canvas using width and height that are supplied via arguments, and draw a rectangle. We then return a React.createElement call which creates a "rendering" component that will contain the output

Note that the above canvas operations use an OffscreenCanvas for Chrome, or in other browsers serialize the drawing commands to be drawn in the main thread

What are the props passed to the renderer

The typical props that a renderer receives

export interface PileupRenderProps {
features: Map<string, Feature>
layout: { addRect: (featureId, leftBp, rightBp, height) => number }
config: AnyConfigurationModel
regions: Region[]
bpPerPx: number
height: number
width: number
highResolutionScaling: number
}

The layout is available on BoxRendererType renderers so that it can layout things in pileup format, and has an addRect function to get the y-coordinate to render your data at

The features argument is a map of feature ID to the feature itself. To iterate over the features Map, we can use an iterator or convert to an array

class MyRenderer extends ServerSideRendererType {
render(props) {
const { features, width, height } = props
// iterate over the ES6 map of features
for (const feature in features.values()) {
// render each feature to canvas or output SVG
}
// alternatively
const feats = Array.from(features.values())
feats.forEach(feat => {})
}
}

Adding custom props to the renderer

Note that track models themselves can extend this using their renderProps function

For example the WiggleTrack has code similar to this, which adds a scaleOpts prop that gets passed to the renderer

const model = types
.compose(
'WiggleTrack',
blockBasedTrack,
types.model({
type: types.literal('WiggleTrack'),
}),
)
.views(self => ({
get renderProps() {
return {
...self.composedRenderProps, // props that the blockBasedTrack adds,
...getParentRenderProps(self), // props that the view wants to add,
scaleOpts: {
domain: this.domain,
stats: self.stats,
autoscaleType: getConf(self, 'autoscale'),
scaleType: getConf(self, 'scaleType'),
inverted: getConf(self, 'inverted'),
},
}
},
}))

Rendering SVG

Our SVG renderer is an example, where it extends the existing built in renderer type with a custom ReactComponent only

export default class SVGPlugin extends Plugin {
install(pluginManager: PluginManager) {
pluginManager.addRendererType(
() =>
new BoxRendererType({
name: 'SvgFeatureRenderer',
ReactComponent: SvgFeatureRendererReactComponent,
configSchema: svgFeatureRendererConfigSchema,
}),
)
}
}

Then, we have our Rendering component just be plain React code. This is a highly simplified SVG renderer just to illustrate

export default function SvgFeatureRendering(props) {
const { width, features, regions, layout, bpPerPx } = props
const region = regions[0]
const feats = Array.from(features.values())
const height = readConfObject(config, 'height', [feature])
return (
<svg>
{feats.map(feature => {
// our layout determines at what y-coordinate to
// plot our feature, given all the other features
const top = layout.addRect(
feature.id(),
feature.get('start'),
feature.get('end'),
height,
)
const [left, right] = bpSpanPx(
feature.get('start'),
feature.get('end'),
region,
bpPerPx,
)
return <rect x={left} y={top} height={height} width={right - left} />
})}
</svg>
)
}

Notes:

  • The above SVG renderer is highly simplified but serves an example, but it shows that you can have a simple React component that leverages the existing BoxRendererType, so that you do not have to necessarily create your own renderer class
  • The renderers receive an array of regions to render, but if they are only equipped to handle one region at a time then they can select only rendering to regions[0]

Overriding the renderer's getFeatures method

Normally, it is sufficient to override the getFeatures function in your dataAdapter

If you want to drastically modify the feature fetching behavior, you can modify the renderer's getFeatures call

The base ServerSideRendererType class has a built-in getFeatures function that, in turn, calls your data adapter's getFeatures function, but if you need tighter control over how your data adapter's getFeatures method is called then your renderer. The Hi-C renderer type does not operate on conventional features and instead works with contact matrices, so the Hi-C renderer has a custom getFeatures function

import { toArray } from 'rxjs/operators'
class HicRenderer extends ServerSideRendererType {
async getFeatures(args) {
const { dataAdapter, regions } = args
const features = await dataAdapter
.getFeatures(regions[0])
.pipe(toArray())
.toPromise()
return features
}
}

Creating custom track types

At a high level the track types are just "ReactComponents" that contain rendered track contents. Oftentimes, for custom drawing, we create a renderer instead of a track, but here are some reasons you might want a custom track

  • Drawing custom things over the rendered content (e.g. drawing the Y-scale bar in the wiggle track)
  • Implementing custom track menu items (e.g. Show soft clipping in the alignments track)
  • Adding custom widgets (e.g. custom VariantFeatureWidget in variant track)
  • You want to bundle your renderer and adapter as a specific thing that is automatically initialized rather than the BasicTrack (which combines any adapter and renderer)

What does creating a track look like

When you create your plugin, you will add a cCreating a custom track is basically looks like this

You have your config schema

import { ConfigurationSchema } from '@jbrowse/core/configuration'
import { BasicTrackConfig } from '@jbrowse/plugin-linear-genome-view'
const configSchema = ConfigurationSchema(
'MyTrack',
{
color: {
type: 'string',
description: 'the color to use on my special features',
defaultValue: 'green',
},
},
{ baseConfiguration: BasicTrackConfig, explicitlyTyped: true },
)

What are the details of configSchema and stateModel

  • stateModel - a mobx-state-tree object that manages track logic
  • configSchema - a combination of a "stateModel" and a "configSchema"

The state model is often implemented as a composition of the "base track" and some custom logic

import { observer } from 'mobx-react'
import { types } from 'mobx-state-tree'
import { BlockBasedTrack } from '@jbrowse/plugin-linear-genome-view'
// A component which changes color when you click on it
// Note that this track is an observer, so it automatically re-renders
// when something inside the track model changes e.g. model.hasTheBellRung
const BackgroundChangeTrack = observer(props => {
const { model } = props
return (
<div
style={{ backgroundColor: model.hasTheBellRung ? 'red' : 'green' }}
onClick={() => model.ringTheBell()}
>
<BlockBasedTrack {...props} />
</div>
)
})
// A track state model that implements the logic for changing the
// background color on user click
return types.compose(
'BackgroundChangeTrack',
BaseTrack,
types
.model({
hasTheBellRung: false,
})
.volatile(() => ({
ReactComponent: MyComponent,
}))
.actions(self => ({
ringTheBell() {
self.hasTheBellRung = true
},
})),
)

This custom track type is fairly silly, but it shows us that our "track" can really be any React component that we want it to, and that we can control some logical state of the track by using mobx-state-tree

Putting it all together

Here is a complete plugin that creates it's ReactComponent, configSchema, stateModel, and Plugin class in a single file. You are of course welcome to split things up into different files in your own plugins :)

src/index.js

import { observer } from 'mobx-react'
import { types } from 'mobx-state-tree'
import { BlockBasedTrack } from '@jbrowse/plugin-linear-genome-view'
import { ConfigurationSchema } from '@jbrowse/core/configuration'
import { BasicTrackConfig } from '@jbrowse/plugin-linear-genome-view'
import Plugin from '@jbrowse/core/Plugin'
const BackgroundChangeTrack = observer(props => {
const { model } = props
return (
<div
style={{ backgroundColor: model.hasTheBellRung ? 'red' : 'green' }}
onClick={() => model.ringTheBell()}
>
<BlockBasedTrack {...props} />
</div>
)
})
const stateModel = types.compose(
'BackgroundChangeTrack',
BaseTrack,
types
.model({
hasTheBellRung: false,
})
.volatile(() => ({
ReactComponent: MyComponent,
}))
.actions(self => ({
ringTheBell() {
self.hasTheBellRung = true
},
})),
)
const configSchema = ConfigurationSchema(
'MyTrack',
{
color: {
type: 'string',
description: 'the color to use on my special features',
defaultValue: 'green',
},
},
{ baseConfiguration: BasicTrackConfig, explicitlyTyped: true },
)
export default class MyPlugin extends Plugin {
install(pluginManager) {
pluginManager.addTrackType(() => {
return new TrackType({
name: 'MyTrack',
compatibleView: 'LinearGenomeView', // this is the default
configSchema,
stateModel,
})
})
}
}

FAQ

General

What technologies does JBrowse 2 use
  • React
  • mobx-state-tree
  • web-workers
  • Typescript
  • Electron (for desktop specifically)
What is special about JBrowse 2

One thing that makes JBrowse 2 special is that we can create new view types via our plugin system, e.g. circular, dotplot, etc. Anything you want can be added as a view, and can be shown alongside our other views

This makes JBrowse 2 more than just a genome browser-- it is really a platform that can be built on.

What are new features in jbrowse 2
  • Uses webworkers for data parsing and rendering tracks
  • Use ctrl+scroll to zoom in and out quickly
  • Status updates while track is loading (e.g. Downloading BAM index...)
  • Hi-C visualization from .hic format files
  • Can display multiple chromosomes or discontinuous regions on a single linear genome view
  • Can connect to UCSC trackhubs
  • Alignments track has both coverage and pileup display integrated in a single track
  • Read pileups can be sorted by various attributes
  • Has ability to show soft clipped bases on reads
  • Interactively edit the configuration using the GUI
  • Circular, dotplot, stacked synteny views
  • SV inspector, that gives spreadsheet and circos overview of data in a single view
  • Linear genome view can be reverse complemented
Can the linear genome view be reverse complemented

Yes! See here

Setup

How can I start the JBrowse 2 app as a developer

We recommend that you have the following

Then you can follow steps from our README

It basically boils down to git cloning our repo, and running yarn start which creates a development server on port 3000

You can use PORT=8080 yarn start to manually specify a different port

Note that this is a development server that gets started up. To install jbrowse 2 in production on your webserver, see below

Do you have any tips for learning React and mobx-state-tree

Here is a short guide to React and mobx-state-tree that could help get you oriented

https://gist.github.com/cmdcolin/94d1cbc285e6319cc3af4b9a8556f03f

How can I setup JBrowse 2 in production

We recommend following the steps in the quickstart web guide

How can I setup JBrowse 2 without the CLI tools

The jbrowse CLI tools are basically a convenience, and are not strictly required

Simple tasks can be done without it

For example, for jbrowse create, you can visit the blog and download the latest jbrowse-web release tag, and unzip it into your web directory

For other things, like add-assembly and add-track, you can manually edit the config.json, reviewing the config docs and sample configs will be valuable

Understanding the config basics will come in handy also because you can manually edit in advanced configs after your tracks are loaded however be careful because corrupt configs can produce hard to understand errors, because our config system is strongly typed

Feel free to message the team if you encounter these

How can I setup JBrowse 2 with the CLI tools

See the quickstart guide

How do I load a track into JBrowse 2

If you have followed the above steps and installed jbrowse 2 on your webserver and loaded the assembly, and have the CLI tools installed

jbrowse add-track myfile.bw -a hg19

This will setup a bigwig track on the hg19 assembly in your config.json. Make sure to run the command inside your current jbrowse2 folder e.g. /var/www/html/jbrowse2 or wherever you are currently setting up a config.json (you can have multiple configs)

Note that you can also use remote URLs

jbrowse add-track http://yourremote/myfile.bam

The add-track command will do as much as possible to infer from the file extension how to configure this track, and automatically infer the index to be myfile.bam.bai

Curiosities

Why do all the tracks need an assembly specified

We require that all tracks have a specific genome assembly specified in their config. This is because jbrowse 2 is a multi-genome-assembly browser (and can compare genomes given the data). This may be different to using say jbrowse 1 where it knows which genome assembly you are working with at any given time

How are the menus structured in the app

In JBrowse 1, the app level menu operated on the single linear genome view, but with JBrowse 2, the top level menu only performs global operations and the linear genome view has it's own hamburger menu. Note that each track also has it's own track level menu.


  1. This means it's only possible to have one version of a particular plugin loaded on any given webpage, even if multiple products are loaded and using it on the same page.