Coverage for src/cell_abm_pipeline/flows/plot_basic_metrics.py: 0%
197 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 basic metrics.
4Working location structure:
6.. code-block:: bash
8 (name)
9 ├── groups
10 │ └── groups.BASIC_METRICS
11 │ ├── (name).metrics_bins.(key).(seed).(tick).(metric).csv
12 │ ├── (name).metrics_distributions.(metric).json
13 │ ├── (name).metrics_individuals.(key).(seed).(metric).json
14 │ ├── (name).metrics_spatial.(key).(seed).(tick).(metric).csv
15 │ ├── (name).metrics_temporal.(key).(metric).json
16 │ └── (name).population_counts.(tick).csv
17 └── plots
18 └── plots.BASIC_METRICS
19 ├── (name).metrics_bins.(key).(seed).(tick).(metric).png
20 ├── (name).metrics_distributions.(metric).png
21 ├── (name).metrics_individuals.(key).(seed).(metric).png
22 ├── (name).metrics_spatial.(key).(seed).(tick).(metric).png
23 ├── (name).metrics_temporal.(key).(metric).png
24 └── (name).population_counts.(tick).png
26Plots use grouped data from **groups.BASIC_METRICS**. Plots are saved to
27**plots.BASIC_METRICS**.
28"""
30from dataclasses import dataclass, field
31from typing import Optional
33from io_collection.keys import make_key
34from io_collection.load import load_dataframe, load_json
35from io_collection.save import save_figure
36from prefect import flow
38from cell_abm_pipeline.flows.group_basic_metrics import (
39 BIN_METRICS,
40 CELL_PHASES,
41 DISTRIBUTION_METRICS,
42 INDIVIDUAL_METRICS,
43 SPATIAL_METRICS,
44 TEMPORAL_METRICS,
45)
46from cell_abm_pipeline.tasks import (
47 make_bar_figure,
48 make_density_figure,
49 make_histogram_figure,
50 make_line_figure,
51 make_range_figure,
52 make_scatter_figure,
53)
55PLOTS: list[str] = [
56 "metrics_bins",
57 "metrics_distributions",
58 "metrics_individuals",
59 "metrics_spatial",
60 "metrics_temporal",
61 "population_counts",
62]
64PHASE_COLORS: dict[str, str] = {
65 "PROLIFERATIVE_G1": "#7F3C8D",
66 "PROLIFERATIVE_S": "#11A579",
67 "PROLIFERATIVE_G2": "#3969AC",
68 "PROLIFERATIVE_M": "#F2B701",
69 "APOPTOTIC_EARLY": "#E73F74",
70 "APOPTOTIC_LATE": "#80BA5A",
71}
73POPULATION_COLORS: dict[int, str] = {
74 1: "#7F3C8D",
75}
78@dataclass
79class ParametersConfigMetricsBins:
80 """Parameter configuration for plot basic metrics subflow - metrics bins."""
82 metrics: list[str] = field(default_factory=lambda: BIN_METRICS)
83 """List of bin metrics."""
85 seed: int = 0
86 """Simulation seed to use for plotting bin metrics."""
88 ticks: list[int] = field(default_factory=lambda: [0])
89 """Simulation ticks to use for plotting bin metrics."""
91 scale: float = 1
92 """Metric bin scaling."""
95@dataclass
96class ParametersConfigMetricsDistributions:
97 """Parameter configuration for plot basic metrics subflow - metrics distributions."""
99 metrics: list[str] = field(default_factory=lambda: DISTRIBUTION_METRICS)
100 """List of distribution metrics."""
102 phases: list[str] = field(default_factory=lambda: CELL_PHASES)
103 """List of cell cycle phases."""
105 regions: list[str] = field(default_factory=lambda: ["DEFAULT"])
106 """List of subcellular regions."""
109@dataclass
110class ParametersConfigMetricsIndividuals:
111 """Parameter configuration for plot basic metrics subflow - metrics individuals."""
113 metrics: list[str] = field(default_factory=lambda: INDIVIDUAL_METRICS)
114 """List of individual metrics."""
116 seed: int = 0
117 """Simulation seed to use for plotting individual metrics."""
119 regions: list[str] = field(default_factory=lambda: ["DEFAULT"])
120 """List of subcellular regions."""
122 phase_colors: dict[str, str] = field(default_factory=lambda: PHASE_COLORS)
123 """Colors for each cell cycle phase."""
126@dataclass
127class ParametersConfigMetricsSpatial:
128 """Parameter configuration for plot basic metrics subflow - metrics spatial."""
130 metrics: list[str] = field(default_factory=lambda: SPATIAL_METRICS)
131 """List of spatial metrics."""
133 seeds: list[int] = field(default_factory=lambda: [0])
134 """Simulation seeds to use for plotting spatial metrics."""
136 regions: list[str] = field(default_factory=lambda: ["DEFAULT"])
137 """List of subcellular regions."""
139 ticks: list[int] = field(default_factory=lambda: [0])
140 """Simulation ticks to use for plotting spatial metrics."""
142 phase_colors: dict[str, str] = field(default_factory=lambda: PHASE_COLORS)
143 """Colors for each cell cycle phase."""
145 population_colors: dict[int, str] = field(default_factory=lambda: POPULATION_COLORS)
146 """Colors for each cell population."""
149@dataclass
150class ParametersConfigMetricsTemporal:
151 """Parameter configuration for plot basic metrics subflow - metrics temporal."""
153 metrics: list[str] = field(default_factory=lambda: TEMPORAL_METRICS)
154 """List of temporal metrics."""
156 regions: list[str] = field(default_factory=lambda: ["DEFAULT"])
157 """List of subcellular regions."""
159 populations: list[int] = field(default_factory=lambda: [1])
160 """List of cell populations."""
162 phases: list[str] = field(default_factory=lambda: CELL_PHASES)
163 """List of cell cycle phases."""
166@dataclass
167class ParametersConfigPopulationCounts:
168 """Parameter configuration for plot basic metrics subflow - population counts."""
170 tick: int = 0
171 """Simulation tick to use for plotting population counts."""
174@dataclass
175class ParametersConfig:
176 """Parameter configuration for plot basic metrics flow."""
178 plots: list[str] = field(default_factory=lambda: PLOTS)
179 """List of basic metric plots."""
181 metrics_bins: ParametersConfigMetricsBins = ParametersConfigMetricsBins()
182 """Parameters for plot metrics bins subflow."""
184 metrics_distributions: ParametersConfigMetricsDistributions = (
185 ParametersConfigMetricsDistributions()
186 )
187 """Parameters for plot metrics distributions subflow."""
189 metrics_individuals: ParametersConfigMetricsIndividuals = ParametersConfigMetricsIndividuals()
190 """Parameters for plot metrics individuals subflow."""
192 metrics_spatial: ParametersConfigMetricsSpatial = ParametersConfigMetricsSpatial()
193 """Parameters for plot metrics spatial subflow."""
195 metrics_temporal: ParametersConfigMetricsTemporal = ParametersConfigMetricsTemporal()
196 """Parameters for plot metrics temporal subflow."""
198 population_counts: ParametersConfigPopulationCounts = ParametersConfigPopulationCounts()
199 """Parameters for plot population counts subflow."""
202@dataclass
203class ContextConfig:
204 """Context configuration for plot basic metrics flow."""
206 working_location: str
207 """Location for input and output files (local path or S3 bucket)."""
210@dataclass
211class SeriesConfig:
212 """Series configuration for plot basic metrics flow."""
214 name: str
215 """Name of the simulation series."""
217 conditions: list[dict]
218 """List of series condition dictionaries (must include unique condition "key")."""
221@flow(name="plot-basic-metrics")
222def run_flow(context: ContextConfig, series: SeriesConfig, parameters: ParametersConfig) -> None:
223 """
224 Main plot basic metrics flow.
226 Calls the following subflows, if the plot is specified:
228 - :py:func:`run_flow_plot_metrics_bins`
229 - :py:func:`run_flow_plot_metrics_distributions`
230 - :py:func:`run_flow_plot_metrics_individuals`
231 - :py:func:`run_flow_plot_metrics_spatial`
232 - :py:func:`run_flow_plot_metrics_temporal`
233 - :py:func:`run_flow_plot_population_stats`
234 """
236 if "metrics_bins" in parameters.plots:
237 run_flow_plot_metrics_bins(context, series, parameters.metrics_bins)
239 if "metrics_distributions" in parameters.plots:
240 run_flow_plot_metrics_distributions(context, series, parameters.metrics_distributions)
242 if "metrics_individuals" in parameters.plots:
243 run_flow_plot_metrics_individuals(context, series, parameters.metrics_individuals)
245 if "metrics_spatial" in parameters.plots:
246 run_flow_plot_metrics_spatial(context, series, parameters.metrics_spatial)
248 if "metrics_temporal" in parameters.plots:
249 run_flow_plot_metrics_temporal(context, series, parameters.metrics_temporal)
251 if "population_counts" in parameters.plots:
252 run_flow_plot_population_counts(context, series, parameters.population_counts)
255@flow(name="plot-basic-metrics_plot-metrics-bins")
256def run_flow_plot_metrics_bins(
257 context: ContextConfig, series: SeriesConfig, parameters: ParametersConfigMetricsBins
258) -> None:
259 """Plot basic metrics subflow for binned metrics."""
261 group_key = make_key(series.name, "groups", "groups.BASIC_METRICS")
262 plot_key = make_key(series.name, "plots", "plots.BASIC_METRICS")
263 keys = [condition["key"] for condition in series.conditions]
265 for key in keys:
266 for tick in parameters.ticks:
267 for metric in parameters.metrics:
268 metric_key = f"{key}.{parameters.seed:04d}.{tick:06d}.{metric.upper()}"
270 group = load_dataframe(
271 context.working_location,
272 make_key(group_key, f"{series.name}.metrics_bins.{metric_key}.csv"),
273 )
275 save_figure(
276 context.working_location,
277 make_key(plot_key, f"{series.name}.metrics_bins.{metric_key}.png"),
278 make_density_figure(group, parameters.scale),
279 )
282@flow(name="plot-basic-metrics_plot-metrics-distributions")
283def run_flow_plot_metrics_distributions(
284 context: ContextConfig, series: SeriesConfig, parameters: ParametersConfigMetricsDistributions
285) -> None:
286 """Plot basic metrics subflow for metrics distributions."""
288 group_key = make_key(series.name, "groups", "groups.BASIC_METRICS")
289 plot_key = make_key(series.name, "plots", "plots.BASIC_METRICS")
290 keys = [condition["key"] for condition in series.conditions]
292 metrics: list[str] = []
293 for metric in parameters.metrics:
294 if metric in ["volume", "height"]:
295 metrics = metrics + [f"{metric}.{region}" for region in parameters.regions]
296 elif metric == "phase":
297 metrics = metrics + [f"{metric}.{phase}" for phase in parameters.phases]
298 else:
299 continue
301 for metric in metrics:
302 metric_key = metric.upper()
304 group = load_json(
305 context.working_location,
306 make_key(group_key, f"{series.name}.metrics_distributions.{metric_key}.json"),
307 )
309 assert isinstance(group, dict)
311 save_figure(
312 context.working_location,
313 make_key(plot_key, f"{series.name}.metrics_distributions.{metric_key}.png"),
314 make_histogram_figure(keys, group),
315 )
318@flow(name="plot-basic-metrics_plot-metrics-individuals")
319def run_flow_plot_metrics_individuals(
320 context: ContextConfig, series: SeriesConfig, parameters: ParametersConfigMetricsIndividuals
321) -> None:
322 """Plot basic metrics subflow for individual metrics."""
324 group_key = make_key(series.name, "groups", "groups.BASIC_METRICS")
325 plot_key = make_key(series.name, "plots", "plots.BASIC_METRICS")
326 keys = [condition["key"] for condition in series.conditions]
328 metrics: list[str] = [
329 f"{metric}.{region}" for metric in parameters.metrics for region in parameters.regions
330 ]
332 for key in keys:
333 for metric in metrics:
334 metric_key = f"{key}.{parameters.seed:04d}.{metric.upper()}"
336 group = load_json(
337 context.working_location,
338 make_key(group_key, f"{series.name}.metrics_individuals.{metric_key}.json"),
339 )
341 group_flat = [
342 {
343 "x": line["time"],
344 "y": line["value"],
345 "color": parameters.phase_colors[line["phase"]],
346 }
347 for item in group
348 for line in item
349 ]
351 save_figure(
352 context.working_location,
353 make_key(plot_key, f"{series.name}.metrics_individuals.{metric_key}.png"),
354 make_line_figure(group_flat),
355 )
358@flow(name="plot-basic-metrics_plot-metrics-spatial")
359def run_flow_plot_metrics_spatial(
360 context: ContextConfig, series: SeriesConfig, parameters: ParametersConfigMetricsSpatial
361) -> None:
362 """Plot basic metrics subflow for spatial metrics."""
364 group_key = make_key(series.name, "groups", "groups.BASIC_METRICS")
365 plot_key = make_key(series.name, "plots", "plots.BASIC_METRICS")
366 keys = [condition["key"] for condition in series.conditions]
368 metrics: list[str] = []
369 for metric in parameters.metrics:
370 if metric in ["volume", "height"]:
371 metrics = metrics + [f"{metric}.{region}" for region in parameters.regions]
372 else:
373 metrics.append(metric)
375 for key in keys:
376 for seed in parameters.seeds:
377 for tick in parameters.ticks:
378 for metric in metrics:
379 metric_key = f"{key}.{seed:04d}.{tick:06d}.{metric.upper()}"
381 colormap: Optional[dict] = None
383 if metric == "phase":
384 colormap = parameters.phase_colors
385 elif metric == "population":
386 colormap = parameters.population_colors
388 group = load_dataframe(
389 context.working_location,
390 make_key(group_key, f"{series.name}.metrics_spatial.{metric_key}.csv"),
391 )
393 save_figure(
394 context.working_location,
395 make_key(plot_key, f"{series.name}.metrics_spatial.{metric_key}.png"),
396 make_scatter_figure(group, colormap),
397 )
400@flow(name="plot-basic-metrics_plot-metrics-temporal")
401def run_flow_plot_metrics_temporal(
402 context: ContextConfig, series: SeriesConfig, parameters: ParametersConfigMetricsTemporal
403) -> None:
404 """Plot basic metrics subflow for temporal metrics."""
406 group_key = make_key(series.name, "groups", "groups.BASIC_METRICS")
407 plot_key = make_key(series.name, "plots", "plots.BASIC_METRICS")
408 keys = [condition["key"] for condition in series.conditions]
410 metrics: list[str] = []
411 for metric in parameters.metrics:
412 if metric in ["volume", "height"]:
413 metrics = metrics + [f"{metric}.{region}" for region in parameters.regions]
414 elif metric == "population":
415 metrics = metrics + [f"{metric}.{population}" for population in parameters.populations]
416 elif metric == "phase":
417 metrics = metrics + [f"{metric}.{phase}" for phase in parameters.phases]
418 else:
419 metrics.append(metric)
421 for key in keys:
422 for metric in metrics:
423 metric_key = f"{key}.{metric.upper()}"
425 group = load_json(
426 context.working_location,
427 make_key(group_key, f"{series.name}.metrics_temporal.{metric_key}.json"),
428 )
430 assert isinstance(group, dict)
432 save_figure(
433 context.working_location,
434 make_key(plot_key, f"{series.name}.metrics_temporal.{metric_key}.png"),
435 make_range_figure(group),
436 )
439@flow(name="plot-basic-metrics_plot-population-counts")
440def run_flow_plot_population_counts(
441 context: ContextConfig, series: SeriesConfig, parameters: ParametersConfigPopulationCounts
442) -> None:
443 """Plot basic metrics subflow for population counts."""
445 group_key = make_key(series.name, "groups", "groups.BASIC_METRICS")
446 plot_key = make_key(series.name, "plots", "plots.BASIC_METRICS")
447 keys = [condition["key"] for condition in series.conditions]
449 group = load_dataframe(
450 context.working_location,
451 make_key(group_key, f"{series.name}.population_counts.{parameters.tick:06d}.csv"),
452 )
454 key_group = {
455 key: {
456 "COUNT": {
457 "mean": group[group["key"] == key]["count"].mean(),
458 "std": group[group["key"] == key]["count"].std(ddof=1),
459 }
460 }
461 for key in keys
462 }
464 save_figure(
465 context.working_location,
466 make_key(plot_key, f"{series.name}.population_counts.{parameters.tick:06d}.png"),
467 make_bar_figure(keys, key_group),
468 )