Source code for polyzymd.analyses.shared.multi_run_formatting
"""Shared formatting helpers for multi-run analysis outputs."""
from __future__ import annotations
from collections.abc import Callable
SINGLE_REPLICATE_SEM_NOTE = "SEM: n/a (single replicate; not estimable)"
[docs]
def is_sem_estimable(n_replicates: int) -> bool:
"""Return whether SEM can be estimated from replicate-level values.
Parameters
----------
n_replicates : int
Number of replicate values contributing to the summary.
Returns
-------
bool
``True`` when at least two replicates are available.
"""
return n_replicates >= 2
[docs]
def format_sem_value(
sem: float | None,
n_replicates: int,
*,
precision: int = 2,
unit: str = "",
) -> str:
"""Format SEM without implying singleton uncertainty is estimable.
Parameters
----------
sem : float | None
SEM value to display when enough replicates are available.
n_replicates : int
Number of replicates contributing to the summary.
precision : int, optional
Decimal places for numeric SEM values, by default 2.
unit : str, optional
Unit suffix appended to numeric SEM values, by default ``""``.
Returns
-------
str
``"n/a"`` for singleton summaries, otherwise a formatted SEM value.
"""
if not is_sem_estimable(n_replicates) or sem is None:
return "n/a"
return f"{sem:.{precision}f}{unit}"
[docs]
def format_sem_phrase(
sem: float | None,
n_replicates: int,
*,
precision: int = 2,
unit: str = "",
) -> str:
"""Format a compact ``SEM: ...`` phrase for summaries.
Parameters
----------
sem : float | None
SEM value to display when enough replicates are available.
n_replicates : int
Number of replicates contributing to the summary.
precision : int, optional
Decimal places for numeric SEM values, by default 2.
unit : str, optional
Unit suffix appended to numeric SEM values, by default ``""``.
Returns
-------
str
``"SEM: n/a (single replicate)"`` for singleton summaries, otherwise
a numeric SEM phrase.
"""
if not is_sem_estimable(n_replicates):
return "SEM: n/a (single replicate)"
return f"SEM: {format_sem_value(sem, n_replicates, precision=precision, unit=unit)}"
[docs]
def make_section_title(title: str, width: int) -> list[str]:
"""Build a section title and separator lines."""
return ["", title, "=" * width]
[docs]
def make_ranked_table_header(*, mean_label: str) -> list[str]:
"""Build standard ranked-table headers for text output."""
header = f"{'Condition':<18} {mean_label:<15} {'SEM':<8} {'Rank':<4}"
return [header, "-" * len(header)]
[docs]
def make_ranked_markdown_header(*, mean_label: str) -> list[str]:
"""Build standard ranked-table headers for markdown output."""
return [
f"| Condition | {mean_label} | SEM | Rank |",
"|-----------|---------------|-----|------|",
]
[docs]
def format_pairwise_line(
*,
condition_a: str,
condition_b: str,
direction: str,
p_value: float,
effect_size: float,
effect_label: str,
percent_change: float,
significant: bool,
prefix: str = "Pairwise",
) -> str:
"""Format one standard pairwise comparison line."""
from polyzymd.analyses.stats import format_pct
sig_marker = "*" if significant else ""
return (
f"{prefix}: {condition_b} vs {condition_a} — "
f"Δ={format_pct(percent_change)}, p={p_value:.3f} {sig_marker}, "
f"d={effect_size:.2f} ({effect_label}), {direction}"
)
[docs]
def format_anova_line(*, f_statistic: float, p_value: float, significant: bool) -> str:
"""Format one standard ANOVA line."""
sig_marker = "*" if significant else ""
return f"ANOVA: F={f_statistic:.2f}, p={p_value:.3f} {sig_marker}"
[docs]
def format_markdown_bullet(prefix: str, line: str) -> str:
"""Format a markdown bullet line with consistent prefixing."""
return f"- {prefix}: {line}"
[docs]
def make_ranked_rows(
ranking: list[str],
get_values: Callable[[str], tuple[float, float]],
) -> list[tuple[str, float, float, int]]:
"""Build ranked rows as ``(label, mean, sem, rank)`` tuples."""
rows: list[tuple[str, float, float, int]] = []
for rank, condition_label in enumerate(ranking, 1):
mean_value, sem_value = get_values(condition_label)
rows.append((condition_label, mean_value, sem_value, rank))
return rows