spacr.qt.screens.outliers

Workflow inputs and outputs

Outliers

Review robust object/well outlier scores and the selected exclusion rule before carrying filtered data into analysis.

Open: QC → Outliers.

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.

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.

API reference.

Module tutorial.

The Outliers screen — which objects are wrong, and which wells are wrong.

A thin surface over spacr.qt.widgets.outlier_model, which is where all the statistics and all the arguments live. The screen’s only jobs are to load a table, collect the four decisions the engine needs (features, method, threshold, transform), run it off the GUI thread, and show what came back without recomputing a single number of its own.

Assembles what already exists:

Two tables, because there are two answers

The Objects tab is the per-object flags; the Wells tab is the across-well pass. They are separate tabs rather than one merged view because they answer different questions and routinely disagree: a well shifted as a whole flags almost none of its individual objects and is nevertheless the loudest point among wells. The engine’s report() is shown verbatim in the third tab, caveats included — the share flagged is not interpretable without the sentence saying whether a symmetric fence on skewed data produced it.

The object table shows the worst rows first and caps how many it draws; the number of flagged objects in the header comes from the result, never from the number of rows the table happens to be showing. Nothing about the export is capped.

Nothing is deleted here

The export writes the whole table with the flag columns added, and separately the flagged rows on their own. There is no “remove outliers” button: dropping objects is a decision about the analysis, made in the analysis, and a screen that offered it as a single click would make it the default.

register() is not called at import; read its docstring.

Classes

OutliersScreen

Load a measurement table, flag the bad objects, and name the bad wells.

Functions

make_outliers_screen(→ PySide6.QtWidgets.QWidget)

Factory handed to spacr.qt.app.register_app().

register(→ bool)

Put Outliers in the app registry, through the public seam. Idempotent.

Module Contents

class spacr.qt.screens.outliers.OutliersScreen(parent=None, *, threaded: bool = True)[source]

Bases: PySide6.QtWidgets.QWidget

Load a measurement table, flag the bad objects, and name the bad wells.

Parameters:
  • threaded – False runs the table read and the scan inline, in the same order and through the same signals, so a test can drive the whole screen synchronously without the behaviour diverging.

  • parent – parent widget; ownership only.

Build the screen: the controls beside the object, well and report tabs.

Parameters:
  • parent – parent widget, or None.

  • threaded – read and scan on a worker thread. Set False in tests so scan finishes before it returns.

active_jobs() → int[source]

How many worker threads are still winding down.

choose_table() → None[source]

Ask for a file, then load_path() it.

closeEvent(event)[source]

Stop background work and unlink before going away.

Parameters:

event – the Qt close event.

current_method() → str[source]

The spacr.qt.widgets.outlier_model.METHODS member picked.

export_csv() → None[source]

Write the flags out: the whole table, the flagged rows, the wells.

Three files, because they have three different row meanings and one sheet mixing them would have to be unpicked before anyone could use it. The first is the whole table with the columns added — the “write columns” case, and the one that keeps every object — and the second is the same rows filtered down to the flagged ones for a quick look. The engine’s own filtered() is what produces it, so the file and the screen cannot disagree about what was flagged.

is_busy() → bool[source]

True while a read or a scan is in flight.

load_path(path: str, table: str | None = None) → None[source]

Load a CSV or one table of a SQLite measurement database.

The read runs on a worker thread through spacr.qt.job_runner.JobRunner; listing the table names stays inline because the picker has to be populated before the read is dispatched, to know which table to read.

Parameters:
  • path – a CSV, TSV or TXT file (by extension), read as one table; any other path is opened as a SQLite measurement database and its tables are listed in the picker.

  • table – the database table to read, also selected in the picker when the database has it; None reads the picker’s current table.

objects_frame() → pandas.DataFrame | None[source]

The loaded table with the flag columns added, or None.

scan() → None[source]

Run the engine over the loaded table, off the GUI thread.

set_frame(frame: pandas.DataFrame, *, label: str = '', scan: bool = True) → None[source]

Scan frame. The one call a host needs.

Parameters:
  • frame – unmodified measurement table to expose in the feature picker and pass to the configured outlier scan.

  • scan – False loads the table and fills the feature picker without running anything, for a caller that wants to set the method first.

spec() → spacr.qt.widgets.outlier_model.OutlierSpec[source]

The controls as an OutlierSpec. The screen’s whole state.

Raises:

OutlierError – from the spec itself on a combination it refuses — the screen never invents a value the engine would not accept.

property frame: pandas.DataFrame | None[source]

The table being scanned, unmodified.

property result[source]

The last OutlierResult, or None.

spacr.qt.screens.outliers.make_outliers_screen(app_key: str | None = None) → PySide6.QtWidgets.QWidget[source]

Factory handed to spacr.qt.app.register_app().

spacr.qt.screens.outliers.register() → bool[source]

Put Outliers in the app registry, through the public seam. Idempotent.

The row itself – the key, the name, the blurb, the section, the “no headless run” sentence, the API doc link and the nine translations of the display name – is declared in spacr.qt.app_catalog. spacr.qt.app.register_app() distributes those into the four tables each used to need a hand-edit in, and this function’s whole job is to name which row. That is what lets the app be registered without importing this module at all: the launch reads the table, and the screen is imported when somebody opens it.

SECTION_EXPLORE rather than SECTION_RESULTS, and the reasoning is worth writing down because the first instinct is the other one. This screen looks like QC — it is about whether to believe what a run produced — but what it does is what the Gate Editor and the Feature Explorer do, and it sits beside them: you pick features, you move a threshold, you watch a distribution answer, and what comes out is a column the user then filters or gates on. Results & QC holds the screens that hand back a verdict; this one hands back a question with the evidence attached, and filtered() is the only place a row is ever dropped and it has to be called on purpose.

The cap made the choice concrete rather than academic: MAX_APPS_PER_SECTION is 13 and Results & QC was already at 12 with Control Charts — the campaign-level verdict — arriving in the same batch. That is the section’s honest occupant, and this one had somewhere honest to go. Both were checked against the cap before the placement, not after.

Not called at import. app.py imports spacr.qt.widgets before register_app exists, so nothing reachable from the top of that file can register during its import, and a registration that happens later is one that some importer’s snapshot of APPS predates. The one place a registration is visible to everybody is spacr.qt.SELF_REGISTERING_MODULES, which spacr.qt.run() runs after spacr.qt.app is fully executed and before MainWindow.__init__ reads the registry. Turning this screen on is therefore one row there:

"spacr.qt.screens.outliers",

and nothing else: the strings above travel with the registration.

Returns:

True if this call is what registered it. Safe to call again — a module imported from two paths, or a test that re-imports it, must not raise on the duplicate key.