GRNLab

GRNLab (Python)

A data generator for gene regulatory networks (GRNs) with Hill-function kinetics. Every dataset comes with the ground truth that produced it: the signed regulatory network, every kinetic parameter, the initial conditions, the seeds, and the solver settings. GRNLab generates data; it does not infer, recover, or score networks.

This is the Python implementation of the GRNLab MATLAB toolbox. The two share the same functions, options, conventions, kinetics, integrators, accuracy audit, and figure style. Seeds are reproducible within each implementation but not across the two (different random-number streams).

Installation

pip install grnlab

Requires Python 3.9 or newer, NumPy, SciPy, and Matplotlib.

Ten lines to a dataset

import grnlab as grn

grn.catalog()                                          # motifs and random topologies

S     = grn.random_network(30, topology="scalefree", seed=2)          # ground truth
model = grn.build_model(S, logic="multiplicative", seed=2)            # kinetics
sol   = grn.simulate(model, cells=50, random_ic=True,
                     noise="langevin", noise_strength=0.2, seed=2)    # data

sol.x.shape            # (501, 30, 50): samples x genes x cells
sol.S                  # the signed adjacency that generated the data
grn.plot_network(model)            # arrowheads = activation, bars = repression
grn.plot_expression(sol, cell=2)
grn.export(sol, "grn30.csv")       # + grn30_truth.csv, grn30_adjacency.csv

Conventions

Motifs by name

sol = grn.simulate("repressilator")                  # oscillates (preset applied)
model = grn.build_model("toggle")                    # bistable
hi = grn.steady_state(model, initial_condition=[5, 0])
lo = grn.steady_state(model, initial_condition=[0, 5])
grn.plot_motifs()                                    # gallery of all ten

Registered motifs: toggle, repressilator, nar, par, ffl_coherent, ffl_incoherent, cascade, sim, bifan, goodwin.

Perturbations, steady states, screens

model = grn.build_model(grn.random_network(10, seed=3), seed=3)
sol = grn.simulate(model, knockout=3, overexpress="G7")
ko  = grn.knockout_screen(model, noise_sigma=0.05)   # ko.X: (n+1) x n, row 0 = wild type
kd  = grn.knockout_screen(model, type="knockdown")
xss, info = grn.steady_state(model, info=True)       # info["converged"], info["stable"]

Time-varying stimuli

on   = grn.stimulus("X", "step", baseline=0, amplitude=1, start=5)   # switch X on at t = 5
sol  = grn.simulate("ffl_incoherent", stimulus=on, duration=30)
sol.u                                                                # realised input, samples x n

pulse = grn.stimulus(0, "step", amplitude=3, start=5, stop=10)
ramp  = grn.stimulus(0, "ramp", baseline=0, amplitude=3, start=0, stop=40)
drive = grn.stimulus("G2", "sine", amplitude=3, period=12)
xss   = grn.steady_state(model, stimulus=ramp, time=20)              # stimulus held at t = 20

Stimuli scale (or, with mode="add", add to) a gene’s production rate. The ODE integration restarts at every stimulus edge, so steps are exact.

Two-stage mRNA/protein kinetics

model = grn.build_model("repressilator", stages=2)
sol = grn.simulate(model, duration=60)
sol.x.shape, sol.state_labels        # (601, 6), ('lacI_mRNA', ..., 'cI_protein')
grn.plot_expression(sol, species="mrna")

Figures

fig = grn.plot_network(model, layout="layered")     # circle, force, or layered
grn.export_figure(fig, "network.pdf")               # vector; .png at 300 dpi by default
fig = grn.plot_expression(sol)
grn.export_figure(fig, "expression.png", resolution=600)

Export

grn.export(data, "name.csv") writes the data table plus name_truth.csv (edge list: source, target, sign) and name_adjacency.csv. .npz stores the arrays and a pickled copy of the whole object under data; .pkl stores the object.

Documentation

The full user guide (13 chapters with worked examples, their output, and figures) is at almomaa.github.io/GRNLab/python.

Function reference

Function Purpose
catalog() List motifs and random topologies
motif(name, size=4) Signed adjacency, labels, and preset of a classic motif
random_network(n, topology, mean_degree, fraction_repressors, self_regulation, modules, within_fraction, rewire, seed, info) Random signed adjacency
build_model(S, logic, stages, seed, params, labels, name, hill_range, gamma_range, vmax_range, k_rel_range, basal_fraction, gammap_range, beta_ratio_range) Kinetic model with sampled parameters
perturb(model, knockout, knockdown, overexpress, knockdown_factor, overexpress_factor) Scale gene production
stimulus(gene, type, amplitude, baseline, start, stop, period, rise, mode, function, breaks) Time-varying input
stimulate(model, stim) Attach stimuli to a model
simulate(model, duration, sample_dt, transient, cells, random_ic, initial_condition, solver, noise, noise_strength, dt, noise_sigma, seed, knockout, knockdown, overexpress, ..., stimulus) Expression time series
steady_state(model, initial_condition, max_time, tol, ..., stimulus, time, info) Fixed point with Newton polish
knockout_screen(model, type, factor, genes, noise_sigma, seed, max_time, tol, stimulus, time) Steady states under single-gene perturbations
export(data, filename) .csv (+ ground-truth companions), .npz, .pkl
plot_network, plot_motifs, plot_expression, export_figure Figures
attach_handles(model) Rebuild handles after editing parameters by hand

Every function has a full docstring (help(grn.simulate)).

Accuracy

python -m grnlab.audit

runs 19 checks of the public API against closed-form results (exponential relaxation, Hill function values, analytic steady states, the repressilator’s Hopf threshold, the toggle switch’s bistability threshold, Euler–Maruyama convergence, Ornstein–Uhlenbeck and chemical-Langevin statistics, two-stage limits, exact step stimuli, knockout sign agreement, seeding) and writes AUDIT.md.

Development

pip install -e ".[test]"
pytest
python -m build            # sdist and wheel in dist/

License

MIT. Author: Abd AlRahman AlMomani, Embry-Riddle Aeronautical University.