Jupyter widgets
pip install react-bio-vizThe Python package wraps the React components as anywidget widgets. They run in JupyterLab, Jupyter Notebook 7, VS Code and Google Colab, with no extra installation step.
from react_bio_viz import MSA, read_fasta
msa = MSA(msa=read_fasta("alignment.fasta"), width=900, options={"tracks": ["conservation"]})msaWidgets
Section titled “Widgets”| Class | Data | Interactive traits (read, write, observe) |
|---|---|---|
MSA |
msa |
viewport, selection, row_order, panel_sizes |
PhyloTree |
tree |
viewport, selection; leaf_order (read-only) |
DistanceMatrix |
labels, matrix |
viewport, row_order, panel_sizes |
GeneModel |
gene |
viewport |
GenomeBrowser |
tracks, reference_length |
viewport |
BlastHitDistribution |
hits, query_length |
viewport, selection, metric |
Trait names are the React props in snake_case (show_branch_lengths, leaf_spacing, …). Values
that are data — viewports, selections, options — keep their camelCase keys, as documented for the
components. The one exception is
PhyloTree.tree_layout (the React layout prop), because ipywidgets reserves layout;
PhyloTree(layout="radial") is accepted as a shorthand.
State is traitlets
Section titled “State is traitlets”Every piece of interactive state is a synced traitlet, so the usual traitlets tools work:
msa.selection # read what the user selectedmsa.viewport = {**msa.viewport, "x0": 0, "x1": 60} # move the viewmsa.observe(lambda change: print(change["new"]["columns"]), names="selection")Callbacks run outside any cell. To see their output, print into an
ipywidgets.Output.
Linking widgets
Section titled “Linking widgets”row_order has the same shape on MSA and DistanceMatrix, and a tree’s leaf_order is a valid
row order, so linking views is one line each:
import traitlets
traitlets.link((msa, "row_order"), (matrix, "row_order")) # both waystraitlets.dlink((tree, "leaf_order"), (msa, "row_order")) # rows follow the treeEvents
Section titled “Events”User actions that aren’t state arrive through callbacks. The widgets never change their own data, so you apply the edit and assign the new data back:
| Method | Called with |
|---|---|
MSA.on_rename_row(fn) |
row_id, new_name |
MSA.on_remove_rows(fn) |
row_ids |
MSA.on_remove_columns(fn) |
columns (indices into the current alignment) |
PhyloTree.on_node_click(fn) |
node: id, name, isLeaf, leafNames, descendantIds, rerootAbove, … |
PhyloTree.on_branch_click(fn) |
node below the branch |
def remove_rows(row_ids): msa.msa = [r for r in msa.msa if r.get("id", r["identifier"]) not in row_ids]
msa.on_remove_rows(remove_rows)Registering a handler also turns on the matching control, such as the × on a label or Delete on a selection.
Reading files
Section titled “Reading files”| Function | Returns |
|---|---|
read_fasta(path), parse_fasta(text) |
[{"identifier", "sequence"}, …] |
read_newick(path), parse_newick(text) |
{"name", "length", "children"} |
to_newick(tree) |
a Newick string (names quoted where needed) |
blast_hits_from_result(result) |
BlastHitDistribution rows from a betula BlastResult (blastserver’s output) |
These are the betula shapes, so JSON from picea, acacia or
blastserver works as is, and any other parser does too as long as it produces them. Biopython records, for
example, convert in one line:
[{"identifier": r.id, "sequence": str(r.seq)} for r in AlignIO.read(path, "fasta")].