Skip to main content

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

Super-quick start guide for JBrowse web

This is a quick overview to get started running JBrowse 2 from scratch using the command line. It is helpful if you have some familiarity with the command line, and with some bioinformatics tools like samtools in general. This guide also assumes you have:

  • a web server that reads files from /var/www/html/ e.g. Apache or nginx (not strictly necessary for jbrowse to run, see footnote)
  • node 10+ installed
  • genometools installed e.g. sudo apt install genometools or brew install brewsci/bio/genometools, used for sorting GFF3 for creating tabix GFF
  • samtools installed e.g. sudo apt install samtools or brew install samtools, used for creating FASTA index and BAM/CRAM processing
  • tabix installed e.g. sudo apt install tabix or brew install htslib, used for created tabix indexes for BED/VCF/GFF files

Super-quick overview for CLI

Initial setup

### Install JBrowse 2 CLI tools, note: if you want to use the jbrowse command
### under the sudo user, change this to `sudo npm install -g @jbrowse/cli`, but
### sometimes it is better to work under the principle of least priviledge and
### operate under a normal user so this guide does not use this
npm install -g @jbrowse/cli


### Use the `jbrowse create` command to download the latest release, and put it
### in a web server directory
jbrowse create /var/www/html/jbrowse2

### Alternatively, you may download to a directory, and then move it to the web
### directory
jbrowse create ~/mylocaljbrowse
mv ~/mylocaljbrowse /var/www/html/jbrowse2

Loading a FASTA file


### Create indexed FASTA file and load it using the add-assembly command
### Add your genome assembly to the config at /var/www/html/jbrowse2/config.json
### Also copies the files to this directory
samtools faidx genome.fa
jbrowse add-assembly genome.fa --out /var/www/html/jbrowse2 --load copy

Loading a BAM file

### Copies file.bam and file.bam.bai to /var/www/html/jbrowse2 and adds track to
### the config at /var/www/html/jbrowse2/config.json. Assumes that file.bam and
### file.bam.bai exist
samtools index file.bam
jbrowse add-track file.bam --out /var/www/html/jbrowse2/ --load copy

### Adds a url entry for a bam file to the config.json, the URL is stored in the
### config instead of downloading files, so no --load flag is needed
jbrowse add-track http://website.com/myfile.bam --out /var/www/html/jbrowse2

### If your BAM index (bai) is not filename+'.bai' then you can manually specify
### the --index flag. The --index flag also works with loading tabix tracks too
jbrowse add-track myfile.bam --index myfile.bai --out /var/www/html/jbrowse2 --load copy

Loading GFF3

### load gene annotations from a GFF, using "GenomeTools" (gt) to sort the gff
### and tabix to index the GFF3
gt gff3 -sortlines -tidy -retainids myfile.gff > myfile.sorted.gff
bgzip myfile.sorted.gff
tabix myfile.sorted.gff.gz
jbrowse add-track myfile.sorted.gff.gz --out /var/www/html/jbrowse2 --load copy

Miscellaneous tips

### Example of using --subDir to organize your data directory:
### copies myfile.bam and myfile.bam.bai to /var/www/html/jbrowse2/my_bams
### folder, which helps organize your data folder
jbrowse add-track myfile.bam --subDir my_bams --out /var/www/html/jbrowse2 --load copy

### Example without using the --out parameter:
### If you are in a directory with a config.json file, you can omit the --out parameter
cd /var/www/html/jbrowse2
jbrowse add-track /path/to/my/file.bam --load copy

### After you've had jbrowse for a while, you can upgrade to our latest release
jbrowse upgrade /var/www/html/jbrowse2

### Outputting to a specific config file instead of a config directory
### Alternative loading syntax where I specify a config file, and then this can
### be loaded via http://localhost/jbrowse2/?config=alt_config.json
jbrowse add-assembly mygenome.fa --out /var/www/html/jbrowse2/alt_config.json --load copy


Load a synteny track

### Demo for loading synteny data, both assemblies are outputted to a single
### config.json in /var/www/html/jbrowse2/config.json
minimap2 grape.fa peach.fa > peach_vs_grape.paf
jbrowse add-assembly grape.fa --load copy --out /var/www/html/jbrowse2/ -n grape
jbrowse add-assembly peach.fa --load copy --out /var/www/html/jbrowse2/ -n peach

### Use gt gff3 to make sorted tabixed gffs for each assembly, and then load to
### their respective ## assembly
jbrowse add-track grape.sorted.gff.gz -a grape --load copy --out /var/www/html/jbrowse2
jbrowse add-track peach.sorted.gff.gz -a peach --load copy --out /var/www/html/jbrowse2

### Load the synteny "track" from a PAF file. Note the order matters here for
### the --assemblyNames parameter. If minimap2 is run like `minimap2 grape.fa
### peach.fa` then you load --assemblyNames peach,grape. the order is reversed
### because the syntax is minimap2 ref.fa query.fa on the CLI and query (left side
### of PAF) and target (right hand side) in PAF output file
jbrowse add-track peach_vs_grape.paf --assemblyNames peach,grape --out /var/www/html/jbrowse2/ --load copy

Create a text index to let users search for gene names

### Finally create a text-index for your genes. By default it will index all
### tracks with Gff3TabixAdapter and VcfTabixAdapter. A progress bar will show
### indexing progress
jbrowse text-index --out /var/www/html/jbrowse2

### Index only a specific assembly
jbrowse text-index --out /var/www/html/jbrowse2 -a hg19

#### Index only some specific trackIds
jbrowse text-index --out /var/www/html/jbrowse2 --tracks=mygenes1,mygenes2

#### Index each track individually
jbrowse text-index --out /var/www/html/jbrowse2 --tracks=mygenes1,mygenes2 --perTrack

### If you already have a text-index, you have to use --force to overwrite the old one
jbrowse text-index --out /var/www/html/jbrowse2 --force

Conclusion

You can now visit http://localhost/jbrowse2 and your genome should be ready!

This guide is meant to be a super-quick conceptual overview for getting JBrowse 2 set up, but if you are new to the command line or to jbrowse in general, you might want to start with the slightly longer quick-start guide here.

Footnote

JBrowse doesn't strictly need Apache or nginx, it is "static site compatible" meaning it uses no server code and can run on any static website hosting. For example, you can upload the jbrowse folder that we prepared here in /var/www/html/jbrowse2 to Amazon S3, and it will work there too. See the FAQ for what webserver do I need for more info.

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.4+
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 manually

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
Figure: 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 screen with a sample configuration
Figure: JBrowse 2 screen 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
Figure: 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
Figure: 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

Note if you get errors about your VCF file not being sorted when using tabix, you can use bcftools to sort your VCF.

bcftools sort file.vcf > file.sorted.vcf
bgzip file.sorted.vcf
tabix file.sorted.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
Figure: JBrowse 2 linear genome view with variant track

Adding a BigWig/BigBed track

Probably one of the most simple track types to load is a BigWig/BigBed file since it does not have any external index file, it is just a single file

An example file is here https://jbrowse.org.s3.amazonaws.com/genomes/volvox/volvox-sorted.bam.coverage.bw

### Download bigwig or bigbed file
jbrowse add-track volvox-sorted.bam.coverage.bw --load copy

Adding a GFF3 file with GFF3Tabix

To load a GFF3 file, we can sort and index it with tabix

Sorting a GFF3 can be done with GenomeTools (to install can use sudo apt install genometools)

gt gff3 -sortlines -tidy -retainids yourfile.gff > yourfile.sorted.gff
bgzip yourfile.sorted.gff
tabix yourfile.sorted.gff.gz
jbrowse add-track yourfile.sorted.gff.gz --load copy

Indexing feature names for searching

The final step of loading you jbrowse instance may include adding a "search index" so that you can search by genes or other features by their name or ID

To do this we can use the jbrowse text-index command

jbrowse text-index

This will index relevant track types e.g. any track with Gff3TabixAdapter (gene names and IDs) or VcfTabixAdapter (e.g. variant IDs). The command will print out a progress bar for each track that it is indexing.

This will also update your config.json so after it completes, you can type a gene name into the "search box" in the linear genome view or other views and quickly navigate to genes by gene name.

See the text-index command docs for more info. Also see the FAQ entries for text searching

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, which provides a link that can be used. Note: we do not recommend using admin-server in production, and should be used for temporary configuration
Figure: JBrowse CLI admin-server output, which provides a link that can be used. Note: we do not recommend using admin-server in production, and should be used for temporary configuration
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

Screenshot showing the assembly manager, with no assemblies loaded yet
Figure: Screenshot showing the assembly manager, with no assemblies loaded yet

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

Press the "Add New Assembly" button, and enter the necessary information in the form:

  • name: hg38
  • type: BgzipFastaAdapter
  • 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
Assembly manager page for adding a new assembly
Figure: Assembly manager page for adding a new assembly

Click on "Create New Assembly". Great, we've added an assembly! We can see that we have successfully added the hg38 assembly.

The assembly manager dialog box with human assemblies available
Figure: The assembly manager dialog box with human assemblies available

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 the 'Add track' form
Figure: JBrowse 2 file menu with the 'Add track' form

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

The 'Add track' form can be launched from the circular '+' button in the bottom righthand corner
Figure: The 'Add track' form can be launched from the circular '+' button in the bottom righthand corner

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.

The configuration editor, which will persist settings to the config file if editing using the admin-server
Figure: The configuration editor, which will persist settings to the config file if editing using the admin-server

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.

Setting a default session

It is also possible to use the graphical admin server to set the default session of your JBrowse 2 instance. This is the session that will appear when JBrowse 2 is first visited. To do so, open the form to set the default session (Admin > Set default session):

The 'Set default session' will persist your current session into the config file so any subsequent visitors to the app will see this session
Figure: The 'Set default session' will persist your current session into the config file so any subsequent visitors to the app will see this session

You can use the form to clear your default session, select the currently open session, or any of your previously saved sessions.

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

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 and find the latest Linux AppImage release. Download that file to wherever you would like to keep it and then start it in one of two ways:

In the terminal

Using the AppImage file on linux, all that is needed is to make the file executable which you can do in a terminal

## Make the AppImage file executable, only need to do this once
chmod a+x jbrowse-desktop-*-linux.AppImage
## Run!
./jbrowse-desktop-*-linux.AppImage
In your file explorer

This may vary slightly depending on your distribution but should basically follow these steps:

  1. Right-click on the AppImage file and select "Properties"
  2. Go to the "Permissions" tab
  3. Check "Allow executing file as program" and close

You can now double-click the AppImage file to launch JBrowse.

Installing on MacOS

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

Download the .dmg file for MacOS, double click, and drag JBrowse 2 into 'applications'.

You can now open JBrowse 2 like any other application on your Mac.

Installing on Windows

Visit http://github.com/gmod/jbrowse-components/releases/latest and download the latest Windows installer executable (will end with win.exe).

Double-click the downloaded installer and it will install and open JBrowse. You can now open JBrowse like any other program.

JBrowse Desktop start screen

After you have installed and started JBrowse Desktop you will see a start screen like this

Screenshot showing the start screen on JBrowse desktop
Figure: Screenshot showing the start screen on JBrowse desktop

The left hand panel, with "Launch new session" can quickly launch a new session using either your own custom genome (which you can load using an indexed FASTA or a twobit file). Also on the left hand panel is the "Quickstart list". Users can click the checkbox next to e.g. hg38 and hit Go.

On the right hand panel is the "Recently opened sessions". This includes sessions that you have specifically saved, and sessions that were autosaved (e.g. ones that you didn't explicitly use "Save as" on). You can re-open your sessions by clicking on the link.

Special features on the start screen

Converting a saved session into a quickstart entry

If you study a rare species, you might find it useful to customize your quickstart panel. We allow you to convert a session in the "Recently opened sessions" into an entry that appears in the quickstart list.

To do so: Click a checkbox next to a session in the "Recently opened sessions" table, and then hit the

icon next to the trash can icon. This is helpful if e.g. you want to make your own custom organism a template for quickstarts in the future.

Selecting multiple entries from the quickstart panel

Users can also hit the checkbox for multiple species in the quickstart list, and then the sessions are combined which is helpful if e.g. you are doing comparative genomics of hg19 and mm10.

Next steps

Check out the user guide for more info on how to use JBrowse Desktop. This covers all the features that are available with screenshots and instructions.

User guide

Linear genome view usage

To start a linear genome view, use the menu bar

File->Add->Linear genome view

  • 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

You can also use the search box to search by gene name (if it is configured)

Search for gene names or other features via the location search box.
Figure: Search for gene names or other features via the location search box.

In order to enable name searching, you or the admin on the instance will need to create a "text index". See the quickstart guide for more info.

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

After opening the menu item for 'Open new track' a drawer widget for the 'Add track form' will appear
Figure: After opening the menu item for 'Open new track' a drawer widget for the 'Add track form' will appear

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

The orange plus icon in the bottom right of a tracklist can also be used to launch the 'Add track form'
Figure: The orange plus icon in the bottom right of a tracklist can also be used to launch the 'Add track form'

In the "Add track" form, you can provide a URL to a file to load, or you can also open files from your local machine. In some cases, you need to provide an index (bigwig files for example have no index, but BAM/CRAM or tabix filetypes like VCF/GFF/BED tabix do). In some cases we can automatically infer the index e.g. if you provide a URL for a BAM and the index filename is bamfilename +'.bai' but you may need to manually supply it in some cases (index inference can't be done with files from your local machine)

The following file formats are supported

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

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

On JBrowse Web, 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.

Note: Share sessions is not available on JBrowse Desktop.

Also note: you can't copy the literal URL in your address bar and send it to other users, you must use the "Share" button to do that, but you can copy and paste the URL in your URL bar between different tabs in your local browser though

The session share dialog, which gives you a short URL to share your session with other users. It is important to use these URLs generated here rather than simply copying and pasting your URL to other users
Figure: The session share dialog, which gives you a short URL to share your session with other users. It is important to use these URLs generated here rather than simply copying and pasting your URL to other users

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!

Track menu

Users can access track-specific functions by using the track menu, which is accessible from the track selecter itself ("..." icon) or on the track label (vertical "..."). Some functions are only available when the track is open e.g. from the track label, but more basic options like "About track" are available from the track menu on the track selector.

Screenshot showing how to open the track menu (both in the track selector area and in the track label area of the linear genome view), and an example of a VCF track with it's track menu open
Figure: Screenshot showing how to open the track menu (both in the track selector area and in the track label area of the linear genome view), and an example of a VCF track with it's track menu open

About track dialog

Using the track menu as described above, you can access the "About track" dialog

Screenshot of the 'About track' dialog for a CRAM file, showing the full CRAM file header and config info. Having the full header of a BAM/CRAM file available is helpful to easily check what genome it was aligned to for example.
Figure: Screenshot of the 'About track' dialog for a CRAM file, showing the full CRAM file header and config info. Having the full header of a BAM/CRAM file available is helpful to easily check what genome it was aligned to for example.

Editing track configs

As a non-admin user, in order to edit a track config, you have to make a copy of the track. This will copy it to your "session tracks", which you can edit freely

Screenshot showing the procedure to copy the track before being able to edit the settings
Figure: Screenshot showing the procedure to copy the track before being able to edit the settings
Rubberband selection

The scale bars accept a click-and-drag action to select a region. Rubberband selection can be performed on both the main (lower) and overview (upper) scale bars.

Screenshot of rubberbanding both the main and overview scalebars. The main scalebar produces extra options on selection, e.g. Zoom to region, Get sequence, etc.
Figure: Screenshot of rubberbanding both the main and overview scalebars. The main scalebar produces extra options on selection, e.g. Zoom to region, Get sequence, etc.
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
Figure: 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
Figure: Before and after horizontally flipping

Sequence track

The sequence track shows the reference sequence and a three-frame translation. If the view is horizontally flipped, the sequence is "reverse complemented" so the bottom three translation frames go to the top, and the top frames go to the bottom.

The sequence track, with a positive strand gene for context, shows the start codon on the first exon in the top-three rows of the translation frame. The bottom panel shows the same view but with the view horizontally flipped, and the gene is now shown reversed and the start codon is in the bottom translation frames.
Figure: The sequence track, with a positive strand gene for context, shows the start codon on the first exon in the top-three rows of the translation frame. The bottom panel shows the same view but with the view horizontally flipped, and the gene is now shown reversed and the start codon is in the bottom translation frames.

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
Figure: 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.
Figure: 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
Figure: 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)
Figure: 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)

Sort, color and filter by tag

We can now also do things like

  • Sort by tag
  • Filter by tag
  • Color by tag

With these features, we can create very expressive views of alignments tracks. For example, in the below step-by-step guide, it shows how to color and sort the reads by the HP tag.

Step-by-step guide showing how to sort and color by haplotype with the HP tag
Figure: Step-by-step guide showing how to sort and color by haplotype with the HP tag

Color by modifications/methylation

If you have data that marks DNA/RNA modifications using the MM tag in BAM/CRAM format, then the alignments track can use these to color these. It uses two modes

  1. Modifications mode - draws the modifications as they are
  2. Methylation mode - draws both unmodified and modifified CpGs (unmodified positions are not indicated by the MM tag and this mode considers the sequence context)
The track menu can be used to access the settings to color by modifications or methylation
Figure: The track menu can be used to access the settings to color by modifications or methylation
Screenshot showing the same track in both modifications mode and methylation mode
Figure: Screenshot showing the same track in both modifications mode and methylation mode
After the setting has been enabled you can revisit the dialog box to see the current coloring settings
Figure: After the setting has been enabled you can revisit the dialog box to see the current coloring settings

Color by orientation

JBrowse uses the same color scheme as IGV for coloring by pair orientation. These pair orientations can be used to reveal complex patterns of structural variation

See https://software.broadinstitute.org/software/igv/interpreting_pair_orientations for a good guide on interpreting these pair orientations

This shows an inverted duplication, the tandem duplication can produce green arrows which have reads pointing in opposite directions e.g. <-- and -->, while blue arrows which can indicate an inversion point in the same direction e.g. --> and -->
Figure: This shows an inverted duplication, the tandem duplication can produce green arrows which have reads pointing in opposite directions e.g. <-- and -->, while blue arrows which can indicate an inversion point in the same direction e.g. --> and -->

BigWig tracks

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

A simple wiggle track with the XY plot renderer
Figure: A simple wiggle track with the XY plot renderer

Viewing whole-genome coverage for profiling CNV

The latest jbrowse also allows refining the resolution of BigWig tracks, and viewing whole genome coverage. This allows us to get detailed global views of CNV for example from whole-genome coverage profiling

Here is a short picture guide to setup a whole-genome view of a BigWig for CNV coverage visualization

  1. Open your BigWig track
  2. Go to the view menu and select "Show all assembly regions"
  3. Adjust the "Autoscale type" to your liking, the new options for "Local +/- 3sd" allows the autoscaling to avoid outliers
  4. Go to the track menu and select "Turn off histogram fill", which then shows only a dot for each point on the graph
  5. Go to the track menu and select "Resolution->Finer resolution" a couple times until resolution looks nice

Also note: all tracks have a drag handle on the bottom of it which you can drag down to make the track taller

A step-by-step guide to view a whole-genome CNV profile of coverage from a BigWig file
Figure: A step-by-step guide to view a whole-genome CNV profile of coverage from a BigWig file

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
Figure: 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

Screenshot showing the variant feature sidebar with a filtered by genotype (with alternative allele '1'). Users can also filter by sample name or other attributes
Figure: Screenshot showing the variant feature sidebar with a filtered by genotype (with alternative allele '1'). Users can also filter by sample name or other attributes

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
Figure: 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
Figure: 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
Figure: 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

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: 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
Example screenshot showing the linear synteny view for grape vs peach
Figure: Example screenshot showing the linear synteny view for grape vs peach

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

Opening a synteny view from a dotplot view

We have designed JBrowse 2 to be able to open up a synteny view from a dotplot view. This is enabled by "display modes" so that the same track can be displayed in different contexts.

Here is a short demo that shows opening a synteny view from a dotplot view selection

Screenshow showing the 'click and drag' selection over the dotplot view prompts you to open up a linear synteny view from the selected region
Figure: Screenshow showing the 'click and drag' selection over the dotplot view prompts you to open up a linear synteny view from the selected region

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
Figure: 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
Figure: 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 of a Hi-C track
Figure: Screenshot of 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
Figure: 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 opening a file locally or using a URL for files in the following formats:

  • VCF or VCF.gz (plain text VCF, or (b)gzipped VCF)
  • BEDPE
  • STAR-fusion result file
The import form for getting started with the SV inspector
Figure: The import form for getting started with the SV inspector

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

The SV inspector with the import form and URL pasted
Figure: The SV inspector with the import form and URL pasted

SV inspector results

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

The SV inspector with loaded results
Figure: The SV inspector with loaded results

Now here is where things can become interesting

We can search and filter the table, with filtering and searching being reflected in the circular view as well.

The SV inspector with filter applied
Figure: The SV inspector with filter applied

Launching breakpoint split view

By clicking on the features in the circular view, or clicking on the triangle drop-down on the leftmost column of the table, 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.

Screenshot of the 'breakpoint split view' which examines the breakpoints of a structural variant, e.g. an interchromosomal translocation, and connects supporting reads (black splines) and the variant call itself (green thicker line, with feet indicating directionality)
Figure: Screenshot of the 'breakpoint split view' which examines the breakpoints of a structural variant, e.g. an interchromosomal translocation, and connects supporting reads (black splines) and the variant call itself (green thicker line, with feet indicating directionality)

Getting the protein sequence for features

If you have a track with gene or transcript level features, then the feature detail sidebar will automatically stitch together the sequence for that feature. The options include:

  • CDS - the coding sequences, spliced together
  • Protein - performs protein translation on the CDS, currently assuming the default codon translation table
  • cDNA - the CDS plus UTR, or just all exons if a non-coding gene
  • Gene w/ introns - the entire gene region sequence with the introns included
  • Gene w/ 10bp of introns - the spliced gene sequence with 10bp around the splice sites shown
  • Gene w/ 500 up+down stream - the entire gene region with 500bp upstream and downstream (shown in light red)
  • Gene w/ 500 up+down stream + 10bp of introns - the spliced gene sequence with 10bp around the splice sites shown and the up/down stream shown

Some of the params such as 500bp and 10bp are arbitrarily chosen, if you are interested in adjusting these parameters let us know

The sequence for the upstream and downstream, exons, and intron sequences shown in the feature details
Figure: The sequence for the upstream and downstream, exons, and intron sequences shown in the feature details

Using the plugin store

Users can add plugins to their session using the in-app plugin store. The plugin will be added to your "session" which can be shared with the share button (or if you are an admin running the admin-server, then it will be added to the config file).

This can add extra functions or tracks or many other interesting features. For example, if you add the CIVIC plugin, it will automatically add a track that contains the CIVIC cancer gene annotations to hg19.

Note that not all plugins are directly useful from being added (sometimes it needs extra work on the part of the plugin developer to make them useful in the GUI, some plugins require hand editing of configuration files).

Screenshot showing the plugin store inside the app
Figure: Screenshot showing the plugin store inside the app

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 */
],
"aggregateTextSearchAdapters": [
/* optional array of text search adapters */
],
"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",
"locationType": "UriLocation"
},
"faiLocation": {
"uri": "https://jbrowse.org/genomes/hg19/fasta/hg19.fa.gz.fai",
"locationType": "UriLocation"
},
"gziLocation": {
"uri": "https://jbrowse.org/genomes/hg19/fasta/hg19.fa.gz.gzi",
"locationType": "UriLocation"
}
},
"rendering": {
"type": "DivSequenceRenderer"
}
},
"refNameAliases": {
"adapter": {
"type": "RefNameAliasAdapter",
"location": {
"uri": "https://s3.amazonaws.com/jbrowse.org/genomes/hg19/hg19_aliases.txt",
"locationType": "UriLocation"
}
}
}
}
]
}

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",
"locationType": "UriLocation"
}
}
}

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 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",
"locationType": "UriLocation"
},
"faiLocation": {
"uri": "https://jbrowse.org/genomes/hg19/fasta/hg19.fa.gz.fai",
"locationType": "UriLocation"
},
"gziLocation": {
"uri": "https://jbrowse.org/genomes/hg19/fasta/hg19.fa.gz.gzi",
"locationType": "UriLocation"
}
},
"rendering": {
"type": "DivSequenceRenderer"
}
},
"refNameAliases": {
"adapter": {
"type": "RefNameAliasAdapter",
"location": {
"uri": "https://s3.amazonaws.com/jbrowse.org/genomes/hg19/hg19_aliases.txt",
"locationType": "UriLocation"
}
}
}
}
]
}

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",
"locationType": "UriLocation"
},
"faiLocation": {
"uri": "https://jbrowse.org/genomes/hg19/fasta/hg19.fa.gz.fai",
"locationType": "UriLocation"
},
"gziLocation": {
"uri": "https://jbrowse.org/genomes/hg19/fasta/hg19.fa.gz.gzi",
"locationType": "UriLocation"
}
},
"rendering": {
"type": "DivSequenceRenderer"
}
}

BgzipFastaAdapter

A bgzip FASTA format file is generated by

bgzip -i sequence.fa
samtools faidx sequence.fa.gz

### above commands generates the following 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",
"locationType": "UriLocation"
},
"faiLocation": {
"uri": "https://jbrowse.org/genomes/hg19/fasta/hg19.fa.gz.fai",
"locationType": "UriLocation"
},
"gziLocation": {
"uri": "https://jbrowse.org/genomes/hg19/fasta/hg19.fa.gz.gzi",
"locationType": "UriLocation"
}
}

IndexedFastaAdapter

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

samtools faidx sequence.fa

### above commands generate the .fa and .fai 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",
"locationType": "UriLocation"
},
"faiLocation": {
"uri": "https://jbrowse.org/genomes/hg19/fasta/hg19.fa.fai",
"locationType": "UriLocation"
}
}

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",
"locationType": "UriLocation"
}
}

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",
"locationType": "UriLocation"
},
"faiLocation": {
"uri": "https://jbrowse.org/genomes/hg19/fasta/hg19.fa.gz.fai",
"locationType": "UriLocation"
},
"gziLocation": {
"uri": "https://jbrowse.org/genomes/hg19/fasta/hg19.fa.gz.gzi",
"locationType": "UriLocation"
}
}
}
}
],
"tracks": [
{
"type": "FeatureTrack",
"trackId": "repeats_hg19",
"name": "Repeats",
"assemblyNames": ["hg19"],
"category": ["Annotation"],
"adapter": {
"type": "BigBedAdapter",
"bigBedLocation": {
"uri": "https://jbrowse.org/genomes/hg19/repeats.bb",
"locationType": "UriLocation"
}
}
}
]
}

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",
"locationType": "UriLocation"
},
"index": {
"location": {
"uri": "http://yourhost/file.bam.bai",
"locationType": "UriLocation"
}
}
}
}
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",
"locationType": "UriLocation"
},
"index": {
"location": {
"uri": "http://yourhost/file.bam.bai",
"locationType": "UriLocation"
}
}
}
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",
"locationType": "UriLocation"
},
"craiLocation": {
"uri": "http://yourhost/file.cram.crai",
"locationType": "UriLocation"
}
}

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",
"locationType": "UriLocation"
}
}
}
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",
"locationType": "UriLocation"
}
}
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 jexl:baseColor.alpha(Math.min(1,count/(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",
"locationType": "UriLocation"
},
"index": {
"location": {
"uri": "http://yourhost/file.vcf.gz.tbi",
"locationType": "UriLocation"
}
}
}
}
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",
"locationType": "UriLocation"
},
"index": {
"location": {
"uri": "http://yourhost/file.vcf.gz.tbi",
"locationType": "UriLocation"
}
}
}

QuantitativeTrack config

Example QuantitativeTrack config

{
"trackId": "my_wiggle_track",
"name": "My Wiggle Track",
"assemblyNames": ["hg19"],
"type": "QuantitativeTrack",
"adapter": {
"type": "BigWig",
"bigWigLocation": {
"uri": "http://yourhost/file.bw",
"locationType": "UriLocation"
}
}
}
General QuantitativeTrack 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 QuantitativeTrack

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 QuantitativeTrack

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

  • minScore
  • maxScore
QuantitativeTrack drawing options
  • inverted - draws upside down
  • defaultRendering - can be density, xyplot, or line
  • summaryScoreMode - options: min, max, whiskers
QuantitativeTrack 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",
"locationType": "UriLocation"
}
}

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",
"locationType": "UriLocation"
},
"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

Advanced adapters

There are two useful adapter types that can be used for more advanced use cases, such as generating configuration for data returned by an API. These are the FromConfigAdapter and FromConfigSequenceAdapter. They can be used as the adapter value for any track type.

FromConfigAdapter

This adapter can be used to generate features directly from values stored in the configuration.

Example FromConfigAdapter

{
"type": "FromConfigAdapter",
"features": [
{
"refName": "ctgA",
"uniqueId": "alias1",
"aliases": ["A", "contigA"]
},
{
"refName": "ctgB",
"uniqueId": "alias2",
"aliases": ["B", "contigB"]
}
]
}
FromConfigSequenceAdapter

Similar behavior to FromConfigAdapter, with a specific emphasis on performance when the features are sequences.

Example FromConfigSequenceAdapter

{
"type": "FromConfigSequenceAdapter",
"features": [
{
"refName": "SEQUENCE_1",
"uniqueId": "firstId",
"start": 0,
"end": 33,
"seq": "CCAAGATCTAAGATGTCAACACCTATCTGCTCA"
},
{
"refName": "SEQUENCE_2",
"uniqueId": "secondId",
"start": 0,
"end": 44,
"seq": "CCGAACCACAGGCCTATGTTACCATTGGAAAGCTCACCTTCCCG"
}
]
}

Text searching

Text searching is now available on JBrowse 2.

Text searching appears in two forms: per-track indexes and aggregate indexes which search across multiple tracks

Aggregate indexes may look like this

{
"aggregateTextSearchAdapters": [
{
"type": "TrixTextSearchAdapter",
"textSearchAdapterId": "hg19-index",
"ixFilePath": {
"uri": "https://jbrowse.org/genomes/hg19/trix/hg19.ix",
"locationType": "UriLocation"
},
"ixxFilePath": {
"uri": "https://jbrowse.org/genomes/hg19/trix/hg19.ixx",
"locationType": "UriLocation"
},
"metaFilePath": {
"uri": "https://jbrowse.org/genomes/hg19/trix/meta.json",
"locationType": "UriLocation"
},
"assemblyNames": ["hg19"]
}
}

An example per-track config may look like this

{
"trackId":"yourtrack",
"name":"Track name",
"adapter":{
"type": "Gff3TabixAdapter",
"gffGzLocation": { "uri":"yourfile.gff.gz",
"locationType": "UriLocation" }
"index":{ "location": { "uri":"yourfile.gff.gz.tbi",
"locationType": "UriLocation" } }
},
"textSearching": {
"textSearchAdapter": {
"type": "TrixTextSearchAdapter",
"textSearchAdapterId": "hg19-index",
"ixFilePath": {
"uri": "https://jbrowse.org/genomes/hg19/trix/hg19.ix",
"locationType": "UriLocation"
},
"ixxFilePath": {
"uri": "https://jbrowse.org/genomes/hg19/trix/hg19.ixx",
"locationType": "UriLocation"
},
"metaFilePath": {
"uri": "https://jbrowse.org/genomes/hg19/trix/meta.json",
"locationType": "UriLocation"
},
"assemblyNames": ["hg19"]
},
"indexingAttributes": ["Name","ID"],
"indexingFeatureTypesToExclude": ["CDS","exon"]
}
}

Information on generating trix indexes via the cli can be found here

TrixTextSearchAdapter config

The trix search index is the current file format for name searching

It is based on the UCSC trix file format described here https://genome.ucsc.edu/goldenPath/help/trix.html

To create trix indexes you can use our command line tools. More info found at our jbrowse text-index guide. This tool will automatically generate a config like this. The config slots are described below for details

{
"textSearchAdapter": {
"type": "TrixTextSearchAdapter",
"textSearchAdapterId": "gff3tabix_genes-index",
"ixFilePath": {
"uri": "trix/gff3tabix_genes.ix",
"locationType": "UriLocation"
},
"ixxFilePath": {
"uri": "trix/gff3tabix_genes.ixx",
"locationType": "UriLocation"
},
"metaFilePath": {
"uri": "trix/gff3tabix_genes_meta.json",
"locationType": "UriLocation"
}
}
}
  • ixFilePath - the location of the trix ix file
  • ixxFilePath - the location of the trix ixx file
  • metaFilePath - the location of the metadata json file for the trix index

JBrowse1TextSearchAdapter config

This is more uncommon, but allows back compatibility with a jbrowse 1 names index created by generate-names.pl

{
"textSearchAdapter": {
"type": "JBrowse1TextSearchAdapter",
"textSearchAdapterId": "generate-names-index",
"namesIndexLocation": {
"uri": "/names",
"locationType": "UriLocation"
}
}
}
  • namesIndexLocation - the location of the JBrowse1 names index data directory

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",
"locationType": "UriLocation"
}
}
}
},
{
"name": "peach",
"sequence": {
"trackId": "peach_seq",
"type": "ReferenceSequenceTrack",
"adapter": {
"type": "ChromSizesAdapter",
"chromSizesLocation": {
"uri": "peach.chrom.sizes",
"locationType": "UriLocation"
}
}
}
}
],
"tracks": [
{
"trackId": "grape_peach_synteny_mcscan",
"type": "SyntenyTrack",
"assemblyNames": ["peach", "grape"],
"trackIds": [],
"renderDelay": 100,
"adapter": {
"mcscanAnchorsLocation": {
"uri": "grape.peach.anchors",
"locationType": "UriLocation"
},
"subadapters": [
{
"type": "NCListAdapter",
"rootUrlTemplate": {
"uri": "https://jbrowse.org/genomes/synteny/peach_gene/{refseq}/trackData.json",
"locationType": "UriLocation"
}
},
{
"type": "NCListAdapter",
"rootUrlTemplate": {
"uri": "https://jbrowse.org/genomes/synteny/grape_gene/{refseq}/trackData.json",
"locationType": "UriLocation"
}
}
],
"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",
"locationType": "UriLocation"
},
"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",
"locationType": "UriLocation"
},
"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",
"locationType": "UriLocation"
}
}
}
},
{
"name": "peach",
"sequence": {
"trackId": "peach_seq",
"type": "ReferenceSequenceTrack",
"adapter": {
"type": "ChromSizesAdapter",
"chromSizesLocation": {
"uri": "peach.chrom.sizes",
"locationType": "UriLocation"
}
}
}
}
],
"tracks": [
{
"trackId": "grape_peach_synteny_mcscan",
"type": "SyntenyTrack",
"assemblyNames": ["peach", "grape"],
"trackIds": [],
"renderDelay": 100,
"adapter": {
"mcscanAnchorsLocation": {
"uri": "grape.peach.anchors",
"locationType": "UriLocation"
},
"subadapters": [
{
"type": "NCListAdapter",
"rootUrlTemplate": {
"uri": "https://jbrowse.org/genomes/synteny/peach_gene/{refseq}/trackData.json",
"locationType": "UriLocation"
}
},
{
"type": "NCListAdapter",
"rootUrlTemplate": {
"uri": "https://jbrowse.org/genomes/synteny/grape_gene/{refseq}/trackData.json",
"locationType": "UriLocation"
}
}
],
"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",
"locationType": "UriLocation"
}
},
"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",
"locationType": "UriLocation"
}
}
},
{
"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",
"locationType": "UriLocation"
}
},
"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",
"locationType": "UriLocation"
}
}
}
],
"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:

Example screenshot showing the default theme
Figure: Example screenshot showing the default theme
Example screenshot showing the customized theme
Figure: Example screenshot showing the 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"
}
}
}
}

It is also possible to supply a custom logo to be displayed in the top right corner of the app instead of the JBrowse 2 logo. To do this, store a SVG file containing your logo on your server, and specify the path in your configuration:

{
"configuration": {
"logoPath": {
"uri": "path/to/my/custom-logo.svg"
}
}
}

The dimensions of the logo should be 150x48px.

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
}
}

Configuration callbacks

We use Jexl (see https://github.com/TomFrost/Jexl) for defining configuration callbacks.

An example of a Jexl configuration callback might look like this

"color": "jexl:get(feature,'strand')==-1?'red':'blue'"

The notation get(feature,'strand') is the same as feature.get('strand') in javascript code.

We have a number of other functions such as

Feature operations - get


jexl:get(feature,'start') // start coordinate, 0-based half open
jexl:get(feature,'end') // end coordinate, 0-based half open
jexl:get(feature,'refName') // chromosome or reference sequence name
jexl:get(feature,'CIGAR') // BAM or CRAM feature CIGAR string
jexl:get(feature,'seq') // BAM or CRAM feature sequence
jexl:get(feature,'type') // feature type e.g. mRNA or gene

Feature operations - getTag

The getTag function smooths over slight differences in BAM and CRAM features to access their tags

jexl:getTag(feature, 'MD') // fetches MD string from BAM or CRAM feature
jexl:getTag(feature, 'HP') // fetches haplotype tag from BAM or CRAM feature

String functions

jexl:charAt('abc',2) // c
jexl:charCodeAt(' ',0) // 32
jexl:codePointAt(' ',0) // 32
jexl:startsWith('kittycat','kit') // true
jexl:endsWith('kittycat','cat') // true
jexl:padStart('cat', 8, 'kitty') // kittycat
jexl:padEnd('kitty', 8, 'cat') // kittycat
jexl:replace('kittycat','cat','') // kitty
jexl:replaceAll('kittycatcat','cat','') // kitty
jexl:slice('kittycat',5) // cat
jexl:substring('kittycat',0,5) // kitty
jexl:trim(' kitty ') // kitty, whitespace trimmed
jexl:trimStart(' kitty ') // kitty, starting whitespace trimmed
jexl:trimEnd(' kitty ') // kitty, ending whitespace trimmed
jexl:toUpperCase('kitty') // KITTY
jexl:toLowerCase('KITTY') // kitty

Math functions


jexl:min(0,2)
jexl:max(0,2)
jexl:abs(-5)
jexl:ceil(0.5)
jexl:floor(0.5)
jexl:round(0.5)
jexl:parseInt('2')
jexl:parseFloat('2.054')

Console logging


jexl:log(feature) // console.logs output and returns value
jexl:cast({'mRNA':'green','pseudogene':'purple'})[get(feature,'type')] // returns either green or purple depending on feature type

Binary operators

jexl:get(feature,'flags')&2 // bitwise and to check if BAM or CRAM feature flags has 2 set

Command line tools

This document covers the CLI tools.

Installation

The command line tools can be installed globally using npm as follows

$ npm install -g @jbrowse/cli

A CLI tool called jbrowse should then be available in the path. 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 globally with npm install @jbrowse/cli -g 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

--displayName=displayName
The display name to specify for the assembly, e.g. "Homo sapiens (hg38)" while the name can be a shorter identifier
like "hg38"

--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 hg38 --alias GRCh38 --displayName "Homo sapiens (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"}, "locationType": "UriLocation"}'

-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"}, "locationType": "UriLocation"}' --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, --trackType=trackType 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
# --load copy copies my.bam and my.bam.bai to current directory and adds track to config.json
$ jbrowse add-track /path/to/my.bam --load copy

# same as above, but specify path to bai file
$ jbrowse add-track /path/to/my.bam --indexFile /path/to/my.bai --load copy

# --load symlink creates symlink in /path/to/jb2/ directory for this file, and adds track to config.json
$ jbrowse add-track /path/to/my.bam --target /path/to/jb2/config.json --load symlink

# no --load flag to add literal URL for this track to config.json
$ jbrowse add-track https://mywebsite.com/my.bam

# --load move to move the file
$ jbrowse add-track /path/to/my.bam --name 'New Track' --load move

# --load inPlace puts /url/relative/path.bam in the config without performing any file operations
$ jbrowse add-track /url/relative/path.bam --trackId AlignmentsTrack1 --load url --overwrite

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

--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 v1.0.0.
Defaults to latest

-u, --url=url A direct URL to a JBrowse 2 release

--branch=branch Download a development build from a named git branch

--nightly Download the latest development build from the main branch

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 v1.0.0
$ 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

--delete Delete any existing default session.

--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 text-index

Make a text-indexing file for any given track(s).

USAGE
$ jbrowse text-index

OPTIONS
-a, --assemblies=assemblies Specify the assembl(ies) to create an index for. If unspecified, creates an index for
each assembly in the config

-h, --help show CLI help

-q, --quiet Hide the progress bars

--attributes=attributes [default: Name,ID] Comma separated list of attributes to index

--dryrun Just print out tracks that will be indexed by the process, without doing any indexing

--exclude=exclude [default: CDS,exon] Adds gene type to list of excluded types

--file=file File or files to index (can be used to create trix indexes for embedded component use
cases not using a config.json for example)

--force Overwrite previously existing indexes

--out=out Synonym for target

--perTrack If set, creates an index per track

--target=target Path to config file in JB2 installation directory to read from.

--tracks=tracks Specific tracks to index, formatted as comma separated trackIds. If unspecified, indexes
all available tracks

EXAMPLES
# indexes all tracks that it can find in the current directory's config.json
$ jbrowse text-index

# indexes specific trackIds that it can find in the current directory's config.json
$ jbrowse text-index --tracks=track1,track2,track3

# indexes all tracks in a directory's config.json or in a specific config file
$ jbrowse text-index --out /path/to/jb2/

# indexes only a specific assembly, and overwrite what was previously there using force (which is needed if a previous
index already existed)
$ jbrowse text-index -a hg19 --force

# create index for some files for use in @jbrowse/react-linear-genome-view or similar
$ jbrowse text-index --file myfile.gff3.gz --file myfile.vcfgz --out indexes

See code: src/commands/text-index.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 v1.0.0.
Defaults to latest

-u, --url=url A direct URL to a JBrowse 2 release

--branch=branch Download a development build from a named git branch

--nightly Download the latest development build from the main branch

EXAMPLES
$ jbrowse upgrade # Upgrades current directory to latest jbrowse release
$ jbrowse upgrade /path/to/jbrowse2/installation
$ jbrowse upgrade /path/to/jbrowse2/installation --tag v1.0.0
$ 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 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.), 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)
Figure: Architecture diagram of JBrowse 2, showing how plugins encapsulate views (e.g. LinearGenomeView, DotplotView etc.), tracks (AlignmentsTrack, VariantTrack, etc.), 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
Figure: This figure summarizes the general architecture of our state model and React component tree

Example plugins

You can follow this guide for developing plugins, but you might also want to refer to working versions of plugins on the web now

This repo contains a template for creating new plugins https://github.com/GMOD/jbrowse-plugin-template.

Here are some examples of working plugins.

You can use these to see how plugins are generally structured, and can use the pluggable elements in them as templates for your own pluggable elements.

We will go over what plugins do and what is in them now

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 its configure method to 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 pieces of functionality that plugins can add to JBrowse. Examples of pluggable types include:

  • Adapters
  • Track types
  • Renderer types
  • Widgets
  • RPC calls
  • Display types
  • View types

In additional to creating plugins that create new 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

Adapters

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

Example adapters: the @jbrowse/plugin-alignments plugin creates multiple 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

Displays

A display is a method for displaying a particular track in a particular view

For example, we have a notion of a synteny track type, and the synteny track type has two display models

  • DotplotDisplay, which is used in the dotplot view
  • LinearSyntenyDisplay, which is used in the linear synteny view

This enables a single track entry to be used in multiple view types e.g. if I run jbrowse add-track myfile.paf, this automatically creates a synteny track that can be opened in both a dotplot and a linear synteny view.

Most track types only have a "linear" display available, but one more example is the VariantTrack, which has two display methods

  • LinearVariantDisplay - used in linear genome view
  • ChordVariantDisplay - used in the circular view

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-like circular 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

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: () => {},
},
],
},
]
This screenshot shows all the various track menu options, generated by the code listing
Figure: This screenshot shows all the various track menu options, 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.

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.
Figure: 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 top-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 => ({
trackMenuItems() {
return [
{
label: 'Menu Item',
icon: AddIcon,
onClick: () => {},
},
]
},
}))

Note that it is also common to use this scenario, because the base display may implement track menu items so this is like getting the superclasses track menu items

types
.model({
// model
})
.views(self => {
const { trackMenuItems: superTrackMenuItems } = self
return {
get trackMenuItems() {
return [
...superTrackMenuItems(),
{
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 extending the contextMenuItems view of the display model. Here is an example:

class SomePlugin extends Plugin {
name = 'SomePlugin'

install(pluginManager) {
pluginManager.addToExtensionPoint(
'Core-extendPluggableElement',
pluggableElement => {
if (pluggableElement.name === 'LinearPileupDisplay') {
const { stateModel } = pluggableElement
const newStateModel = stateModel.extend(self => {
const superContextMenuItems = self.contextMenuItems
return {
views: {
contextMenuItems() {
const feature = self.contextMenuFeature
if (!feature) {
// we're not adding any menu items since the click was not
// on a feature
return superContextMenuItems()
}
return [
...superContextMenuItems(),
{
label: 'Some menu item',
icon: SomeIcon,
onClick: () => {
// do some stuff
},
},
]
},
},
}
})

pluggableElement.stateModel = newStateModel
}
return pluggableElement
},
)
}
}

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: `jexl:get(feature,'strand') == - 1 ? '#8F8FD8' : '#EC8B8B'`,
contextVariable: ['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 'contextVariable' 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

We use Jexl to express callbacks. See https://github.com/TomFrost/Jexl for more details.

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": "variant_colors",
"name": "volvox filtered vcf (green snp, purple indel)",
"category": ["VCF"],
"assemblyNames": ["volvox"],
"adapter": {
"type": "VcfTabixAdapter",
"vcfGzLocation": {
"uri": "volvox.filtered.vcf.gz",
"locationType": "UriLocation"
},
"index": {
"location": {
"uri": "volvox.filtered.vcf.gz.tbi",
"locationType": "UriLocation"
}
}
},
"displays": [
{
"type": "LinearVariantDisplay",
"displayId": "volvox_filtered_vcf_color-LinearVariantDisplay",
"renderer": {
"type": "SvgFeatureRenderer",
"color1": "jexl:get(feature,'type')=='SNV'?'green':'purple'"
}
}
]
}

This draws all SNV (single nucleotide variants) as green, and other types as purple (insertion, deletion, other structural variant).

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', locationType: 'UriLocation' },
},
// 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',
locationType: 'UriLocation',
},
},
}),
},
{ explicitlyTyped: true },
)

Reading the sub-config schema is as follows

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

Alternatively can use

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

However, this may miss default values from the slot, the readConfObject has special logic to fill in the default value

Creating adapters

What is an adapter

An adapter is essentially a class that fetches and parses your data and returns it in a format JBrowse understands.

For example, if you have some data source that contains genes, and you want to display those genes using JBrowse's existing gene displays, you can write a custom adapter to do so. If you want to do a custom display of your data, though, you'll probably need to create a custom display and/or renderer along with your adapter.

What types of adapters are there

  • Feature adapter - This is the most common type of adapter. Essentially, it takes a request for a region (a chromosome, starting position, and ending position) and returns the features (e.g. genes, reads, variants, etc.) that are in that region. Examples of this in JBrowse include adapters for BAM and VCF file formats.
  • Regions adapter - This type of adapter is used to define what regions are in an assembly. It returns a list of chromosomes/contigs/scaffolds and their sizes. An example of this in JBrowse is an adapter for a chrome.sizes file.
  • Sequence adapter - This is basically a combination of a regions adapter and a feature adapter. It can give the list of regions in an assembly, and can also return the sequence of a queried region. Examples of this in JBrowse include adapters for FASTA and .2bit file formats.
  • RefName alias adapter - This type of adapter is used to return data about aliases for reference sequence names, for example to define that "chr1" is an alias for "1". An example of this in JBrowse is an adapter for (alias files)[http://software.broadinstitute.org/software/igv/LoadData/#aliasfile]
  • Text search adapter - This type of adapter is used to search through text search indexes. Returns list of search results. An example of this in JBrowse is the trix text search adapter.

Note about refname alias adapter: the first column must match what is seen in your FASTA file

Skeleton of a feature adapter

A basic feature adapter might look like this (with implementation omitted for simplicity):

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

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

Example feature 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 {
// your constructor gets a config object that you can read with readConfObject
// if you use "subadapters" then you can initialize those with getSubAdapter
constructor(config, getSubAdapter) {
const fileLocation = readConfObject(config, 'fileLocation')
const subadapter = readConfObject(config, 'sequenceAdapter')
const sequenceAdapter = getSubAdapter(subadapter)
}

// use rxjs observer.next(new SimpleFeature(...your feature data....) for each
// feature you want to return
getFeatures(region, options) {
return ObservableCreate(async observer => {
try {
const { refName, start, end } = region
const response = await fetch(
'http://myservice/genes/${refName}/${start}-${end}',
options,
)
if (response.ok) {
const features = await result.json()
features.forEach(feature => {
observer.next(
new SimpleFeature({
uniqueID: `${feature.refName}-${feature.start}-${feature.end}`,
refName: feature.refName,
start: feature.start,
end: feature.end,
}),
)
})
observer.complete()
} else {
throw new Error(`${response.status} - ${response.statusText}`)
}
} 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 feature 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)

The region parameter contains

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

The refName, start, end specify a simple genomic range. The "assemblyName" is used to query a specific assembly if your adapter responds to multiple assemblies e.g. for a synteny data file or a REST API that queries a backend with multiple assemblies.

The "originalRefName" are also passed, where originalRefName is the queried refname before ref renaming e.g. in BamAdapter, if the BAM file uses chr1, and your reference genome file uses 1, then originalRefName will be 1 and refName will be chr1

The options parameter to getFeatures 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 from getFeatures. 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 adapters make this an empty function

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

Writing your own plugin

JBrowse 2 plugins can be used to add new pluggable elements (views, tracks, 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.

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/',
locationType: 'UriLocation',
},
},
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": "FeatureTrack",
"trackId": "genehancer_ucsc",
"name": "UCSC GeneHancer",
"assemblyNames": ["hg38"],
"adapter": {
"type": "UCSCAdapter",
"track": "geneHancerInteractionsDoubleElite"
}
}

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(
() =>
new ArcRenderer({
name: 'ArcRenderer',
ReactComponent: ArcRendererReactComponent,
configSchema: ArcRendererConfigSchema,
pluginManager,
}),
)
}
}

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 reactElement = React.createElement(
this.ReactComponent,
{
...renderProps,
width,
height,
imageData,
},
null,
)
return { reactElement, 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
Figure: 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 {
reactElement: 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 => {
const { renderProps: superRenderProps } = self
return {
renderProps() {
return {
...superRenderProps(),
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,
pluginManager,
}),
)
}
}

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 adapter's getFeatures function, but if you need tighter control over how your 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)

For examples of custom track types, refer to things like

  • HicTrack, which uses a custom HicRenderer to draw contact matrix
  • GDCPlugin, which has a custom track type that registers custom feature detail widgets
  • VariantTrack, which also registers custom widgets, and has ChordVariantDisplay and LinearVariantDisplay
  • SyntenyTrack, which can be displayed with DotplotDisplay or LinearSyntenyDisplay

FAQ

General

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

See the https://jbrowse.org/jb2/features page for an overview of features

Setup

What web server do I need to run JBrowse 2

JBrowse 2 by itself is just a set of JS, CSS, and HTML files that can be statically hosted on a webserver without any backend services running.

Therefore, running JBrowse 2 generally involves just copying the JBrowse 2 folder to your web server html folder e.g. /var/www/html/.

If you use a different platform such as Django, you may want to put it in the static resources folder.

Note that the server that you use should support byte-range requests (e.g. the Range HTTP header so that JBrowse can get small slices of large binary data files.

BAM files do not work on my server

If you are using Apache then you will probably want to disable mime_magic. If mime_magic is enabled, you may see that your server responds with the HTTP header Content-Encoding: gzip which JBrowse does NOT want, because this instructs the browser to unzip the data but JBrowse should be in charge of this.

How can I setup JBrowse 2 on my web server

We recommend following the steps in the quickstart web guide.

The general procedure is using the jbrowse create /var/www/html/jb2 and this will download the latest version of jbrowse to your web folder e.g. in /var/www/html

You can also use jbrowse upgrade /var/www/html/jb2 to get the latest version

How do I install or update the @jbrowse/cli tool

To install the @jbrowse/cli tool, you can use npm install -g @jbrowse/cli

You can use this same command to upgrade the tool too

This command will give you a command named jbrowse which should automatically be in your path if you have a standard installation of nodejs. We recommend using nodesource or nvm to get your nodejs for this.

Also note that the @jbrowse/cli tool is just made for preparing your config.json, it is not used to run any server-side code

How do I update my instance of jbrowse-web

You can use the command, after installing

jbrowse upgrade /path/to/your/jbrowse2

This will download the latest release from github and overwrite it onto your jbrowse-web instance

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 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.

Why do some of my reads not display soft clipping

Some reads, such as secondary reads, do not have a SEQ field on their records, so they will not display softclipping.

The soft clipping indicators on these reads will appear black.

Text searching

Why I am running out of disk space while trix is running

The jbrowse text-index program will output data to a TMP directory while indexing. If your filesystem has low diskspace for /tmp you can set an alternative temporary directory using the environment variable TMPDIR=~/alt_tmp_dir/ jbrowse text-index.

How does the jbrowse text-index trix format work

The jbrowse text-index command creates text searching indexes using trix. The trix indexes are based on the format described by UCSC here https://genome.ucsc.edu/goldenPath/help/trix.html but we reimplemented the code the create these index formats in the JBrowse CLI so you do not have to install the UCSC tools.

The main idea is that you give trix

GENEID001  Wnt signalling
GENEID002 ey Pax6

Then this will generate a new file, the .ix file, sorted in alphabetical order

ey  GENE002
signalling GENE001
Pax6 GENE002
Wnt GENE001

Then a second file, the .ixx file, tells us at what byte offset certain lines in the file are e.g.

signa000000435

Note that JBrowse creates a specialized trix index also. Instead of creating a ix file with just the gene names, it also provides their name and location in an encoded format.

Developers

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

What technologies does JBrowse 2 use

We build on a lot of great open source technology, some main ones include

  • React
  • mobx-state-tree
  • web-workers
  • Typescript
  • Electron (for desktop specifically)
Should I configure gzip on my web server

Yes! JBrowse 2 may load ~5MB of JS resources (2.5MB for main thread bundle, 2.5MB for worker bundle). If you have gzip enabled, the amount of data the user has to download though is only 1.4MB. We have worked on making bundle size small with lazy loading and other methods but adding gzip will help your users.

It will depend on your particular server setup e.g. apache, nginx, cloudfront, etc. how this may be done, but it is recommended to look into this.


  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.