Finishing up¶
When the last step is done, BIWT assembles a BiwtResult and hands
it to the host. Nothing is written to disk by BIWT itself.
What is in the result¶
coordinates¶
A DataFrame with one row per placed cell:
| x | y | z | type |
|---|---|---|---|
| -320.0 | 140.0 | 0.0 | tumor |
| 40.0 | -260.0 | 0.0 | macrophage |
The column names follow the PhysiCell convention — note type, not cell_type. For 2D
data, z is padded with zeros.
cell_type_map¶
How every original label in your data maps to its final name:
{
"CD8_effector": "CD8_T_cell", # merged and renamed
"CD8_memory": "CD8_T_cell", # merged into the same target
"doublet": None, # deleted
"Tumor": "tumor", # renamed only
}
None means the type was deleted and contributes no cells. This is your
audit trail: it records every decision you made at the edit and rename steps.
domain_used¶
The DomainSpec actually applied when placing cells — which may
differ from what the host passed in, if you changed it in
the domain editor. Its source field says where it came from — host, data,
user or default — so the host can tell whether its own domain was overridden.
cell_templates¶
The cell templates you assigned, as a mapping from final cell-type
name to (path, name, content) — the .toml file the template came from, its name in that
file, and its content verbatim.
BIWT never parses that content, so a PhysiCell host receives exactly the <phenotype> block
its own template file holds, and owns every decision about assembling a config from it — see
templates and name matching if you are writing a
host.
Where you picked one of the host's own cell types, path is
HOST_SOURCE and the content is empty — the host already holds that
definition.
Types you left unassigned are absent from the mapping, so {} is a normal result — that is
what Skip produces. Hosts have two more rules to follow here; see
the API contract.
What the host does with it¶
That is up to the host. BIWT's contract ends at the callback.
PhysiCell Studio, for example, offers Overwrite / Append / Browse / Cancel when the target
cells.csv already exists, and separately assembles a PhysiCell config from the templates. A
notebook host might just call result.to_csv(...) or work with the DataFrame directly.
If you are writing a host, see embedding BIWT.
Writing it yourself¶
From a script, the convenience method does the obvious thing:
def on_complete(result):
result.to_csv("config/cells.csv")
That writes only the four columns, without the DataFrame index. The templates are yours to
assemble — for a PhysiCell host, one <cell_definition> per type wrapping the content BIWT
handed back:
import xml.etree.ElementTree as ET
from biwt.types import HOST_SOURCE
def on_complete(result):
result.to_csv("config/cells.csv")
cell_defs = ET.Element("cell_definitions")
for i, (cell_type, (path, name, content)) in enumerate(result.cell_templates.items()):
if path == HOST_SOURCE:
continue # you already define this type; no content to parse
cd = ET.SubElement(cell_defs, "cell_definition", name=cell_type, ID=str(i))
cd.append(ET.fromstring(content))
Starting over¶
The widget does not close itself when the workflow finishes — that is the host's call. Importing a new file resets the session completely, so the same widget can be reused for another dataset without restarting anything.