spacr.qt.screens.qc_dashboard¶
Workflow inputs and outputs¶
QC¶
Inspect stored segmentation, unit, leakage and plate-effect checks. Open its nested viewers for detailed inspection.
Open: Home → QC.
Inputs and outputs below include conditional alternatives. The guidance and handoff notes say which route applies.
Inputs
Measured objects — measurements/measurements.db; object tables depend on the enabled cell, nucleus, pathogen and organelle masks. Relevant tables, depending on the route:
cell,nucleus,pathogen,cytoplasm. Relevant columns, depending on the route:plateID,rowID,columnID,fieldID.Quality-control results — Stored project checks and QC reports; a missing check is not a passing result.
Outputs
Quality-control results — Stored project checks and QC reports; a missing check is not a passing result.
Figures and table exports — The output location chosen by the tool; exports describe the selected data and filters.
Before this module
Measure: Review available checks and missing evidence.
One screen that answers “is this run usable?”.
The screen half of spacr.qt.widgets.qc_summary. It shows the
segmentation, units, leakage, plate-effect and agreement verdicts side by
side, with the one-line summary they add up to.
What it is for. Checking a project before its numbers are used. After Mask and Measure, and again after Classify, QC gathers the verdicts those steps already wrote into one place, so the question does not need five screens.
What it needs. A project or plate folder, chosen with Browse or dropped
onto QC. Each card reads a file that is already on disk: the
segmentation scorecards a Mask run writes (seg_qc), the units stamp
Measure puts on every row of measurements.db, leakage.json from the
newest Classify (CV) evaluation bundle, and plate_qc.json and
agreement.json when a plate-effect or annotator-agreement report has been
saved under the project.
What it produces. Nothing on disk. Each card carries a verdict –
ok, missing, warn, fail or error – with a headline, the
details behind it and, for a check that has never run, the step that would
produce it; the overall verdict is the worst of them. A card older than its
inputs is marked stale rather than downgraded, and missing means nothing
was checked, not that nothing is wrong.
What to do next. Fix what a warn or fail card names at its source
and re-run that step; the cards are read again when a file has changed.
Layer Viewer shows the images behind a failing check, Control Charts follows
the same checks over time and Outliers finds the wells or objects unlike the
rest; all three open from this screen’s masthead.
It reads; it does not score. The rule is spacr.qt.prerun’s, and
that module says why: opening a plate’s masks costs seconds to minutes, and a
screen that pays that on every visit is a screen nobody keeps. So the reads go
through a fingerprint cache – one listdir and one stat per artifact – and
the parse only happens when something on disk has actually changed.
Nothing here disables anything. Dashboard.blocks_run is a constant False,
and this screen has no Run button to gate. A QC verdict that stops work gets
switched off; one that informs it gets read.
Classes¶
Read every QC verdict for a project and show them together. |
Functions¶
|
Put qc_dashboard's fold strip on |
|
Factory handed to |
|
Add the QC Dashboard to the app registry. Idempotent. |
Module Contents¶
- class spacr.qt.screens.qc_dashboard.QCDashboardScreen(parent: PySide6.QtWidgets.QWidget | None = None, *, src: Any = '', threaded: bool = True, reader=None)[source]¶
Bases:
PySide6.QtWidgets.QWidgetRead every QC verdict for a project and show them together.
- Parameters:
src – project folder to read; may be set later.
threaded –
Falsereads inline, emitting the same signals in the same order, so a test can drive the screen synchronously.reader – substitute for
spacr.qt.widgets.qc_summary.read_dashboard(), for tests.parent – parent widget; ownership only.
Build the dashboard and arm its drop zone.
The registry key is named here rather than inherited: screens that build themselves rather than being the generic
AppScreenhad none, and fold installation dispatches on exactly that – so this screen could declare folds and never be handed them.Its job runner is marked not user-visible, because it never runs anything: it reads verdicts already on disk, plus the folder check and the fingerprint, on every visit including the ones where nothing has changed. Visible, each of those would flash “QC - running” on Home for a read the user never started.
- Parameters:
parent – parent widget, or
None.src – project or plate folder to open with.
threaded – read on a worker thread. Set
Falsein tests sorefreshfinishes before it returns.reader – an alternative verdict reader, for tests.
- closeEvent(event)[source]¶
Stop background work and unlink before going away.
- Parameters:
event – the Qt close event.
- dashboard() spacr.qt.widgets.qc_summary.Dashboard | None[source]¶
The most recent
Dashboard.
- refresh(*, force: bool = False) bool[source]¶
Re-read the verdicts. Off the GUI thread – all of it, now.
SPLIT IN TWO, and the split is the fix for a frozen application. Only the parse used to be handed to the runner; the two decisions in front of it – “is this a folder?” and “has anything changed?” – were taken inline, and both of them touch the disk at a path the user typed.
os.path.isdirwas one call, and_fingerprintis afind_scorecardslisting plus a stat per artifact.Measured on one workstation: a single
os.path.existsunder/nas_mnt, anautofsmount whose share was asleep, had not returned after TWENTY SECONDS – the stat is what triggers the automount. A project folder on that mount is exactly what this screen is for, and the whole interface stopped the moment one was dropped on it, browsed to, or simply refreshed. It left no traceback, because a stalled event loop is not a crash.path_probeis deliberately NOT used for the folder guard. It answers optimistically, so it could only ever say “go on and read”, which the worker then decides properly anyway; a second guard on the GUI thread would add a way for the two answers to disagree and buy nothing. Every message the screen showed still appears – a moment later, and that is the only difference the user can see.- Parameters:
force – read even when the fingerprint says nothing changed.
- Returns:
whether a read of the disk was started. Reading inline (
threaded=False) that is exact, because the worker half has already run and reported by the time this returns. Threaded, it means the job was started: the fingerprint is not taken yet, so “nothing changed” arrives later, on the status line.
- spacr.qt.screens.qc_dashboard.install_folds(screen: PySide6.QtWidgets.QWidget) spacr.qt.widgets.fold_strip.FoldStrip | None[source]¶
Put qc_dashboard’s fold strip on
screen’s masthead.Reached by the one pass over the stack that serves every host – see
spacr.qt.screens.map_barcodes.FOLD_HOST_MODULES.
- spacr.qt.screens.qc_dashboard.make_qc_dashboard_screen(app_key: str | None = None) PySide6.QtWidgets.QWidget[source]¶
Factory handed to
spacr.qt.app.register_app().
Nested helpers¶
- QCDashboardScreen.refresh.work(s=src, r=reader, force=force, previous=self._cache_key, had_one=self._dashboard is not None)¶
Off the GUI thread. Touches no widget – returns a verdict.
The cache comparison comes with it rather than staying behind: the key it compares IS the walk of the disk, so leaving the comparison on the GUI thread would leave the walk there too.
spacr/qt/screens/qc_dashboard.py:392