neu_eval.compare

One call from two registered pieces to everything a comparison produces.

compare(a, b) builds the table once, computes every metric from it, ranks and locates the disagreements, and, given a reviewed verdict file, adds an adjudicated score. A Report holds it all, raw and adjudicated side by side.

The two pieces must describe the same physical box. Read the second with read_piece(seg, level=..., crop=gt_piece), which converts the box using that level’s own voxel size and origin; matching shapes by hand or assuming a 2 ** level factor can shift it by part of a voxel. compare() checks the frames agree.

Attributes

Classes

Report

Everything one comparison produced.

Functions

compare(a, b, *[, labels, ignore_a, ignore_b, mask, ...]) → Report

Compare two registered pieces and return everything the comparison produced.

scattered_labels(piece, c, *[, factor, min_voxels]) → list[dict]

Reference labels whose bounding box is far larger than the label itself.

summarize(c, *[, at]) → dict

Every scalar metric for one table, as a single flat row.

Module Contents

class neu_eval.compare.Report

Everything one comparison produced.

summary and adjudicated_summary are flat dicts, so many comparisons make a DataFrame directly. The adjudicated_* fields are None when no verdicts were given; verdicts that changed nothing give a summary equal to the raw one, and verdict_tally shows why.

headline() → str

A one-line summary for a terminal or a log.

adjudicated: neu_eval.overlap.Contingency | None = None
adjudicated_summary: dict | None = None
contingency: neu_eval.overlap.Contingency
property kind_counts: dict[str, int]
labels: tuple[str, str]
rows: list[dict]
summary: dict
verdict_tally: dict | None = None
warnings: list[str] = []
neu_eval.compare.compare(a: Any, b: Any, *, labels: Sequence[str] = ('gt', 'seg'), ignore_a: Sequence[int] = (0,), ignore_b: Sequence[int] = (), mask: Any = None, top: int | None = 200, min_frac: float = 0.05, min_voxels: int = 1, rank: str = 'severity', locate: bool = True, point_at: str = 'seam', verdicts: Mapping[str, str] | None = None, check_frames: bool = True, check_scattered: bool = True) → Report

Compare two registered pieces and return everything the comparison produced.

a is the reference and b the side assessed; that sets only the default ignore_a=(0,), the output names, and the direction of voi_split / voi_merge.

locate=False skips the per-pair distance transforms, the one cost that scales with top; useful when only the numbers are wanted. point_at is passed to neu_eval.disagree.locate(). verdicts (pair_key -> verdict, from a reviewed disagreement file) adds an adjudicated score alongside the raw one.

neu_eval.compare.scattered_labels(piece: Any, c: neu_eval.overlap.Contingency, *, factor: float = SCATTER_FACTOR, min_voxels: int = SCATTER_MIN_VOXELS) → list[dict]

Reference labels whose bounding box is far larger than the label itself.

This mainly catches a reference assembled from several annotated crops that each number their bodies from 1: without neu-vol relabel, one id names a different cell in each crop, a low-numbered “body” is a chimera of unrelated cells, and every metric is meaningless with no error.

It warns rather than raises, because a genuinely fragmented annotation looks the same from the voxels; the warning carries the numbers so the reader can judge.

neu_eval.compare.summarize(c: neu_eval.overlap.Contingency, *, at: tuple[float, ...] = (0.5, 0.9)) → dict

Every scalar metric for one table, as a single flat row.

neu_eval.compare.SCATTER_FACTOR = 1000.0
neu_eval.compare.SCATTER_MIN_VOXELS = 100