Quickstart
Three entry points cover most work: the reference genome, a single-source experiment
dataset built from a publication, and a multi-source dataset queried out of the served
knowledge graph. Every block below states what it needs. Blocks marked
requires DATA_ROOT read files from the data root described in
Installation; blocks marked requires the served database open a
Neo4j connection.
Load the reference genome
Requires DATA_ROOT. SCerevisiaeGenome
(torchcell.sequence.genome.scerevisiae.s288c) resolves the SGD R64-4-1 S288C release
from the genomes tier at $DATA_ROOT/torchcell-genomes/, verifying each file’s sha256
against the tier’s manifest.json on every load. There is no fallback location: a
machine without the tier raises FileNotFoundError with the command that seeds it.
genome_root is only a cache directory for the gffutils database (data.db) and must
already exist. With overwrite=False (the default) the database is built only when it
is absent and is otherwise opened after its record is verified; overwrite=True
rebuilds it. go_root holds
go.obo, which is downloaded from geneontology.org only when it is missing.
import os
import os.path as osp
from torchcell.sequence.genome.scerevisiae.s288c import SCerevisiaeGenome
genome = SCerevisiaeGenome(
genome_root=osp.join(os.environ["DATA_ROOT"], "data/sgd/genome"),
go_root=osp.join(os.environ["DATA_ROOT"], "data/go"),
overwrite=False,
)
print(len(genome.gene_set))
gene = genome["YAL001C"]
print(gene.id, gene.chromosome, gene.strand, gene.start, gene.end, len(gene.seq))
Output (run with genome_root pointed at a scratch cache directory, which does not
change the result):
6607
YAL001C 1 - 147594 151166 3573
Load an experiment dataset
Requires DATA_ROOT; the first build also needs the network. Each publication-backed
loader is an ExperimentDataset subclass (see Datasets) whose default
root is relative, for example data/torchcell/smf_costanzo2016. Pass an absolute root
under $DATA_ROOT. If processed/lmdb is absent, the loader downloads its raw files
(for SmfCostanzo2016Dataset, from thecellmap.org) and builds the LMDB; if it is
present, the loader reads it and never touches the network.
import os
import os.path as osp
from torchcell.datasets.scerevisiae.costanzo2016 import SmfCostanzo2016Dataset
dataset = SmfCostanzo2016Dataset(
root=osp.join(os.environ["DATA_ROOT"], "data/torchcell/smf_costanzo2016")
)
print(dataset)
item = dataset[0]
print(sorted(item))
typed = dataset.transform_item(item)
print(type(typed["experiment"]).__name__, typed["experiment"].phenotype.fitness)
print(len(dataset.gene_set), len(dataset.experiment_reference_index))
Output (run against a read-only copy of a built processed/ and preprocess/):
SmfCostanzo2016Dataset(20484)
['experiment', 'publication', 'reference']
FitnessExperiment 0.9395
5493 2
dataset[i] returns plain dictionaries; transform_item validates them into the typed
Experiment, ExperimentReference and Publication models. experiment_reference_index
groups records by the reference they share; this dataset has two (its 26 C and 30 C
screens carry different references).
Query the served knowledge graph
Requires the served database (connection from NEO4J_URI, NEO4J_USER,
NEO4J_PASSWORD) and DATA_ROOT for the output directory. None of the code in this
section was run for this page.
Neo4jQueryRaw
torchcell.data.neo4j_query_raw.Neo4jQueryRaw runs one Cypher query and caches every
returned record in an LMDB at <root_dir>/raw/lmdb. It is an attrs class; its
constructor arguments are:
Neo4jQueryRaw(
uri: str,
username: str,
password: str,
root_dir: str,
query: str,
io_workers: int | None = None,
num_workers: int | None = None,
cypher_kwargs: dict[str, str | int | float | list[Any]] = {}, # attrs factory=dict
version: str | None = None,
)
The query runs once, on construction, when <root_dir>/raw/lmdb/data.mdb does not yet
exist; later constructions open the cached LMDB read-only. cypher_kwargs are passed to
session.run as query parameters, so a query that filters on $gene_set gets
cypher_kwargs={"gene_set": [...]}. version names the knowledge-graph release to open
and defaults to TORCHCELL_KG_VERSION (see Choosing a release).
Each result row must have one of two shapes:
Shape |
|
When to use |
|---|---|---|
Property |
|
Required for large queries: the driver does not cache hydrated nodes, so memory stays flat. |
Node |
|
Supported for the historical queries under |
e is the Experiment node and ref its ExperimentReference. Each stored record is
revalidated through EXPERIMENT_TYPE_MAP and EXPERIMENT_REFERENCE_TYPE_MAP from
torchcell.datamodels.schema, keyed by the record’s experiment_type.
Neo4jCellDataset
torchcell.data.neo4j_cell.Neo4jCellDataset wraps the raw query in a processing
pipeline and returns graph-ready items. Its constructor arguments:
Neo4jCellDataset(
root: str,
query: str | None = None,
gene_set: GeneSet | None = None,
graphs: GeneMultiGraph | None = None,
incidence_graphs: dict[str, nx.Graph | hnx.Hypergraph] | None = None,
node_embeddings: dict[str, BaseEmbeddingDataset] | None = None,
graph_processor: GraphProcessor | None = None,
add_remaining_gene_self_loops: bool = True,
converter: type[Converter] | None = None,
deduplicator: type[Deduplicator] | None = None,
aggregator: type[Aggregator] | None = None,
overwrite_intermediates: bool = False,
uri: str | None = None,
username: str | None = None,
password: str | None = None,
transform: Callable[..., Any] | None = None,
pre_transform: Callable[..., Any] | None = None,
pre_filter: Callable[..., Any] | None = None,
phenotype_labels: list[str] | None = None,
)
converter, deduplicator and aggregator are passed as classes; process()
instantiates them. uri, username and password default to the environment. The
gene_set is sent to the query as $gene_set. On first construction process() runs
the stages in order, each writing its own LMDB under root:
Stage |
LMDB |
Runs when |
|---|---|---|
raw |
|
always (the |
conversion |
|
|
deduplication |
|
|
aggregation |
|
|
processed |
|
always |
A finished stage writes a STAGE_COMPLETE file beside its LMDB, and a restarted build
skips stages that carry one. phenotype_labels selects and orders the phenotypes each
item carries by label_name (for example ["fitness", "gene_interaction"]); leave it
None only when the build holds a single phenotype.
The block below is the construction used by
experiments/025-solid-growth/scripts/query.py:
# Requires the served database and DATA_ROOT.
import os
import os.path as osp
from dotenv import load_dotenv
from torchcell.data import GenotypeAggregator, MeanExperimentDeduplicator
from torchcell.data.graph_processor import SubgraphRepresentation
from torchcell.data.neo4j_cell import Neo4jCellDataset
from torchcell.datamodels.fitness_composite_conversion import CompositeFitnessConverter
from torchcell.sequence.genome.scerevisiae.s288c import SCerevisiaeGenome
load_dotenv()
data_root = os.environ["DATA_ROOT"]
with open("experiments/025-solid-growth/queries/001_all_solid_growth.cql") as f:
query = f.read()
genome = SCerevisiaeGenome(
genome_root=osp.join(data_root, "data/sgd/genome"),
go_root=osp.join(data_root, "data/go"),
)
dataset = Neo4jCellDataset(
root=osp.join(data_root, "data/torchcell/experiments/025-solid-growth/001-full-build"),
query=query,
gene_set=genome.gene_set,
converter=CompositeFitnessConverter,
deduplicator=MeanExperimentDeduplicator,
aggregator=GenotypeAggregator,
graph_processor=SubgraphRepresentation(),
)
print(len(dataset))
print({k: len(v) for k, v in dataset.phenotype_label_index.items()})
CompositeFitnessConverter turns gene-essentiality and synthetic-lethality records into
fitness records (see Converters), which is what lets that query pool them with
measured fitness. dataset.phenotype_label_index, dataset.dataset_name_index and
dataset.perturbation_count_index map a label, a source dataset, or a perturbation count
to the item indices that carry it.
Inspect a stored record
A built experiment LMDB stores one pickled dictionary per record under the keys
"0", "1", and so on. Constant sub-objects that repeat across a dataset (the
environment, the reference, the publication) are stored once in a sibling interned
LMDB when their canonical JSON is at least INTERN_MIN_BYTES (512) long, and the record holds a {"$ref": <sha256>, "name": <hint>} pointer in their place.
torchcell.data.experiment_dataset.resolve_interned splices them back; a reader that
bypasses the dataset class must call it.
The script below opens the development build of SmfCostanzo2016Dataset read-only and
prints record 0:
import os.path as osp
import pickle
from pprint import pprint
import lmdb
from torchcell.data.experiment_dataset import resolve_interned
from torchcell.datamodels.schema import FitnessExperiment
root = "/scratch/projects/torchcell-scratch/data/torchcell/smf_costanzo2016/processed"
# Records and interned constants live in two sibling LMDB environments.
env = lmdb.open(osp.join(root, "lmdb"), readonly=True, lock=False)
ienv = lmdb.open(osp.join(root, "interned"), readonly=True, lock=False)
with ienv.begin() as txn:
interned = {k.decode(): pickle.loads(v) for k, v in txn.cursor()}
with env.begin() as txn:
print("records:", txn.stat()["entries"])
raw = pickle.loads(txn.get(b"0"))
print("keys:", sorted(raw))
print("stored environment:", raw["experiment"]["environment"])
record = resolve_interned(raw, interned)
experiment = FitnessExperiment(**record["experiment"])
print("experiment_type:", experiment.experiment_type)
print("dataset_name:", experiment.dataset_name)
pprint(experiment.genotype.model_dump(), width=88)
env_dump = experiment.environment.model_dump()
print("media.name:", env_dump["media"]["name"], "| state:", env_dump["media"]["state"])
print("temperature:", env_dump["temperature"])
pprint(experiment.phenotype.model_dump(), width=88)
print("publication:", record["publication"])
Output, verbatim (build of 2026-09-14):
records: 20484
keys: ['experiment', 'publication', 'reference']
stored environment: {'$ref': '424e6d43e0fcd66aa5490fdd3c0a9f92485038ab7157c1a4456769e91461d9aa', 'name': 'SGA double-mutant selection (SD-MSG, -His/Arg/Lys, +canavanine/thialysine/G418/clonNAT)'}
experiment_type: fitness
dataset_name: SmfCostanzo2016Dataset
{'perturbations': [{'damp_description': 'Damp Perturbation information specific to SGA '
'experiments.',
'damp_perturbation_type': 'SGA',
'description': '4-10 decreased expression via KANmx insertion at '
'the ',
'expression_range': {'max': 0.25, 'min': 0.1},
'mechanism_so_id': 'SO:0001060',
'mechanism_so_name': 'sequence_variant',
'perturbation_type': 'damp',
'perturbed_gene_name': 'tfc3_damp',
'provenance': 'engineered',
'strain_id': 'YAL001C_damp174',
'systematic_gene_name': 'YAL001C'}]}
media.name: SGA double-mutant selection (SD-MSG, -His/Arg/Lys, +canavanine/thialysine/G418/clonNAT) | state: solid
temperature: {'value': 26.0, 'unit': <TemperatureUnit.celsius: 'Celsius'>}
{'fitness': 0.9395,
'fitness_se': 0.0988,
'fitness_std': 0.0988,
'fitness_uncertainty': 0.0988,
'fitness_uncertainty_type': <UncertaintyType.bootstrap_se: 'bootstrap_se'>,
'graph_level': 'global',
'label_name': 'fitness',
'label_statistic_name': 'fitness_se',
'n_samples': 17,
'provenance_gaps': [],
'sample_unit': <SampleUnit.screen: 'screen'>}
publication: {'pubmed_id': '27708008', 'pubmed_url': 'https://pubmed.ncbi.nlm.nih.gov/27708008/', 'doi': '10.1126/science.aaf1420', 'doi_url': 'https://www.science.org/doi/10.1126/science.aaf1420'}
The record reads as one experiment: a genotype of one perturbation (a DAmP allele of
TFC3, systematic name YAL001C), an environment (the SGA selection medium, solid, at
26 C), and a fitness phenotype of 0.9395 with its uncertainty named as a bootstrap
standard error over 17 screens. Data model describes each part.