Source code for ClearMap.Analysis.Statistics.group_assets

from pathlib import Path
from dataclasses import dataclass

import numpy as np
import pandas as pd

import ClearMap.IO.IO as clearmap_io
from ClearMap.Analysis.Statistics.group_statistics import LoadedPValueResults


[docs] @dataclass(frozen=True) class PairKey: channel: str gp1: str gp2: str suffix: str = '' def _sfx(self) -> str: return f'_{self.suffix}' if self.suffix else '' def _grp_sfx(self, group_name: str) -> str: sfx = f'_{self.suffix}' if self.suffix else '' return f'{self.channel}_{group_name}{sfx}'
[docs] class GroupResultsAssets: """ Single source of truth for paths of group-level result assets. Mirrors Workspace2 for single samples — the orchestrator asks this object for paths; it never builds paths itself. """ def __init__(self, results_folder: Path): self.root = Path(results_folder) # ── per-group ─────────────────────────────────────────────────────────
[docs] def avg_density_path(self, channel: str, group_name: str, suffix: str = '') -> Path: return self._group_path(channel, 'avg_density', group_name, suffix)
[docs] def sd_density_path(self, channel: str, group_name: str, suffix: str = '') -> Path: return self._group_path(channel, 'sd_density', group_name, suffix)
[docs] def stacked_density_path(self, channel: str, group_name: str, suffix: str = '') -> Path: return self._group_path(channel, 'stacked_density', group_name, suffix)
# ── per-pair ──────────────────────────────────────────────────────────
[docs] def p_val_colors_path(self, channel: str, gp1: str, gp2: str, suffix: str = '') -> Path: return self._pair_path(channel, 'p_val_colors', gp1, gp2, suffix, ext='.tif')
[docs] def effect_size_path(self, channel: str, gp1: str, gp2: str, suffix: str = '') -> Path: return self._pair_path(channel, 'effect_size', gp1, gp2, suffix, ext='.tif')
[docs] def stats_table_path(self, channel: str, gp1: str, gp2: str, suffix: str = '') -> Path: return self._pair_path(channel, 'statistics', gp1, gp2, suffix, ext='.csv')
# ── existence checks ─────────────────────────────────────────────────
[docs] def p_val_assets_exist(self, channel: str, gp1: str, gp2: str, suffix: str = '') -> bool: return self.p_val_colors_path(channel, gp1, gp2, suffix).exists()
# ── loaders ──────────────────────────────────────────────────────────
[docs] def load_p_val_results(self, channel: str, gp1: str, gp2: str, suffix: str = '') -> 'LoadedPValueResults': def _opt(p: Path): return clearmap_io.read(p) if p.exists() else None return LoadedPValueResults( gp1_avg=clearmap_io.read(self.avg_density_path(channel, gp1, suffix)), gp1_sd=_opt(self.sd_density_path(channel, gp1, suffix)), gp2_avg=clearmap_io.read(self.avg_density_path(channel, gp2, suffix)), gp2_sd=_opt(self.sd_density_path(channel, gp2, suffix)), p_vals=clearmap_io.read(self.p_val_colors_path(channel, gp1, gp2, suffix)), effect_size=_opt(self.effect_size_path(channel, gp1, gp2, suffix)), )
# ── writers ──────────────────────────────────────────────────────────
[docs] def write_avg_density(self, array: np.ndarray, channel: str, group_name: str, suffix: str = '') -> None: clearmap_io.write(self.avg_density_path(channel, group_name, suffix), array)
[docs] def write_sd_density(self, array: np.ndarray, channel: str, group_name: str, suffix: str = '') -> None: clearmap_io.write(self.sd_density_path(channel, group_name, suffix), array)
[docs] def write_p_val_colors(self, array: np.ndarray, channel: str, gp1: str, gp2: str, suffix: str = '') -> None: clearmap_io.write(self.p_val_colors_path(channel, gp1, gp2, suffix), array, photometric='rgb', imagej=True)
[docs] def write_effect_size(self, array: np.ndarray, channel: str, gp1: str, gp2: str, suffix: str = '') -> None: clearmap_io.write(self.effect_size_path(channel, gp1, gp2, suffix), array, imagej=True)
[docs] def write_stats_table(self, df: pd.DataFrame, channel: str, gp1: str, gp2: str, suffix: str = '') -> None: df.to_csv(self.stats_table_path(channel, gp1, gp2, suffix))
# ── internal ───────────────────────────────────────────────────────── def _group_path(self, channel: str, kind: str, group_name: str, suffix: str, ext: str = '.tif') -> Path: sfx = f'_{suffix}' if suffix else '' return self.root / f'{channel}_{kind}_{group_name}{sfx}{ext}' def _pair_path(self, channel: str, kind: str, gp1: str, gp2: str, suffix: str, ext: str = '.tif') -> Path: sfx = f'_{suffix}' if suffix else '' return self.root / f'{channel}_{kind}_{gp1}_{gp2}{sfx}{ext}'