spacr.qt.screens.dose_response¶
Workflow inputs and outputs¶
Dose–Response¶
Supply dose and response columns, controls and units before curve fitting; this route does not require sequencing.
Open: Home → Dose–Response.
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.Experimental layout — Exported plate/condition/control/replicate map. Keep its plate and well identifiers consistent with the acquired data.
Outputs
Assay results — Assay-specific result tables and figures in the configured destination, preserving well and condition identities.
Figures and table exports — The output location chosen by the tool; exports describe the selected data and filters.
Before this module
Experiment Design: Acquire and measure the experiment first, preserving dose/condition identities.
Measure: Join the measured response to explicit doses and controls.
Dose–Response — a concentration series, a 4PL curve, and an honest EC50.
The statistics are all in spacr.qt.widgets.dose_response and there is
none in here. This module is the surface: pick the concentration column, the
response column and (optionally) a grouping column, and get one curve per
gene or compound with its EC50 and confidence interval, drawn on the log axis
a dilution series is read on.
Three decisions shape the screen, and all three follow from the engine’s central claim — that the useful answer is sometimes “this experiment does not locate the EC50”, and a screen that cannot render that sentence would undo the module underneath it.
Refusals and one-sided bounds are rows, not silence. A plate where three
compounds fit and the fourth is cytotoxic at the top dose has four rows. The
cytotoxic one says refused and carries the engine’s message; a compound
whose midpoint sits past the highest dose says unbounded and carries
EC50 > 30 µM, with an empty EC50 cell. Dropping either from the table
would turn “we checked and the answer is no” into “no data”, which is the one
reading the numbers cannot survive.
Every number on this screen comes out of the engine. The table is
table(), the text is
report(), and the
plotted line is
curve(). Nothing is
recomputed here, so the figure, the exported CSV and the sentence a user
pastes into a methods section cannot drift apart.
The Curve picker offers the asymmetric model and does not choose it. Four-parameter is what Fit uses until someone says otherwise, and a five-parameter fit says in its own report whether the fifth parameter earned itself. A screen that picked the better-fitting model per group would hand back a plate whose EC50s came from two different models, compared as though they had not.
The fit runs off the GUI thread through
spacr.qt.job_runner.JobRunner, like every other read and compute in
the Qt layer. A profile-likelihood interval on a 96-compound plate is
seconds, not milliseconds, and threaded=False runs the identical code
inline so a test drives the same path the shipped screen does.
register() is not called at import; read its docstring.
Classes¶
Load a concentration series, fit a 4PL per group, and read the EC50s. |
Functions¶
|
Factory handed to |
|
Put Dose–Response in the app registry. Idempotent. |
Module Contents¶
- class spacr.qt.screens.dose_response.DoseResponseScreen(parent=None, *, threaded: bool = True)[source]¶
Bases:
PySide6.QtWidgets.QWidgetLoad a concentration series, fit a 4PL per group, and read the EC50s.
- Parameters:
parent – the usual Qt parent.
threaded –
Falseruns the table read and the fit inline, emitting the same signals in the same order, so a test drives the screen synchronously without the behaviour diverging.
Build the screen: the curve canvas beside the fit table and report.
- Parameters:
parent – parent widget, or
None.threaded – read and fit on a worker thread. Set
Falsein tests sofitfinishes before it returns.
- closeEvent(event)[source]¶
Stop background work and unlink before going away.
- Parameters:
event – the Qt close event.
- 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
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. The same shapespacr.qt.screens.trellis.TrellisScreenuses, for the same reasons.- 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;
Nonereads the picker’s current table.
- result_set() spacr.qt.widgets.dose_response.DoseResponseSet | None[source]¶
The last fit, or
None. What a test and an exporter both read.
- set_frame(frame: pandas.DataFrame, *, label: str = '') None[source]¶
Offer
frame’s columns and wait to be told which ones to fit.The one call a host needs. It deliberately does not fit: which column is the dose is not guessable from a measurement table, and a curve through the wrong pair of columns is worse than an empty axis.
- Parameters:
frame – the measurement table; its columns fill the concentration, response, group, plate, control, host and second-dose pickers.
label – the source line to show; empty shows the row and column counts.
- show_group(index: int) None[source]¶
Draw and describe the
index-th curve of the last fit.- Parameters:
index – position of the curve in the last fit’s groups; out of range, or with no fit yet, nothing happens.
- spec() spacr.qt.widgets.dose_response.DoseResponseSpec[source]¶
The spec the controls currently describe.
- spacr.qt.screens.dose_response.make_dose_response_screen(app_key: str | None = None) PySide6.QtWidgets.QWidget[source]¶
Factory handed to
spacr.qt.app.register_app().
- spacr.qt.screens.dose_response.register() bool[source]¶
Put Dose–Response in the app registry. Idempotent.
Called from
spacr.qt.SELF_REGISTERING_MODULES, whichspacr.qt.run()runs afterspacr.qt.appis fully executed and beforeMainWindow.__init__reads the registry — the position the docstring there explains. Not called at import, so importing this module to reachDoseResponseScreenfrom a test or a notebook does not mutate process-wide state.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_DESIGN, which is not the obvious answer and is the right one. Design is “everything that happens before the microscope: power, sample size, plate layout, controls and replicates”, and it already holds Power / Design. A dose–response series is the other pre-experiment calculation a screening lab runs: nobody fits an EC50 to admire it, they fit it to pick the concentration the actual screen will use, exactly as they run a power calculation to pick n. The output of this screen is an input to the next experiment, which is what the section means.The alternative reading — Explore, “ask the numbers a question you did not plan for” — is the weaker one because a concentration series is planned: the doses were chosen in advance and the curve is the thing the experiment was for. The cap made the choice concrete:
MAX_APPS_PER_SECTIONis 13, Explore stood at 12 before this batch, and Outliers — which really is an open question asked of a finished table — is the one that belongs there.- Returns:
Trueif this call is what registered it.