Data and chart inputs¶
GenomeSpy works with tabular data: rows are records, and columns are named fields. Encodings refer to those field names when they assign values to position, color, size, or another visual channel.
Records and fields¶
A list of dictionaries is the smallest useful input. Each dictionary below is one observation with the same three fields:
Pass the records as the first argument to Chart:
import genome_spy as gs
measurements = [
{"sample": "A", "time": 0, "value": 2.1},
{"sample": "A", "time": 1, "value": 3.4},
{"sample": "A", "time": 2, "value": 4.0},
{"sample": "B", "time": 0, "value": 1.8},
{"sample": "B", "time": 1, "value": 2.7},
{"sample": "B", "time": 2, "value": 3.6},
]
inline_chart = (
gs.Chart(measurements)
.mark_point(size=90)
.encode(
x=gs.X("time:O").title("Time"),
y=gs.Y("value:Q").scale(zero=False).title("Value"),
color=gs.Color("sample:N").legend(title="Sample"),
)
)
The chart includes these rows in the generated GenomeSpy specification, normally as a named dataset. Inline data is a good fit for examples and small tables because the specification remains self-contained. The GenomeSpy documentation describes this and the other eager sources in inline data.
DataFrames and Arrow tables¶
Chart also accepts these table objects directly:
pandas
DataFrame;Polars
DataFrame;PyArrow
TableandRecordBatch.
Use the same chart construction for any of them: gs.Chart. GenomeSpy
uses column names as fields. A pandas index is not a field, so call
frame.reset_index() first when an index contains values needed by the chart.
Notebook display and live updates use Arrow IPC for supported tables when available. See Create and update charts in notebooks for setup and transport details.
The grammar is easiest to use with long-form data, where one row represents
one observation and categories such as sample are stored as values in a
field. If category names are spread across several columns, reshape the table
before constructing the chart or use a suitable GenomeSpy transform.
Try it with packaged data¶
The package ships the tables used by the gallery examples:
from genome_spy.datasets import load_dataset
gwas = load_dataset("hapmap_gwas")
Example datasets lists them and their sources.
Load a URL in the browser¶
For a CSV, TSV, JSON, or another eager file source, use Data with a URL.
The format can often be inferred from the filename, but an explicit format
makes the intended parsing clear:
url_chart = (
gs.Chart(
gs.Data(
url="https://example.org/measurements.csv",
format=gs.data_format(type="csv"),
)
)
.mark_point()
.encode(x="time:O", y="value:Q", color="sample:N")
)
The URL is loaded by the browser that renders GenomeSpy, not by Python. It must therefore be reachable from that browser and permit cross-origin access when it uses another domain. A relative URL is resolved against the page containing the visualization; it is not automatically resolved against the Python working directory.
URL data is useful when embedding the rows would make the specification too large. Indexed genomic formats use a separate lazy-loading API described later in the genomic data guide.
The GenomeSpy documentation lists the supported tabular formats and their parsing options under URL data.
Inherit data in a composed view¶
Data declared on a parent view is available to its children. This avoids repeating the same source when several layers use the same rows:
points = (
gs.Chart()
.mark_point(size=90)
.encode(
x="time:O",
y=gs.Y("value:Q").scale(zero=False),
color="sample:N",
)
)
labels = (
gs.Chart()
.mark_text(dy=-12)
.encode(
x="time:O",
y="value:Q",
text="value",
color="sample:N",
)
)
inherited_chart = (points + labels).properties(
data=measurements,
title="Measurements over time",
)
Here, neither child chart declares data. The layered parent owns one copy of
measurements, and both the point and text marks read it.
Reuse a table across charts¶
You can pass the same table to several charts. Like Altair, the wrapper stores equal record tables once in the exported specification and lets each chart refer to that copy:
rows = [{"x": 1, "y": 2}, {"x": 2, "y": 4}]
points = gs.Chart(rows).mark_point().encode(x="x:Q", y="y:Q")
bars = gs.Chart(rows).mark_bar().encode(x="x:Q", y="y:Q")
inline_chart = points | bars
This happens automatically for ordinary records and tables exported as records. It reduces repeated data in JSON, HTML, and gallery charts. Notebook displays keep using Arrow for supported tables. URLs and sources that need special parsing retain their existing data definitions.
For a stable name you can use in notebook updates, declare the
table yourself and reference it with Data:
points = gs.Chart(gs.Data(name="measurements")).mark_point().encode(x="x:Q", y="y:Q")
bars = gs.Chart(gs.Data(name="measurements")).mark_bar().encode(x="x:Q", y="y:Q")
chart = (points | bars).properties(datasets={"measurements": rows})
Different explicit names remain independent, even when their initial rows are equal. Avoid relying on automatically generated names for updates.
To export each inline table separately, temporarily disable consolidation with
gs.data_transformers.enable:
with gs.data_transformers.enable(consolidate_datasets=False):
spec = inline_chart.to_dict()
This affects automatic sharing; explicitly named datasets stay named. A large unique table still takes space, so consider URL data or Arrow notebook transport when removing repeated copies is not enough.
Prepare in Python or transform in the chart?¶
Prepare data in Python when the work is independent of the visualization—for example, validating identifiers, reshaping a wide table, or calculating a statistical result. This keeps analysis explicit and testable.
Use a GenomeSpy transform when the operation belongs to the visualization, such as filtering visible rows, deriving a label, aggregating marks, or reacting to an interactive parameter. Transforms run in the browser before marks are drawn and are covered in the transforms guide.