import random
random.seed(3)
# Gene models: each gene is a set of exon [start, end] intervals, drawn connected.
genes = []
for j in range(4):
start = 40 + j * 120
exons = [[start + k * 30, start + k * 30 + 18] for k in range(random.randint(2, 4))]
genes.append({"id": f"GENE{j+1}", "dir": "right" if j % 2 == 0 else "left",
"fill": "rgb(70,130,220)", "outline": "rgb(0,0,0)", "data": exons})
# Coverage and expression: one entry per binned position, three tissues each.
offsets = [50 + i * 22 for i in range(22)]
coverage = [{"id": f"p{i}", "offset": o,
"data": [random.randint(8, 45), random.randint(8, 45), random.randint(8, 45)]}
for i, o in enumerate(offsets)]
express = [{"id": f"p{i}", "offset": o,
"data": [round(random.gauss(0, 1), 2) for _ in range(3)]}
for i, o in enumerate(offsets)]
# Variants: point markers at genomic positions.
snps = [{"id": f"rs{1000+k}", "offset": random.randint(45, 520),
"fill": "rgb(200,40,40)", "outline": "rgb(0,0,0)"} for k in range(9)]
data = {"tracks": [
{"name": "Genes (exon models)", "type": "box", "connect": True, "data": genes},
{"name": "Coverage — Heart / Liver / Kidney", "type": "bar", "height": 120,
"fill": "rgb(80,80,200)", "outline": "rgb(60,60,60)", "data": coverage},
{"name": "Expression (z-score)", "type": "heatmap", "height": 90, "data": express},
{"name": "SNPs", "type": "triangle", "data": snps},
]}Genome browser tracks in Python with canvasxpress
A genome browser view stacks tracks that share one coordinate axis: coverage, gene models, variants. In Python this usually means pyGenomeTracks or a static matplotlib figure. Here we build an interactive, zoomable view with canvasxpress — from one portable spec.
Install
pip install canvasxpressThe data shape
A Genome figure is a list of tracks that share one coordinate axis — each with a type. Real browser views stack several: here we build four — gene models (box, multi-exon, connected), coverage across three tissues (bar), an expression heatmap (heatmap), and variant markers (triangle).
The plot
from canvasxpress.canvas import CanvasXpress
from canvasxpress.render.jupyter import CXNoteBook
from IPython.display import display
config = {
"graphType": "Genome",
"background": "rgb(245,245,245)",
"featureStaggered": True,
"title": "Multi-track genome browser: genes, coverage, expression and variants",
}
cx = CanvasXpress(render_to="genome", data=data, config=config, width=760, height=520)
for part in CXNoteBook(cx).render():
display(part)Scroll/drag to pan and zoom into a region; every track stays locked to the shared coordinate axis, so the gene models, coverage, expression and variants line up position-for-position. Swap each track for your own pileup, annotation and VCF-derived data.
Why “reproducible”
The tracks and config are the figure — one portable JSON spec that renders the identical browser view from R or JavaScript, and can be validated and re-rendered later.