Skip to content
Eric Cramer edited this page May 29, 2026 · 2 revisions

Frequently Asked Questions

Short answers with links to the canonical docs for depth.

Q: When should I use network_mode="contact" vs network_mode="radius"?

Contact mode draws an edge between two cells when their surfaces touch (distance < r1 + r2). It's the right model for "are these cells physically adjacent in the tissue?"

Radius mode draws an edge whenever two cell centers are within a user-supplied network_radius of each other. It's the right model for "is this cell within a signalling range of that one?" and is also more robust on randomly packed tissues — because packing uses min_spacing > 0, surface contacts are rare and contact mode can yield empty interaction sets.

Most replicate-generation and target-statistics tests use network_mode="radius" for this reason. See the Spatial Analysis API guide for the math.

Q: Why does the packing fraction stop short of 1.0?

The sphere-packing algorithm uses Random Sequential Addition (RSA), which is an off-line, non-equilibrium method. The theoretical RSA limit for monodisperse spheres in 3D is about 38%; polydisperse mixtures reach 40–50%. Higher-than-RSA packings exist (hexagonal close packing ≈ 74%) but require iterative relaxation, which the algorithm here doesn't do — we trade density for speed and tunability of cell-size distributions. See the Core API for details.

Q: How do I make a workflow bit-reproducible from a seed?

As of v0.1.9 every stochastic component accepts a seed. Pass the same integer for the same outcome:

TissueSection(..., seed=42)               # tissue + packing
SpherePacker(..., seed=42)                # packer alone
ReplicateGenerator(..., seed=42)          # batches of replicates
GraphColorizer(..., seed=42)              # SA cell-type assignment
workflow.assign_cell_types(seed=42)       # workflow wrapper
quick_workflow(..., seed=42)              # end-to-end

Same seed= plus same inputs → byte-identical output. seed=None (default) preserves the legacy unseeded behavior. The MCP assign_cell_types tool also accepts a seed argument. See the Graph Coloring guide for the implementation note.

Q: Why do my visualizations have different colors each run?

Prior to v0.1.12 they could: the visualize_* functions built their color maps by iterating an unsorted set of cell types, so two Python processes could assign different colors to the same type. v0.1.12 sorts cell types alphabetically before color assignment, so cancer / immune / stroma always get the same colors across runs and across visualize_* functions. See CHANGELOG 0.1.12.

Q: What's the difference between GraphColorizer and ReplicateGenerator?

They solve different problems and produce different things:

  • GraphColorizer assigns labels to nodes of a fixed graph via simulated annealing to match a target adjacency structure (node_counts, edge_counts, neighbor_dist). Positions never change.
  • ReplicateGenerator repacks new positions for each replicate to match a target's contact statistics and proportions through random placement plus radius adjustment. There's no annealing; cell-type labels are assigned with rng.choice weighted by target proportions.

For structured multi-type targets (e.g. a tumor disc / fibroblast ring / CD8 annulus), the canonical path is the two-stage workflow: TissueSection.generate_cells for positions → TissueWorkflow.assign_cell_types for labels. The standalone ReplicateGenerator will not converge on strongly structured targets — see the "When to use what" section in the Graph Coloring guide.

Q: How do I load an externally measured (or PhysiCell-generated) tissue?

Three entry points landed in v0.1.7/v0.1.8:

  • TissueSection.from_cells(cells, …) — wrap pre-positioned Cell objects.
  • load_tissue_from_csv("cells.csv") — load from a coordinate CSV (x, y, z, radius, cell_type, is_boundary).
  • load_target_statistics_from_coordinates("cells.csv", network_mode="radius", network_radius=20.0) — go straight from coordinates to a full TargetStatistics (interactions + proportions + density) ready for ReplicateGenerator.

Same flows are reachable from the MCP server via the load_tissue_from_csv and load_target_statistics_from_coordinates tools. PhysiCell exports use this same coordinate schema — see the PhysiCell bridge guide.

Q: Does MCP work with Claude Desktop?

Yes. The MCP server lives under tissue_simulator.mcp and exposes 20 tools (as of v0.1.9). Add an entry to your Claude Desktop config (claude_desktop_config.json) pointing at tissue_simulator.mcp.server and Claude can drive tissue generation, slicing, network analysis, replicate generation, and cell-type assignment via tool calls. See the MCP guide for the 5-minute setup.

Q: How do I generate replicates that match a measured sample?

The flow:

  1. Load your sample with load_tissue_from_csv("measured.csv") (or load_target_statistics_from_coordinates(...) if you want to skip the intermediate TissueSection).
  2. Build a TargetStatistics from it via load_target_statistics_from_tissue(tissue, network_mode="radius", network_radius=20.0).
  3. Instantiate ReplicateGenerator(target_stats=…, tissue_dimensions=…, base_cell_radii=…, seed=2026).
  4. Call generate_replicates(num_replicates=10).

For structured sources, use the two-stage path with TissueWorkflow instead — see the previous FAQ entry.

Q: Where do I report bugs or request features?

GitHub issues: https://github.com/emcramer/tissue_simulator/issues. Include the version you're on (import tissue_simulator; print(tissue_simulator.__version__)) and a short reproducer when possible.