Skip to content

iscc.tumor.GenotypeTumor

GenotypeTumor(config=None, seed=42, genome_params=None, selection_params=None, cancer_cell_params=None, deme_params=None, spatial_params=None, epithelial_cell_params=None, stromal_cell_params=None, immune_cell_params=None, host_cell_params=None, genome_mode='abstract', genome_spec=None, update_mode='exact', tau=1.0, snapshot_every=1, microenv_params=None, layout_seed=None, expression_params=None, coarsen_passengers=False, max_cells=None, germline_params=None, founder_mutations=None)

Genotype-level (count-based) tumour engine — the default, scalable iscc growth model.

The tumour grows on a grid of demes (lattice patches); each deme is represented as genotype counts over a shared registry rather than one Python object per cell, so it is spatially explicit at the deme level while every birth / death / mutation / dispersal event is O(1) integer arithmetic on counts. It realises the same evolutionary process as the cell-level GlandularTumor (statistically equivalent, roughly two orders of magnitude faster) and is the class most users should reach for. Typical flow: construct, call grow to run the dynamics, then read the per-cell ground truth off make_cell_data and quality-check it with diagnose.

The constructor takes either a single config YAML path (the usual entry point; see notebooks/example_config.yaml) or the individual nested-dict parameter blocks below. Only the top-level blocks are summarised here — every knob, with its default, valid range and effect, is covered in the parameter documentation.

Parameters:

Name Type Description Default
config str or Path

Path to a YAML config that defines all of the parameter blocks below (keys genome_params, selection_params, deme_params, spatial_params, cell_params and any optional layers). When given it overrides the individual arguments. This is the recommended entry point.

None
seed int

EVOLUTION seed (default 42): drives the per-run stochastic dynamics and the spatial seeding. Two runs differing only in seed are two patients with the same genome landscape but different evolution.

42
genome_params dict

Genome geometry — n_segments × segment_size set the gene count (default 5 × 200 = 1000 genes).

None
selection_params dict

The CINner fitness model — driver / dispersal / resistance proportions and effect sizes, viability limits, and the optional epistasis_params / dependency_params network layers.

None
cancer_cell_params dict

Cancer-cell dynamics — division_rate, death_rate, mutation_rate, n_snvs_per_allele, snv_prob / cnv_prob, amp_prob, wgd_rate.

None
deme_params dict

Per-deme demography — initial_cancer_cells, carrying_capacity, maximum_death_rate and the density-dependent crowding law.

None
spatial_params dict

Grid and tissue geometry, given as keys of this dict (not as individual constructor arguments): grid_size, dispersal_rate, structure_radius / n_structures (glandular substrate), and the optional compartment-selection hazards (epithelial_barrier, stromal_hazard).

None
epithelial_cell_params dict

Seeding parameters for each non-cancer (static) cell type — the tissue structure, cell-type labels and local immune density that the cancer death rate reads.

None
stromal_cell_params dict

Seeding parameters for each non-cancer (static) cell type — the tissue structure, cell-type labels and local immune density that the cancer death rate reads.

None
immune_cell_params dict

Seeding parameters for each non-cancer (static) cell type — the tissue structure, cell-type labels and local immune density that the cancer death rate reads.

None
host_cell_params dict

Seeding parameters for each non-cancer (static) cell type — the tissue structure, cell-type labels and local immune density that the cancer death rate reads.

None
genome_mode (abstract, real)

"abstract" (default) uses a random gene-driver layout; "real" wires the genome from human chromosome-arm data and requires genome_spec.

"abstract"
genome_spec GenomeSpec

Real-genome specification (required when genome_mode="real").

None
update_mode (exact, tau)

"exact" (default) is the reference one-event-per-update Gillespie engine; "tau" is tau-leaping (tau sets the generation length), whose cost scales with number-of-clones × number-of-generations instead of number-of-cells.

"exact"
tau float

Tau-leaping generation length, used only when update_mode="tau" (default 1.0).

1.0
snapshot_every int

Under tau-leaping, record a full per-clone snapshot every k generations (default 1) so the Muller / grid plots keep working.

1
microenv_params dict

Microenvironment layer (hypoxia field + cell-cell communication). Off by default; a pure readout that never changes growth.

None
expression_params dict

Gene-program expression layer (program_params, activity_params, coupling_params, dosage_params, snv_effect_params). Off by default; a readout only.

None
layout_seed int

GENOME-LAYOUT seed (config-determined, shared across runs of the same config): fixes driver identities and baseline expression so a cohort is comparable by construction. Defaults to the fixed DEFAULT_LAYOUT_SEED.

None
germline_params dict

Inherited (germline) variants — het_frac, hom_frac and an optional seed. Off by default; when given, neutral loci are seeded into every cell of the patient (tumour and normal alike) before growth, giving a DNA assay the constant background it reads purity and allelic imbalance against.

None
founder_mutations dict

The mutations the founder cell already carried when it transformed — n_passenger (the clock-like burden the normal lineage accumulated first), n_driver (the transforming hits) and an optional seed. Off by default; when given, they are written into the founder genome before growth, so every cancer cell inherits them and the tumour has the clonal peak real sequencing shows.

None

Methods:

Name Description
is_extinct

Whether the tumour has died out — True when the total deme event rate is zero.

get_tumor_size

Total number of live cells across all genotypes (cancer and normal).

grow

Advance the tumour by n_steps update steps and materialise the result.

truncal_sites

Locus indices of the tumour's trunk — the somatic variants essentially every cancer

primary_window

Deme indices of a rectangular window of the PRIMARY grid, centred on center

make_cell_data

Expand the per-deme genotype counts into per-cell ground-truth tables.

plot_muller

Render a Muller plot of the clonal dynamics (clone frequencies over steps, nested by ancestry).

plot_tissue

Deme-resolution tissue map built directly from the per-deme genotype COUNTS.

plot_phylogeny

Radial CLADE phylogeny drawn inline with matplotlib (Cassiopeia-style).

he_image

Dense H&E-like morphology image built from the per-deme cell COUNTS.

plot_grid

Plot the spatial deme grid, colouring each deme by a per-cell attribute.

plot_grid_compartments

Two spatial grids (primary + met) side by side, shared clone colormap. by_drivers

plot_muller_compartments

Two-band Muller (primary over met) sharing one colormap with the grids. by_drivers

plot_muller_founders

A SINGLE primary Muller highlighting the clone(s) that seeded the metastasis, so you can

plot_clone_tree

Ground-truth clone tree: the TRUE genotypes_parents genealogy collapsed to the

get_genotype_frequencies

Cancer-genotype ids and their frequencies (normal cell types excluded).

epistasis_ground_truth

The planted network — the answer key for MHN/TreeMHN/CBN/REVOLVER edge + order recovery.

event_table

Per-clone event sets and the ORDER this lineage acquired them (empty when epistasis is off).

diagnose

Flag degenerate ("crappy") tumour regimes after growth, with actionable hints.

write

Write the canonical iscc layout (so isccsample/isccdata can consume it).

write_h5ad

Write the whole tumour — cells, genes, clones and parameters — to one .h5ad file.

is_extinct

is_extinct()

Whether the tumour has died out — True when the total deme event rate is zero.

get_tumor_size

get_tumor_size()

Total number of live cells across all genotypes (cancer and normal).

grow

grow(n_steps=1000, seed=None, treatment=None, **kwargs)

Advance the tumour by n_steps update steps and materialise the result.

Runs the birth / death / mutation / dispersal process (exact Gillespie or tau-leaping, per update_mode), appending a population snapshot to self.traces each step, and finally calls make_cell_data to build the per-cell ground truth.

Parameters:

Name Type Description Default
n_steps int

Number of update steps to run (default 1000).

1000
seed int

Evolution seed for this call; defaults to the tumour's construction seed.

None
treatment Treatment

A therapy (e.g. Chemotherapy, TargetedTherapy, Immunotherapy, Surgery) whose dosing schedule and rate modifiers are applied each step; None (default) grows the tumour untreated.

None

Returns:

Type Description
list

self.traces — the list of per-step population snapshots.

truncal_sites

truncal_sites(ccf=0.95, cell_ids=None)

Locus indices of the tumour's trunk — the somatic variants essentially every cancer cell carries — MEASURED from the cells rather than looked up.

The founder starts with a blank genome, so a tumour's clonal layer is not planted: it fixes in the founding duct before the lesion spreads. There is nothing to look up, and :attr:seeded_truncal_sites is empty unless founder_mutations was configured. This finds the trunk the way a study does — the somatic sites carried by at least ccf of cancer cells. Germline variants are excluded: they sit in every cell, tumour and normal alike, so they would otherwise pass the same test.

Parameters:

Name Type Description Default
ccf float

Minimum cancer-cell fraction for a site to count as truncal. 0.95 is the usual clonal cutoff. The count is sensitive to it — a convention, not a constant of the tumour — so report the cutoff with the number.

0.95
cell_ids sequence of str

Restrict to these cells (e.g. one sample's). Defaults to every materialised cell.

None

Returns:

Type Description
ndarray

Sorted locus indices, i.e. positions along the gene axis of cell_data["cell_snv"].

primary_window

primary_window(side, center=None)

Deme indices of a rectangular window of the PRIMARY grid, centred on center (row, col) or the grid centre. Pass to make_cell_data(region=...) to materialise a dense spatial patch (e.g. a Visium slide's footprint) of a cm-scale tumour at real cell density, rather than thinning the whole tumour to a uniform subsample.

Parameters:

Name Type Description Default
side int or tuple of int

Window size in demes: an int for a side×side square, or (rows, cols) for a rectangle. A real capture area is rarely square — the Visium v1 slide is 78×64 spots, i.e. wider than it is tall — so a rectangle is what fills one.

required
center tuple of int

(row, col) centre. Defaults to the grid centre. A window that would overhang the grid is SHIFTED back onto it, so the full requested size is always returned (clipped only if it is larger than the grid) — size a window to a capture area and you get that area, not a sliver of it.

None

make_cell_data

make_cell_data(cell_prefix='C', max_cells=None, region=None, depth_frac=None, **kwargs)

Expand the per-deme genotype counts into per-cell ground-truth tables.

Materialises one row per cell (each genotype's count becomes that many identical cells) into self.cell_data — a dict of dataframes keyed by cell name: evolutionary parameters, expression, SNV and CNV matrices, grid coordinates, cell-type and deme labels, plus any optional layers that are enabled (compartment, allele-resolved expression / RNA BAF, program activity). Called automatically at the end of grow.

Parameters:

Name Type Description Default
cell_prefix str

Prefix for the generated cell names (default "C").

'C'
max_cells int

Cap on the number of cells materialised (defaults to the tumour's self.max_cells). When the tumour is larger, a representative subsample is materialised instead of every cell (see _materialize_plan) so the dense frames stay memory-bounded at cm-scale. None materialises every cell (byte-identical to before this cap existed).

None
region iterable of int

Deme indices to restrict materialisation to, at FULL local density (subject to max_cells). Use this for a SPATIAL assay (e.g. a Visium slide) that samples a small window of a cm-scale tumour and needs that window at real cell density — a uniform whole-tumour subsample would thin it to ~1 cell/spot. None materialises the whole tumour.

None
depth_frac float

DEPTH cut (a "parallel-axis" cut): keep only this fraction of EACH deme's cells, leaving the 2-D structure intact but lowering every deme-column's occupancy. Because K stands for the deme's 3-D column, this is a thin histology/Visium SLICE of a tissue block — the whole 2-D field, one thin layer. None keeps the full column; 0.5 is a half-depth slice. Composes with region (an in-plane cut) and max_cells.

None

Returns:

Type Description
dict

self.cell_data — the per-cell dataframes.

plot_muller

plot_muller(ax=None, by_drivers=False, **kwargs)

Render a Muller plot of the clonal dynamics (clone frequencies over steps, nested by ancestry).

by_drivers=True colours by distinct DRIVER-mutation combinations (Noble's demon convention) instead of by genotype, collapsing passenger-only diversity; combine with min_freq for a size threshold. Additional keywords (ax, colormap, normalize) select the target axes and control the styling.

plot_tissue

plot_tissue(ax=None, color='state', cmap=None, figsize=(7, 7), min_freq=0.02)

Deme-resolution tissue map built directly from the per-deme genotype COUNTS.

Unlike plot_grid (which reads the possibly-subsampled cell_data and so goes holey at cm-scale when max_cells thins the tissue), this colours EVERY occupied deme from the full counts, so the spatial overview is always complete. Primary grid only.

Parameters:

Name Type Description Default
color (state, cancer_frac, clone, stage)

"state" (default): categorical — empty / stroma / duct(normal) / DCIS (cancer in a duct) / IDC (cancer in stroma). "cancer_frac": the per-deme cancer fraction as a heatmap. "clone": colour each cancer deme by its dominant clone's DRIVER-clone colour (the same driver-collapsed palette as plot_muller(by_drivers=True) and plot_phylogeny), on a pale-stroma background. "stage": colour each cancer deme by the STAGE-dominant trait of its dominant clone (none / proliferation / invasion / …) — the same scheme (and palette) as the landing-animation hero — on a pale-stroma background.

"state"
min_freq float

For color="clone", the size threshold (fraction of the cancer population) below which driver clones are merged into their nearest surviving ancestor before colouring — matched to the Muller's min_freq so the two share a palette. Default 0.02.

0.02

plot_phylogeny

plot_phylogeny(ax=None, min_freq=0.02, figsize=(7, 7), linewidth=1.4)

Radial CLADE phylogeny drawn inline with matplotlib (Cassiopeia-style).

Rather than subsampling cells, the whole cancer population is COLLAPSED to driver clones — the same functional collapse the by_drivers Muller uses, size-merged at min_freq — and the tree is the clade genealogy: each surviving clade is one node, placed radially (founder at the centre, depth = clade ancestry), coloured by its driver-clone colour (matching plot_muller(by_drivers) and plot_tissue("clone")) and sized by its cell count.

Renders straight to ax (no image file); returns the matplotlib Axes. Primary grid only.

he_image

he_image(px=6, darkness=0.8, sigma_frac=0.5)

Dense H&E-like morphology image built from the per-deme cell COUNTS.

The tissue image a histology/Visium slide sits on. Unlike rasterising the (possibly subsampled) cell_data — which is a THIN section and so renders faint and holey at cm-scale — this paints EVERY occupied deme from the full counts, so denser tissue (packed DCIS ducts, invasive masses) reads dark and looser stroma reads pale, giving a complete, high-contrast image. Cancer nuclei tint toward hematoxylin purple; stroma stays eosin pink.

The image is in the raw deme-grid frame (px pixels per deme). To overlay a placed Visium slide, shift the spot coordinates back into this frame by the placement translation (spot_coords.mean(0) - section_cell_crd.mean(0)); see notebook 03.

Parameters:

Name Type Description Default
px int

Pixels per deme.

6
darkness float

Maximum staining of the densest tissue.

0.8
sigma_frac float

Gaussian smoothing sigma as a fraction of px.

0.5

Returns:

Name Type Description
image (ndarray, shape(G * px, G * px, 3), float32)

RGB H&E morphology image in [0, 1].

px float

Pixels per deme (the scale factor mapping deme coords onto the image).

plot_grid

plot_grid(color=None, ax=None, **kwargs)

Plot the spatial deme grid, colouring each deme by a per-cell attribute.

Rebuilds the per-cell data if stale, then draws the grid coloured by color (default the dominant clone / cell type). When the metastatic compartment is enabled and no explicit ax is passed, both the primary and met grids are drawn side by side with a shared clone colormap.

Parameters:

Name Type Description Default
color str or list of str

Attribute key(s) to colour by; defaults to the dominant clone / cell type.

None
ax Axes

Axes to draw into; forces the single-panel primary view. A new figure is created when None.

None

Returns:

Type Description
Axes

The axes drawn into.

plot_grid_compartments

plot_grid_compartments(color=None, axes=None, by_drivers=False, by_stage=False, **kwargs)

Two spatial grids (primary + met) side by side, shared clone colormap. by_drivers colours by functional clone (matching the driver-collapsed 2-band Muller); by_stage colours by the stage-dominant driver; pass min_freq to also merge below-threshold clones.

plot_muller_compartments

plot_muller_compartments(axes=None, by_drivers=False, by_stage=False, star_seeder=True, **kwargs)

Two-band Muller (primary over met) sharing one colormap with the grids. by_drivers collapses genotypes to FUNCTIONAL clones and min_freq (a fraction) merges below-threshold clones, so selective sweeps (DCIS→IDC breach, the met founder, post-chemo resistant escape) show as bands instead of a passenger rainbow. by_stage instead colours by the STAGE-DOMINANT driver. star_seeder stars the first met-seeding clone's band in BOTH panels at the seeding moment (so a minor founder is findable).

plot_muller_founders

plot_muller_founders(ax=None, **kwargs)

A SINGLE primary Muller highlighting the clone(s) that seeded the metastasis, so you can see which — usually minor — primary population founds the met. Founders are read from the seeding events; a primary clone is highlighted iff it shares a functional signature with one.

plot_clone_tree

plot_clone_tree(ax=None, by_stage=False, by_drivers=False, **kwargs)

Ground-truth clone tree: the TRUE genotypes_parents genealogy collapsed to the display clones, each node at its true mutational depth, sized by peak population and coloured by by_stage (stage-dominant driver) or by_drivers (functional clone). Pass min_freq to set the collapse threshold (default 0.02).

get_genotype_frequencies

get_genotype_frequencies(normalize=True)

Cancer-genotype ids and their frequencies (normal cell types excluded).

Parameters:

Name Type Description Default
normalize bool

If True (default) the counts are divided by their sum to give proportions; otherwise raw cell counts are returned.

True

Returns:

Type Description
tuple of (list, numpy.ndarray)

The cancer-genotype ids and their matching counts / frequencies.

epistasis_ground_truth

epistasis_ground_truth()

The planted network — the answer key for MHN/TreeMHN/CBN/REVOLVER edge + order recovery.

Returns the true E matrix, the marginal effects beta, the interaction edges, the conjunctive dependency DAG, the mutually-exclusive pairs and the event->gene modules; or None when epistasis is off. Shared by every patient of a cohort (drawn from the layout stream), which is what makes pooling patients to recover ONE network well-posed.

event_table

event_table()

Per-clone event sets and the ORDER this lineage acquired them (empty when epistasis is off).

One row per cancer genotype: its cell count, the events it carries, and the realised order along its lineage — the per-patient ordering ground truth. event_groups is the truthful form (one tuple per mutating division; events inside a group are TIED, having been acquired together, so no order between them exists); event_order is that flattened for exports needing a linear path. Score ordering against event_groupsevent_order breaks ties arbitrarily.

diagnose

diagnose(thresholds=None, verbose=False)

Flag degenerate ("crappy") tumour regimes after growth, with actionable hints.

Computes phenotype metrics (size, clonal diversity, TMB, clone spatial confinement, fraction-genome-altered, hypoxia core–rim contrast, 1/f fit) and checks each against an overridable threshold: extinct / monoclonal / hypermutated / well-mixed / no-microenvironment-gradient / CNA-runaway / trivial-genome. Returns a TumorDiagnosis. Read-only — it never draws from self.rng or changes the counts, so it cannot alter simulation output (like the microenvironment ground truth).

write

write(output_path)

Write the canonical iscc layout (so isccsample/isccdata can consume it).

write_h5ad

write_h5ad(path, compression='gzip', **kwargs)

Write the whole tumour — cells, genes, clones and parameters — to one .h5ad file.

The standard single-cell container instead of a directory of CSVs: expression in X, the other per-cell matrices in layers, per-cell annotation in obs, tissue coordinates in obsm, gene roles in var, and the clone tree / programs / run parameters in uns. Reads back anywhere anndata is installed (anndata.read_h5ad). Extra keywords go to :func:iscc.integrations.to_anndata (e.g. spatial="rowcol").