Source code for playnano.analysis.utils.frames
"""
Frame-based post-processing helpers.
E.g. summarize per-frame statistics or produce histograms.
"""
from pathlib import Path
from typing import Optional, Sequence
import matplotlib.pyplot as plt
import pandas as pd
[docs]
def frame_summary_to_dataframe(
features_per_frame: Sequence[Sequence[dict]],
) -> pd.DataFrame:
"""
Build a DataFrame with one row per frame.
Summarises number of features, total area, mean intensity, etc.
Parameters
----------
features_per_frame : list of lists of dict
As returned by `FeatureDetectionModule.run()["features_per_frame"]`.
Returns
-------
pd.DataFrame
Columns:
- frame_index (int)
- n_features (int)
- total_area (int)
- mean_area (float)
- mean_intensity (float)
"""
rows = []
for i, feats in enumerate(features_per_frame):
areas = [f["area"] for f in feats]
intensities = [f["mean"] for f in feats]
rows.append(
{
"frame_index": i,
"n_features": len(feats),
"total_area": sum(areas),
"mean_area": float(pd.Series(areas).mean()) if areas else 0.0,
"mean_intensity": (
float(pd.Series(intensities).mean()) if intensities else 0.0
),
}
)
return pd.DataFrame(rows)
[docs]
def plot_frame_histogram(
df: pd.DataFrame,
column: str,
ax: Optional[plt.Axes] = None,
save_to: Optional[Path] = None,
bins: int = 20,
) -> plt.Axes:
"""
Plot a histogram of a per-frame summary metric.
Parameters
----------
df : pandas.DataFrame
As returned by `frame_summary_to_dataframe`.
column : str
Which column to histogram (e.g. 'n_features').
ax : matplotlib Axes, optional
save_to : Path, optional
bins : int
Number of histogram bins.
Returns
-------
ax : matplotlib Axes
"""
if ax is None:
fig, ax = plt.subplots()
ax.hist(df[column], bins=bins, edgecolor="black")
ax.set_xlabel(column)
ax.set_ylabel("Count")
ax.set_title(f"Histogram of {column}")
if save_to:
ax.get_figure().savefig(save_to, dpi=150)
return ax