Getting started

Build a point chart from a Python table, then apply the same grammar to genomic intervals. The examples use plain Python records, so you do not need pandas or prior genomics knowledge.

GenomeSpy uses a declarative visualization grammar: you describe what the chart should show, and GenomeSpy determines how to draw it. A chart description has three central ingredients:

  • data: the values you want to show;

  • a mark: the shape used to represent a row, such as a point or rectangle;

  • encodings: rules that map data fields to visible properties.

Your Python objects become a validated GenomeSpy specification, which the browser renders. The specification follows the GenomeSpy visualization grammar, so its documentation applies to the charts you write here.

Install

GenomeSpy Python requires Python 3.11 or newer.

From PyPI

pip install genome-spy-python

For notebook use, install the Arrow extra so PyArrow is available for dataframe transport:

pip install "genome-spy-python[arrow]"

From source

pip install uv
git clone https://github.com/genome-spy/genome-spy-python.git
cd genome-spy-python
uv sync

Notebook rendering loads the pinned GenomeSpy JavaScript bundle from a CDN, so the browser needs network access when a chart first appears.

Start a notebook and import the package:

import genome_spy as gs

Start with a small table

This table contains six records, represented by Python dictionaries. Each record is one row. The keys day, value, and group name the table’s fields, or columns.

measurements = [
    {"day": 1, "value": 4.2, "group": "A"},
    {"day": 1, "value": 3.4, "group": "B"},
    {"day": 2, "value": 5.1, "group": "A"},
    {"day": 2, "value": 4.6, "group": "B"},
    {"day": 3, "value": 5.8, "group": "A"},
    {"day": 3, "value": 5.2, "group": "B"},
]

Choose a mark

A point mark asks GenomeSpy to draw one point for every record:

points = gs.Chart(measurements).mark_point(size=100)

Without positional encodings, all six points overlap. An encoding assigns each point a position.

Map fields to visual channels

A channel is the visual property controlled by an encoding. The x channel controls horizontal position:

positioned_points = points.encode(x=gs.X("day:O"))

The text "day:O" contains a field name and a type code. A data type tells GenomeSpy how values should behave:

Code

Type

Use it for

Q

quantitative

Numeric amounts that can be compared mathematically

N

nominal

Unordered names or categories

O

ordinal

Values with a meaningful order or sequence

Day is ordinal because day 1 comes before day 2. The measured value is quantitative, while the groups are nominal categories:

encoded_points = positioned_points.encode(
    y=gs.Y("value:Q"),
    color=gs.Color("group:N"),
)

The explicit gs.Y("value", type="quantitative") form means the same thing as gs.Y("value:Q"). The shorthand is convenient once the type codes are familiar.

Adjust scales and guides

A scale converts data values into positions, colors, or sizes. An axis is the visible guide for a positional scale, while a legend explains a color, size, or shape scale.

Guide titles label the mappings. Setting zero=False lets the vertical scale focus on the observed values instead of including zero:

measurement_chart = encoded_points.encode(
    x=gs.X("day:O").title("Day"),
    y=gs.Y("value:Q").scale(zero=False).title("Measured value"),
    color=gs.Color("group:N").legend(title="Group"),
)

Make a genomic interval track

GenomeSpy extends the same grammar with chromosome-aware positions. A genomic interval describes a span from a start position to an end position on a chromosome.

The example uses three intervals on chromosome 17:

features = [
    {"chrom": "chr17", "start": 43_044_000, "end": 43_050_000, "kind": "A"},
    {"chrom": "chr17", "start": 43_057_000, "end": 43_061_000, "kind": "B"},
    {"chrom": "chr17", "start": 43_068_000, "end": 43_075_000, "kind": "A"},
]

Use a rectangle mark for each interval. The x encoding maps the start, and x2 maps the other edge of the rectangle:

genomic_track = (
    gs.Chart(features)
    .mark_rect()
    .encode(
        x=gs.Locus("chrom", "start").scale(
            domain=[
                {"chrom": "chr17", "pos": 43_040_000},
                {"chrom": "chr17", "pos": 43_080_000},
            ]
        ),
        x2=gs.Locus("chrom", "end"),
        y=gs.Y("kind:N").title("Feature kind"),
        color=gs.Color("kind:N").legend(None),
    )
    .properties(assembly="hg38")
)

gs.Locus("chrom", "start") combines a chromosome field and a position field into a locus, meaning a place in the genome. The hg38 genome assembly supplies the chromosome names, lengths, and order needed by the locus scale.

The scale’s domain chooses the region the chart opens on. Without it the view would span all three billion bases of the assembly, leaving these features too small to see. Drag and scroll the chart to move beyond that opening window.

These example intervals use zero-based, half-open coordinates: the start is included and the end is excluded. This is the convention used by formats such as BED. Other formats may require a coordinate offset, as described in genomic coordinates.

Where to go next