spacr.qt.screens.agreement¶
Annotator Agreement — how much do two annotation passes actually agree?
The Annotate app writes one INTEGER column per pass into
png_list. Two people labelling the same crops therefore leave two
columns side by side, and the only question that matters before either
set is used as ground truth is: do they agree, and where don’t they?
Layout:
┌───────────────────────────────────────────────────────────────────┐
│ /data/plate1/measurements/measurements.db [DB…] [Run folder…] │
│ Read-only (mode=ro) — nothing here can modify your annotations. │
├──────────────┬────────────────────────────────────────────────────┤
│ Annotators │ a b n abstain raw κ band │
│ ☑ alice │ alice bob 410 92 88.0% +0.61 substantial │
│ ☑ bob ├────────────────────────────────────────────────────┤
│ ☐ carol │ Confusion [alice vs bob ▾] 1 2 │
│ │ 1 310 22 │
│ [Compute] │ 2 27 51 │
├──────────────┴────────────────────────────────────────────────────┤
│ Overall Cohen's κ +0.61 (substantial) · raw 88.0% · 49 to review │
├───────────────────────────────────┬───────────────────────────────┤
│ Disagreements png_path alice bob│ [crop preview] │
│ …/A01_1_cell_3.png 1 2 │ │
└───────────────────────────────────┴───────────────────────────────┘
Design notes:
Read-only, structurally. Every connection goes through
spacr.agreement. It opens the file withfile:…?mode=roandPRAGMA query_only = ON, the same approach the Database Browser takes. Adjudicating a disagreement is a job for the Annotate app. This screen only ever looks.Off the GUI thread. The report reads the whole
png_listannotation block, so it runs throughspacr.qt.bridge.make_thread()like every other spaCR job. Tests passthreaded=False.No modal dialogs on any error path. “You only picked one column”, “that file isn’t a database”, “this table has no annotation columns” — all of it lands in an inline status label. A QMessageBox would hang a headless run.
κ is never quoted alone. Raw percent agreement, the number of compared rows, the number of abstentions and the reason κ is undefined (when it is) are all on screen next to it. See
spacr.agreementfor why that matters on a screen where 98 % of cells are negative.
Classes¶
Inter-annotator agreement over the annotation columns of a database. |
Functions¶
|
Render a κ for display — |
Module Contents¶
- class spacr.qt.screens.agreement.AgreementScreen(parent=None, threaded: bool = True)[source]¶
Bases:
PySide6.QtWidgets.QWidgetInter-annotator agreement over the annotation columns of a database.
- Parameters:
threaded – compute the report on a worker thread (the default). Tests pass
Falsefor deterministic, synchronous behaviour.parent – parent widget; ownership only.
- Variables:
last_error – text of the most recent failure,
""when the last operation succeeded. Errors are only ever reported here and in the inline status label — never in a modal dialog.
Build the screen and arm its drop zone.
- Parameters:
parent – parent widget, or
None.threaded – run the agreement computation on a worker thread. Set
Falsein tests socomputefinishes before it returns.
- closeEvent(event)[source]¶
Let every in-flight compute thread finish before the widget dies.
- Parameters:
event – the close event, passed on to the base class once each running job thread has been asked to quit and waited on (up to five seconds each).
- compute() bool[source]¶
Build the agreement report for the ticked columns.
Everything that can go wrong here is a normal state — no database, one column ticked, a column that turns out to be empty — so every failure is inline text and a
Falsereturn.- Returns:
for the synchronous path, whether the report was built; for the threaded path,
Trueonce the job has started.
- disagreement_rows() List[List[str]][source]¶
The review list as plain strings — key first, then each label.
- is_busy() bool[source]¶
Whether anything is still running.
What the window asks before closing.
- Returns:
True while work is outstanding.
- report() spacr.agreement.AgreementReport | None[source]¶
The most recent
AgreementReport, or None.
- select_columns(names) bool[source]¶
Tick exactly
names; report inline for anything unknown.- Parameters:
names – annotation column names to check; every other listed column is unchecked. Names not in the list are reported in the status line.
- Returns:
True when every requested column was found.
- select_disagreement(row: int) bool[source]¶
Show the crop for review row
row.A missing PNG is a fact about the dataset (crops get moved, or the database was copied without them), not an error worth a dialog — the preview says so and the row stays selected.
- Parameters:
row – zero-based row of the disagreement table; out of range clears the preview.
- Returns:
True when an image was actually rendered.
- set_database(path: str) bool[source]¶
Open
pathread-only and list its annotation columns.Accepts the database file or a run
srcfolder. Any problem (missing file, not a database, nopng_list) is reported in the status label and returnsFalse— this never raises.- Parameters:
path –
measurements.dbfile, runsrcfolder ormeasurementsfolder; resolved withspacr.qt.screens.db_browser.resolve_db_path().- Returns:
True when a database with at least one annotation column was opened.