spacr.qt.screens.profiler

Workflow inputs and outputs

Prediction Profiler

Inspect how a fitted model responds as an input feature changes; predictions do not establish causal effects.

Open: Regression → Prediction Profiler.

Inputs and outputs below include conditional alternatives. The guidance and handoff notes say which route applies.

Inputs

  • Fitted feature classifier — The fitted tabular classifier and its recorded feature list, training settings and validation results.

Outputs

  • Figures and table exports — The output location chosen by the tool; exports describe the selected data and filters.

API reference.

Module tutorial.

Prediction Profiler — interrogate a fitted model one input at a time.

A coefficient table says which terms matter. It does not say what the model would predict for a well like yours, and it certainly does not say what happens if this one gRNA’s fraction doubles while everything else stays put. That question — one input moving, the rest pinned where you chose — is what this screen answers.

inputs (ranked)        ┌─────────────────────────────────┐
▸ grna[233460_1] +2.4  │            ______/              │
  grna[239740_3] -1.8  │      _____/                     │
  grna[000000_2] +0.1  │  ___/                           │
                       └─────────────────────────────────┘
                       held:  grna[239740_3] ──●──── 0.31
                              grna[000000_2] ●────── 0.02

The left column is spacr.profiler.sensitivity() — every input ranked by how far it actually moves the prediction, not by its coefficient, because a large coefficient on an input that never varies moves nothing. That ranking is what makes a three-thousand-term design usable: it tells you which input to open the profiler on.

Nothing is re-fitted. The screen reads a coefficient table a regression run already wrote and wraps it in spacr.profiler.FittedLinear, which is reading the fit. A profiler that re-fits is showing a second model under the first one’s name, and on a penalised backend with alpha='auto' it is not even the same model. A caller that has a live fitted object can hand it straight to ProfilerScreen.set_model() and skip the file entirely.

The link is named, not guessed. A coefficient table does not record which inverse link produced it, and applying the wrong one draws a plausible curve on the wrong scale. So the link is a control the user sets, it defaults to identity, and the axis label always says which one is in force.

Where there is no design, the assumption is stated. Without the original design matrix the observed range of each input is unknown, so the screen sweeps 0-1 — the range a per-gRNA fraction lives in — and says so in the status strip rather than implying it measured something.

Classes

CurveCanvas

Draws one Profile.

ProfilerScreen

Sweep one input of a fitted model; hold the rest.

Functions

curve_points(→ List[Tuple[float, float]])

Map a profile onto pixel coordinates inside width x height.

make_profiler_screen(→ PySide6.QtWidgets.QWidget)

Factory the registry calls to build this screen.

register(→ bool)

Add Prediction Profiler to the app registry. Idempotent.

Module Contents

class spacr.qt.screens.profiler.CurveCanvas(parent=None)[source]

Bases: PySide6.QtWidgets.QWidget

Draws one Profile.

Parameters:

parent – Qt parent.

Create the empty profile canvas.

Parameters:

parent – parent widget, or None.

curve() → spacr.profiler.Profile | None[source]

The profile currently drawn, or None.

paintEvent(event) → None[source]

Axes, then the curve, then the labels.

Parameters:

event – the paint event; not read, since the whole canvas is redrawn every time.

points() → List[Tuple[float, float]][source]

The pixel coordinates the curve is currently drawn at.

set_curve(curve: spacr.profiler.Profile | None, message: str = '') → None[source]

Show curve; None shows message instead.

Parameters:

curve – the Profile to draw, or None; a profile with fewer than two points also shows the message.

class spacr.qt.screens.profiler.ProfilerScreen(parent=None, coefficients: str = '', model: Any = None, design: pandas.DataFrame | None = None, threaded: bool = True)[source]

Bases: PySide6.QtWidgets.QWidget

Sweep one input of a fitted model; hold the rest.

Parameters:
  • parent – Qt parent.

  • coefficients – open straight onto this coefficient CSV.

  • model – use this already-fitted object instead of reading a file.

  • design – the design matrix, when the caller has it. Without one the screen sweeps DEFAULT_RANGE and says so.

  • threaded – False computes inline, so a test drives the screen synchronously without the behaviour diverging.

Variables:

last_error – text of the most recent failure, "" when the last operation worked.

Build the screen and arm its drop zone.

A model can arrive three ways and they are tried in order: an already-fitted model, a coefficients CSV to read one from, or nothing – in which case the screen says which file to choose.

Parameters:
  • parent – parent widget, or None.

  • coefficients – a results CSV to load the model from.

  • model – an already-fitted model, which wins over coefficients.

  • design – the design matrix the model was fitted on.

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

active_jobs() → int[source]

How many worker threads are still winding down.

closeEvent(event) → None[source]

Drain the worker before the widget goes.

Parameters:

event – the close event; passed to the base class after the worker threads are shut down.

curve() → spacr.profiler.Profile | None[source]

The profile currently drawn, or None.

design() → pandas.DataFrame[source]

The design the sweeps run over — supplied or synthesized.

held_values() → Dict[str, float][source]

Where each held input currently sits.

is_busy() → bool[source]

True while a model is still being read.

load_coefficients(path: str) → None[source]

Read a coefficient table and profile the model it describes.

Parameters:

path – CSV file with feature and coefficient columns; read on a worker thread and rebuilt with the chosen link. An empty path only asks for a table.

model() → Any[source]

The fitted object currently profiled, or None.

ranked_inputs() → List[Any][source]

Every input, ranked by how far it moves the prediction.

set_design(design: pandas.DataFrame | None) → None[source]

Supply the design matrix, so the sweeps use observed ranges.

Parameters:

design – the design matrix the model was fitted on, one column per input; None or an empty frame falls back to a synthetic design. A loaded model is re-profiled at once.

set_held(name: str, value: float) → None[source]

Hold one input at value and redraw.

Parameters:
  • name – the input to hold; it must have a held-value slider or KeyError is raised.

  • value – the value to hold it at, clamped to the slider’s range and snapped to its nearest step.

set_model(model: Any, *, design: pandas.DataFrame | None = None) → None[source]

Profile an already-fitted object, skipping the file entirely.

Parameters:

model – a fitted object spacr.profiler.predict() accepts (a statsmodels result, a scikit-learn estimator, anything with params or coef_, or a FittedLinear); None reports that the model could not be read.

variable() → str[source]

The input currently swept, or "".

spacr.qt.screens.profiler.curve_points(curve: spacr.profiler.Profile | None, width: int, height: int, *, margin: int = 36) → List[Tuple[float, float]][source]

Map a profile onto pixel coordinates inside width x height.

Split out from the widget so the plot is testable without reading pixels back: the shape of the curve is a property of this function, and the paintEvent only strokes what it returns.

Parameters:
  • curve – the profile to plot; None or empty gives [].

  • width – canvas width in pixels.

  • height – canvas height in pixels.

  • margin – gutter reserved for the axes.

Returns:

(x, y) pairs, left to right, y measured downwards.

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

Factory the registry calls to build this screen.

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

Add Prediction Profiler to the app registry. Idempotent.