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. JBrowseApp drives the full app from
a views list, so a notebook can also hold a linear synteny view or a dotplot.
Each entry is a view as a config's defaultSession.views writes it. See the E.
coli example below.
jbrowse-anywidget 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
A widget's keyword arguments are the JBrowse embedding options as JSON, passed through unchanged: assemblies, tracks and sessions are the same config objects JBrowse uses everywhere, so every track type, adapter and option works with no Python wrapper to keep in sync.
from jbrowse_anywidget import LinearGenomeView, features_track
view = LinearGenomeView(
assembly={"name": "mygenome", "uri": ".../mygenome.fa.gz"},
location="chr1:1..20,000",
tracks=[
{
"type": "AlignmentsTrack",
"trackId": "reads",
"name": "reads",
"assemblyNames": ["mygenome"],
"adapter": {"type": "CramAdapter", "uri": ".../reads.cram"},
}
],
)
view # display the widget
view.location # read back the current region after panning
view.update(tracks=[*view.options["tracks"], features_track(df, name="peaks")])
assembly also takes a hosted genome by name ("hg38", "mm39", or a GenArk
GCA_...), which brings refName aliases, cytobands and gene-name search from
genomes.jbrowse.org, so your own tracks line up
even when they name chromosomes differently (chr17 vs 17). update merges
keys into the options, and features_track turns an in-memory DataFrame into a
track with no file written.
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 | When to write a file to disk instead of passing data to features_track |
| Large signal | Three routes for a quantitative track, 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
features_track carries every row in the widget's own state.
See also
- Embedded components: the JS/React view this wraps
- JBrowseR: R/Shiny equivalent