Coverage for src/cell_abm_pipeline/flows/plot_colony_dynamics.py: 0%
89 statements
« prev ^ index » next coverage.py v7.1.0, created at 2024-06-05 19:14 +0000
« prev ^ index » next coverage.py v7.1.0, created at 2024-06-05 19:14 +0000
1"""
2Workflow for plotting colony dynamics.
4Working location structure:
6.. code-block:: bash
8 (name)
9 ├── groups
10 │ └── groups.COLONIES
11 │ ├── (name).feature_distributions.(feature).json
12 │ ├── (name).feature_temporal.(key).(feature).json
13 │ ├── (name).neighbor_positions.(key).(seed).(tick).csv
14 │ └── (name).neighbor_positions.(key).(seed).(tick).(feature).csv
15 └── plots
16 └── plots.COLONIES
17 ├── (name).feature_distributions.(feature).png
18 ├── (name).feature_temporal.(key).(feature).json
19 └── (name).neighbor_positions.(key).(seed).(tick).(feature).png
21Plots use grouped data from **groups.COLONIES**. Plots are saved to
22**plots.COLONIES**.
23"""
25from dataclasses import dataclass, field
27from io_collection.keys import make_key
28from io_collection.load import load_dataframe, load_json
29from io_collection.save import save_figure
30from prefect import flow
32from cell_abm_pipeline.flows.group_colony_dynamics import (
33 DISTRIBUTION_FEATURES,
34 POSITION_FEATURES,
35 TEMPORAL_FEATURES,
36)
37from cell_abm_pipeline.tasks import make_graph_figure, make_histogram_figure, make_range_figure
39PLOTS: list[str] = [
40 "feature_distributions",
41 "feature_temporal",
42 "neighbor_positions",
43]
46FEATURE_COLORMAPS = {"depth": "magma_r", "group": "tab10"}
49@dataclass
50class ParametersConfigFeatureDistributions:
51 """Parameter configuration for plot colony dynamics subflow - feature distributions."""
53 features: list[str] = field(default_factory=lambda: DISTRIBUTION_FEATURES)
54 """List of colony features."""
57@dataclass
58class ParametersConfigFeatureTemporal:
59 """Parameter configuration for plot colony dynamics subflow - feature temporal."""
61 features: list[str] = field(default_factory=lambda: TEMPORAL_FEATURES)
62 """List of temporal features."""
65@dataclass
66class ParametersConfigNeighborPositions:
67 """Parameter configuration for plot colony dynamics subflow - neighbor positions."""
69 features: list[str] = field(default_factory=lambda: POSITION_FEATURES)
70 """List of position features."""
72 seed: int = 0
73 """Simulation seed to use for plotting neighbor positions."""
75 ticks: list[int] = field(default_factory=lambda: [0])
76 """Simulation ticks to use for plotting neighbor positions."""
78 colormaps: dict[str, str] = field(default_factory=lambda: FEATURE_COLORMAPS)
79 """Colormaps for each feature."""
82@dataclass
83class ParametersConfig:
84 """Parameter configuration for plot colony dynamics flow."""
86 plots: list[str] = field(default_factory=lambda: PLOTS)
87 """List of colony dynamics plots."""
89 feature_distributions: ParametersConfigFeatureDistributions = (
90 ParametersConfigFeatureDistributions()
91 )
92 """Parameters for plot feature distributions subflow."""
94 feature_temporal: ParametersConfigFeatureTemporal = ParametersConfigFeatureTemporal()
95 """Parameters for plot feature temporal subflow."""
97 neighbor_positions: ParametersConfigNeighborPositions = ParametersConfigNeighborPositions()
98 """Parameters for plot neighbor positions subflow."""
101@dataclass
102class ContextConfig:
103 """Context configuration for plot colony dynamics flow."""
105 working_location: str
106 """Location for input and output files (local path or S3 bucket)."""
109@dataclass
110class SeriesConfig:
111 """Series configuration for plot colony dynamics flow."""
113 name: str
114 """Name of the simulation series."""
116 conditions: list[dict]
117 """List of series condition dictionaries (must include unique condition "key")."""
120@flow(name="plot-colony-dynamics")
121def run_flow(context: ContextConfig, series: SeriesConfig, parameters: ParametersConfig) -> None:
122 """
123 Main plot colony dynamics flow.
125 Calls the following subflows, if the plot is specified:
127 - :py:func:`run_flow_plot_feature_distributions`
128 - :py:func:`run_flow_plot_feature_temporal`
129 - :py:func:`run_flow_plot_neighbor_positions`
130 """
132 if "feature_distributions" in parameters.plots:
133 run_flow_plot_feature_distributions(context, series, parameters.feature_distributions)
135 if "feature_temporal" in parameters.plots:
136 run_flow_plot_feature_temporal(context, series, parameters.feature_temporal)
138 if "neighbor_positions" in parameters.plots:
139 run_flow_plot_neighbor_positions(context, series, parameters.neighbor_positions)
142@flow(name="plot-colony-dynamics_plot-feature-distributions")
143def run_flow_plot_feature_distributions(
144 context: ContextConfig, series: SeriesConfig, parameters: ParametersConfigFeatureDistributions
145) -> None:
146 """Plot colony dynamics subflow for feature distributions."""
148 group_key = make_key(series.name, "groups", "groups.COLONIES")
149 plot_key = make_key(series.name, "plots", "plots.COLONIES")
150 keys = [condition["key"] for condition in series.conditions]
152 for feature in parameters.features:
153 feature_key = feature.upper()
155 group = load_json(
156 context.working_location,
157 make_key(group_key, f"{series.name}.feature_distributions.{feature_key}.json"),
158 )
160 assert isinstance(group, dict)
162 save_figure(
163 context.working_location,
164 make_key(plot_key, f"{series.name}.feature_distributions.{feature_key}.png"),
165 make_histogram_figure(keys, group),
166 )
169@flow(name="plot-colony-dynamics_plot-feature-temporal")
170def run_flow_plot_feature_temporal(
171 context: ContextConfig, series: SeriesConfig, parameters: ParametersConfigFeatureTemporal
172) -> None:
173 """Plot colony dynamics subflow for temporal features."""
175 group_key = make_key(series.name, "groups", "groups.COLONIES")
176 plot_key = make_key(series.name, "plots", "plots.COLONIES")
177 keys = [condition["key"] for condition in series.conditions]
179 for key in keys:
180 for feature in parameters.features:
181 feature_key = f"{key}.{feature.upper()}"
183 group = load_json(
184 context.working_location,
185 make_key(group_key, f"{series.name}.feature_temporal.{feature_key}.json"),
186 )
188 assert isinstance(group, dict)
190 save_figure(
191 context.working_location,
192 make_key(plot_key, f"{series.name}.feature_temporal.{feature_key}.png"),
193 make_range_figure(group),
194 )
197@flow(name="plot-colony-dynamics_plot-neighbor-positions")
198def run_flow_plot_neighbor_positions(
199 context: ContextConfig, series: SeriesConfig, parameters: ParametersConfigNeighborPositions
200) -> None:
201 """Plot colony dynamics subflow for neighbor positions."""
203 group_key = make_key(series.name, "groups", "groups.COLONIES")
204 plot_key = make_key(series.name, "plots", "plots.COLONIES")
205 keys = [condition["key"] for condition in series.conditions]
207 for key in keys:
208 for tick in parameters.ticks:
209 for feature in parameters.features:
210 edge_key = f"{key}.{parameters.seed:04d}.{tick:06d}"
211 node_key = f"{key}.{parameters.seed:04d}.{tick:06d}.{feature.upper()}"
213 edge_group = load_dataframe(
214 context.working_location,
215 make_key(group_key, f"{series.name}.neighbor_positions.{edge_key}.csv"),
216 )
218 node_group = load_dataframe(
219 context.working_location,
220 make_key(group_key, f"{series.name}.neighbor_positions.{node_key}.csv"),
221 )
223 save_figure(
224 context.working_location,
225 make_key(plot_key, f"{series.name}.neighbor_positions.{node_key}.png"),
226 make_graph_figure(node_group, edge_group, parameters.colormaps[feature]),
227 )