jbrowse-anywidget
jbrowse-anywidget renders a
JBrowse 2 linear genome view as an anywidget, drawn on
the GPU. One bundle runs in Jupyter, JupyterLab, VS Code, marimo, and Google
Colab, with two-way sync of the visible region between Python and the view: set
view.location to navigate, read it back to get where the user panned.
LinearGenomeView covers the common case. For comparative genomics,
JBrowseApp drives the full app from a declarative views list, so a notebook
can also hold a linear synteny view or a dotplot (synteny_view, dotplot_view
build the specs). See the E. coli example below.
It replaces the older Dash-based jbrowse-jupyter + dash_jbrowse stack with a
prebuilt ESM bundle loaded by anywidget, so there is no Dash server to run and
no component-generation step.
Install from GitHub for now (below). A PyPI release is planned, after which
pip install jbrowse-anywidget will work directly. The example notebooks each
open in Colab with one click.
Install
pip install "jbrowse-anywidget @ git+https://github.com/GMOD/jbrowse-anywidget"
In Google Colab, also enable third-party widgets once per notebook:
from google.colab import output
output.enable_custom_widget_manager()
The config the widget takes
Assemblies, tracks, and sessions are the same JSON-like config JBrowse uses everywhere, handed straight to the view, so every track type and adapter works with no Python wrapper to keep in sync.
from jbrowse_anywidget import LinearGenomeView, make_assembly
view = LinearGenomeView(
assembly=make_assembly("hg38", ".../hg38.fa.gz"),
location="10:29,838,565..29,838,850",
)
view.add_track({
"type": "AlignmentsTrack",
"trackId": "reads",
"name": "reads",
"assemblyNames": ["hg38"],
"adapter": {"type": "CramAdapter", "uri": ".../reads.cram"}, # GPU pileup
})
view # display the widget
view.location # read back the current region after panning
Python adds only what JSON can't express itself: add_features (turn an
in-memory pandas DataFrame into a track, no file written) and make_assembly (a
little assembly boilerplate).
For human and model-organism data, fetch_hub("hg38") (also hg19, mm10, or
a GenArk GCA_...) returns a ready, CORS-enabled assembly config from
genomes.jbrowse.org (sequence, refName aliases,
cytobands, a gene-name search index, and a catalog of hosted tracks) as plain
JSON you pass in. Because the assembly carries refName aliases, your own tracks
line up even when they name chromosomes differently (chr17 vs 17).
Example notebooks
Each opens in Colab and runs top-to-bottom.
| Notebook | What it shows |
|---|---|
| Quickstart | An assembly, a track by URL, two-way location sync |
| bioframe → track | A bioframe result (real UCSC CpG islands → their shores) becomes a track |
| GPU alignments | A BAM/CRAM pileup, colored by pair orientation |
| Multi-sample variants | A multi-sample VCF as a per-sample band and a genotype matrix |
| Read depth from a BAM | Real 1000G NA12878 exome coverage over BRCA1, computed with pysam |
| Selection scan → view | Windowed Fst between two Drosophila populations; the sweep lands over Cyp6g1 (real DEST data) |
| Differential expression → view | Counts → log2FC, Welch t-test (scipy) + BH-FDR (statsmodels) → a colored gene track |
| Hosted assembly hub | fetch_hub for easy human data; navigate by gene name |
| Interactive controls | An ipywidgets slider re-runs the analysis and repaints the track |
| Region-reactive | Recompute pysam coverage only over the window in view, adapting to zoom |
| Compare genomes (synteny) | Four E. coli strains in a linear synteny view from one all-vs-all PAF |
| Large results | Where add_features stops being the right door, and writing a file starts |
| Large signal | Three routes for a quantitative track, which is the data type that gets big fastest |
Notebooks 05–07 are the core loop: run an analysis in Python, load the result
onto the genome, using the tools scientists already reach for (pysam,
bioframe, scipy/statsmodels) on real data. Notebooks 09–10 close the loop the
other way: a widget control or a pan in the view drives Python to recompute
and repaint live. Notebooks 12–13 are where a result outgrows that loop, since
add_features carries every row in the widget's own state.
See also
- Embedded components: the JS/React view this wraps
- JBrowseR: R/Shiny equivalent