spacr.qt.screens.app_screen

AppScreen — the reusable layout every non-interactive spacr app uses.

Structure (horizontal splitter):

┌───────────────────────┬─────────────────────────────┐ │ Settings (scrollable) │ Console (top) │ │ │ Usage bars | Run/Stop… │ │ QGroupBox sections │ Progress bar │ │ QFormLayout inside │ │ └───────────────────────┴─────────────────────────────┘

Classes

AppScreen

Generic settings + runtime screen used by every non-interactive app.

ModuleHeader

The masthead every module page wears: name, description, instruction.

Functions

QtGui_QListWidgetItem_helper(fig, idx[, target])

Build a QListWidgetItem with a thumbnail render of fig.

dimension_settings(→ dict)

dimension -> the setting keys that only mean something in it.

module_maturity(→ str)

The stage app_key is drawn in, registry row or not.

setting_dimension(→ str)

The dimension key depends on -- "z", "t" or "".

settings_section_maturity(→ str)

Return the least-mature stage applying to one settings section.

uses_ambient_background(→ bool)

Whether app_key's screen gets the generic ambient backdrop.

Module Contents

class spacr.qt.screens.app_screen.AppScreen(app_key: str, parent=None)[source]

Bases: PySide6.QtWidgets.QWidget

Generic settings + runtime screen used by every non-interactive app.

Composes the settings model on the left with the console, usage bars, figures card, and actions row on the right.

Parameters:
  • app_key – id of the app (see APPS in spacr.qt.app).

  • parent – parent widget; ownership only.

Variables:

error_explain_requested – emitted with (traceback, app_key) when the user clicks “Explain error”; MainWindow routes it to the AI Console for backward compatibility.

Build one module page: the settings column beside the runtime panel.

Ordering matters throughout and is the reason for the length. The live preview watches src and can only be wired once both panels exist, because the settings panel owns the field and the runtime panel owns the preview. The category hints have the same constraint in reverse. The page-surface sweep runs on every route, not only where a backdrop was installed: with the ambient preference off, skipping it left every layout container carrying the blanket window fill, which is what made the settings half a solid slab.

Parameters:
  • app_key – which module this page is; it selects the title, the blurb, the settings schema, the drop handler and the backdrop.

  • parent – parent widget, or None.

active_jobs() → int[source]

How many of this screen’s background jobs are still winding down.

The pipeline run is deliberately not counted: it has its own Stop button, its own console and its own refusal-to-close in closeEvent(). This is the housekeeping work – the usage poll and the issue report – that a test drives to quiescence.

adopt_runtime_pane(card, *, focus: bool = True)[source]

Name a card someone else put in the runtime splitter.

spacr.qt.preview_registry inserts a declared preview above the console; adopting it makes it collapse by its title, resize by its edge, and – as a preview – take the height when it is shown.

Parameters:
  • card – the card, already in the runtime splitter.

  • focus – whether showing it collapses the console, System, the buttons and the settings column.

Returns:

the pane, or None when this screen has no such splitter.

annotate_example_destination()[source]

The shared example plate folder, which is where data/ belongs.

apply_settings_dict(settings: dict) → int[source]

Push key/value pairs from settings into whichever settings widgets this app exposes.

A bulk load is one transaction. If it changes the form’s shape, the complete merged mapping builds one replacement screen before values are applied; no signal may replace the screen halfway through the loop. Silently skips keys the current app does not have — the same dict can safely be applied across several apps. Returns the count of keys actually applied.

Parameters:

settings – setting key to value mapping; legacy key names are translated first, and it is merged over the current values.

apply_settings_that_came_with(folder, *, pack_folder=None) → int[source]

Load the settings a downloaded example shipped, for THIS module.

The point of shipping settings beside data: a user who has to work out which column holds the labels, what the mask dimensions are and which channels were measured has done most of the work the example was meant to save. With them applied, Run is the next action.

Use the shared settings-pack reader to migrate old names and report renamed, dropped, and unreadable rows in the console. Apply only values supplied by the pack, leaving other form values alone. Re-anchor the publisher’s paths onto the local dataset while preserving subfolders.

Parameters:
  • folder – the unpacked dataset folder.

  • pack_folder – optional folder of shipped settings CSVs, preferred over the dataset’s own settings subfolder.

Returns:

how many settings were applied; 0 when no file was found, no supplied settings apply to this form, or applying them failed.

apply_workspace_state(state) → bool[source]

Put a screen’s settings back. Returns whether any key applied.

Only into the module it came from. Settings keys are shared across modules by name and mean different things – level is the regression’s fit level and the proportion plots’ unit – so replaying a measure screen’s state into a regression screen would set keys that happen to collide and leave the rest.

Parameters:

state – mapping with app_key and settings keys, as saved with the workspace; anything that is not a dict, names another module, or has no settings applies nothing.

changeEvent(event) → None[source]

Follow a live theme switch.

Only Home is rebuilt when the theme changes; every other screen is re-styled in place by re-applying the QSS. That is enough for anything whose colours come from the stylesheet, and not enough for a backdrop that paints itself — the DNA rain and the ambient background both capture their flat fill colour and their wallpaper at construction. Switching from dark to light left a black rain rectangle on a white page, and switching into Cell left it painting flat black over the micrograph the theme had just loaded. The ambient backdrop has exactly the same two captured values and therefore exactly the same two bugs.

Both palette events count, and that is the whole reason this works. QApplication.setPalette — which is what spacr.qt.theme.apply_qpalette() ends in — delivers ApplicationPaletteChange only to top-level widgets (Qt 6.11, verified); every child, including every AppScreen inside MainWindow’s stack, gets PaletteChange instead. Listening for the application event alone meant this handler fired in the tests that synthesised it and never once in the running app.

Saving Preferences goes through the same call, so this is also where an ambient preference change lands on a screen that is already open — including the toggle switching back on, which has to build a widget that does not exist yet and so cannot be done by anything walking the live widget tree.

What is deliberately not re-applied is anything the user picked: the rain’s trail colour (it has a swatch in its settings bar) and the ambient theme + palette (they are Preferences entries). Silently resetting a choice the user made is worse than a slightly off-theme one.

Parameters:

event – the state-change event; it is passed to the base class, and only its type is read – ApplicationPaletteChange and PaletteChange re-theme the backdrops.

choose_source_folder() → str[source]

Ask for the run’s source folder and put it in the src field.

Returns:

the folder chosen, or "" if the dialog was cancelled or the screen has no src field to write to.

choose_the_test_data(*, chooser=None, ask=None) → dict[source]

Ask which half of the example plate to fetch, then fetch it.

The same two routes Annotate offers, through the same dialog: the crops that are already cut, or the merged arrays they were cut from. Classify can train from either, and they differ by 110 MB, so the choice is worth describing before it is made rather than after.

Parameters:
  • chooser – replaces the dialog, for tests.

  • ask – replaces the downloader, for tests.

Returns:

the settings that were applied, or an empty mapping.

clear_category_hint() → None[source]

Fall back to the pinned (expanded) category, or to the prompt.

closeEvent(event)[source]

Cancel and join this screen’s worker before destroying widgets.

A worker that has not reached a safe boundary keeps the screen alive; dropping its references or force-terminating it could corrupt an output and triggers Qt’s fatal “QThread destroyed while running”.

An accepted close also joins the owned backdrop renderer. Showing the screen again creates a fresh backdrop from the current settings.

Parameters:

event – the close event; ignored (so the screen stays open) when the worker is still running three seconds after the cancel request.

close_run_beside() → bool[source]

Take the second run’s live plot away, keeping its PHOTOGRAPH.

A still stands in for a run that is not live. The picture stays at about 5 ms a frame instead of 75, and the run’s plot STATE was never in the widget – so making it live again is cheap, and that is what the bound buys.

dimension_is_on(dimension: str) → bool[source]

Whether this screen is showing dimension’s settings now.

Parameters:

dimension – "z" (3D) or "t" (time); a dimension this screen does not track reads as off.

dimension_switch(dimension: str)[source]

The 3D or Time toggle, or None on a screen that carries neither.

Parameters:

dimension – "z" for the 3D toggle or "t" for the Time toggle.

eventFilter(obj, event)[source]

Show/hide the hover tooltip and update the hint strip on Enter/Leave.

Parameters:
  • obj – the watched widget; its settingsCategory or settingKey property decides whether a category blurb or a setting’s help is shown.

  • event – the filtered event; a ToolTip on a widget with hover help is swallowed, Enter schedules the help after the global delay and Leave cancels pending help, and every event is otherwise passed to the base class.

example_images_destination()[source]

The shared example plate folder. See hf_download.example_plate_folder.

force_restart(*, launcher=None, exiter=None) → bool[source]

Save this module and its settings, then restart spaCR.

Parameters:
Returns:

bool – True when a replacement process was started. If saving fails, returns False without stopping the current process.

hideEvent(event) → None[source]

Let the screen stop paying for things nobody can see.

Parameters:

event – the Qt hide event.

is_busy() → bool[source]

True while a background job has not yet delivered its result.

keep_the_src_openable(destination) → str[source]

Take back a shipped src the panel cannot open. Return the value.

THE RULE, once, for every route that applies example settings.

A shipped settings file records the machine that GENERATED it, and reanchor_example_paths re-homes what it can. What it cannot resolve it deliberately leaves alone – a template token, or a path whose folder name matches nothing here – and that value then reaches the field verbatim – which is how Mask Generation came to show the literal token <src> after loading the example images.

A MORE SPECIFIC SHIPPED VALUE IS KEPT. Measure’s example points src at the plate’s merged/ subfolder, and reanchor_example_paths() records that collapsing that to the plate root “would quietly measure the wrong directory rather than fail”. So this only ever replaces a value that is not a directory – never one that merely differs from destination.

Path("") IS THE WORKING DIRECTORY and its is_dir() is True, so an empty cell has to be rejected before the filesystem is asked or the run reads the cwd.

Parameters:

destination – the folder the example was unpacked into.

Returns:

the value the field ends up holding.

live_run_count() → int[source]

How many runs have a live, interactive plot on screen right now.

load_the_annotate_example(*, ask=None) → dict[source]

Download the annotation example and fill this module’s settings in.

Parameters:

ask – optional download function used in place of spacr.qt.hf_download.download_annotate_example().

Returns:

the settings that were applied, or an empty mapping.

load_the_example_images(*, ask=None) → dict[source]

Download the example plate and populate the src setting.

Parameters:

ask – Optional download function used in place of spacr.qt.hf_download.download_toxo_mito_demo().

Returns:

A mapping containing the selected source directory and the downloaded settings path. Returns an empty mapping if the download fails or has not completed.

load_the_example_screen(*, download: bool = True, kind=None) → dict[source]

Fetch the example screen and fill count_data and score_data.

Parameters:

download – If True, download files that are not already in the local cache.

Returns:

A mapping of populated setting names to their file paths.

load_the_measure_example(*, ask=None) → dict[source]

Download Measure’s example plate and point src at it.

Parameters:

ask – optional download function used in place of spacr.qt.hf_download.download_measure_example().

Returns:

a mapping with the source directory, or empty when the download failed or was cancelled.

load_the_ops_example(*, ask=None, folder=None) → dict[source]

Fill the OPS settings with the test data, fetching it when needed.

Parameters:
  • ask – replaces the downloader, for tests.

  • folder – replaces the cache folder, for tests.

Returns:

the settings that were applied; empty while a download is still running or after a failure.

load_the_screen_data(*, kind=None, ask=None, choose=None) → dict[source]

Ask which pieces of the screen to fetch, then fetch them.

Parameters:
  • kind – "measurements" or "crops", so the Feature and Image-crops buttons each show only their own. Filtered rather than greyed: a Feature download listing eight rows and refusing four of them would be four chances to start a 30 GB transfer by mistake.

  • choose – replaces the picker, for tests.

  • ask – replaces the downloader, for tests.

Returns:

what was set on the panel, or an empty mapping.

load_the_sequencing_example(*, picker=None) → dict[source]

Fetch published reads and point src at the folder they land in.

Parameters:

picker – replaces the dialog, for tests.

Returns:

{"src": folder} when something was downloaded, else {}.

measure_example_destination()[source]

The shared example plate folder.

The same one Mask and Annotate use: merged/ and measurements/measurements.db are two halves of one plate, and downloading them into separate trees meant they could not be opened together.

open_run_beside(record) → bool[source]

Open a second run’s results beside the loaded one.

DELIBERATE, NOT THE DEFAULT. Reached from the Runs tab’s context menu; nothing opens a second run on its own.

Parameters:

record – a Runs-tab row, or a run folder.

Returns:

whether a second run is now live.

page_fill()[source]

The flat colour this screen paints itself, or None.

_clear_page_surfaces makes every layout container transparent so that whatever is behind them shows through. That is right, and it is only half a page: something still has to be behind them. With an animation installed that something is the animation. With the ambient preference off, or the Animation preference set to none, nothing was — so the containers showed the blanket QWidget {{ background-color: bg }}, which on the dark theme is #000000. That is the black box behind the settings categories, reported three times: not a container the sweep missed, a page with no colour of its own.

None — meaning “let the stylesheet paint what it always did” — in exactly two cases:

  • a backdrop is installed. It covers the screen and paints its own fill, so a second full-rect fill under it is wasted work.

  • an image theme. There the window paints the wallpaper (or, with no cached image, a gradient in the theme’s own hues) and QWidget is transparent precisely so it shows through; a flat fill here would paint over the picture the theme exists for.

Never raises: a page that cannot resolve its colour falls back to the rendering it had before this existed.

paintEvent(event) → None[source]

Paint the page under everything this screen lays out.

Deliberately does not chain to super() when it fills. The base implementation is what draws the stylesheet background, and the stylesheet background is the bg slab being replaced — calling it afterwards would paint black straight back over this.

Parameters:

event – the paint event; handed to the base class only when there is no page fill. The fill always covers the whole screen, not just the event’s region.

pick_wells_for(field, key: str = '') → str[source]

Open the plate map on field’s value. Returns what was written.

Parameters:

field – the settings field holding a well specification; its text() seeds the picker and setText() receives the choice when the field has them.

Returns:

the new specification, or "" when the user closed without choosing – in which case the field is untouched.

point_src_at(folder) → bool[source]

Put folder in this module’s src field. Returns whether it took.

The counterpart of Make Masks’ _open_folder for a module screen: a module does not open a folder, it runs on one. Reaches the widget the same way _put_the_measure_example_in_place() does, so the two routes cannot drift on where src lives.

Parameters:

folder – the folder to run on, as a path or a string.

Returns:

True when the screen has a src field and it took the value.

static reanchor_example_paths(loaded, destination) → dict[source]

Re-root every absolute path in loaded onto destination.

A shipped example settings file records the paths of the machine that GENERATED it, which on any other machine names a user that does not exist:

gen_masks_settings.csv    src,/home/carruthers/datasets/plate1
crop_measure_settings.csv src,/home/carruthers/datasets/plate1/merged

Both lines matter. The first is why the path is wrong; the second is why substituting the destination outright is not the fix – the Measure set points at a SUBFOLDER, and collapsing it to the plate root would quietly measure the wrong directory rather than fail.

LISTS AND TUPLES ARE NOT A CORNER CASE. Classify’s src is list-valued and regression’s count_data, score_data and paired_data are too, and utils.load_settings turns any CSV cell starting with [, ( or { into a real Python container. An earlier version of this method tested isinstance(value, str) and skipped everything else, which skipped exactly the two modules whose loaders never write a local path as a fallback – so for those the publisher’s path was the panel’s only source of truth. Containers are walked.

Most of the per-path work is not new. spacr.portable_paths.reroot_crop_path() already picks the deepest recorded suffix that EXISTS below the current root, so a rewrite is only made when the reconstructed path is really there; it is tried first and its answer preferred. What it cannot do is the root itself – its resolution needs a suffix to match, and src pointing at the plate folder has none, which is the reported case. That one gap is filled by matching the destination’s own folder name.

A path that already resolves on this machine is left ALONE: a user who imported an example, edited src to their own data and saved would otherwise have that edit undone by the next example load.

Parameters:
  • loaded – the settings as read from the shipped file.

  • destination – the local folder the example actually unpacked to.

Returns:

a new mapping; the input is not modified.

refresh_ambient_background() → None[source]

Re-read the ambient preferences and apply them to this screen.

The restart-free path for the Preferences toggle: turning it off deletes the widget outright rather than hiding it, turning it on builds one on a screen that has been open all along, and a new theme/palette is pushed at the existing one without rebuilding it. Idempotent, and cheap enough to call on every show.

Never raises, for the same reason the install does not.

refresh_maturity_visibility() → None[source]

Show/hide Alpha and Beta settings without discarding typed values.

ALSO THE ONE PLACE A SECTION’S VISIBILITY IS DECIDED. Maturity is not the only reason a category is not on the form – a category every one of whose settings needs a z axis is not on a flat plate’s form either – and two functions each calling setVisible on the same card is how a card comes back the next time Preferences is saved. So the dimension switches are answered here as well, and the settings search hands visibility back to this method for the same reason. A heading the object rule holds back, because the run has none of its objects, stays hidden here too.

The notice below still speaks only for maturity: a category the 3D switch is holding back is not “hidden by Preferences”, and saying so would send the user to a dialog that cannot bring it back.

register_workspace() → None[source]

Enrol this screen and its panels with the workspace registry.

Registered as CALLABLES returning the attribute, never as the widget: _results_panel is rebuilt when the module changes, and a captured reference would hand a run journal a deleted C++ peer to ask.

rendered_settings_sections() → tuple[source]

The section widgets actually mounted in the settings panel.

_settings_sections deliberately also contains dormant forms for object-gated settings. Visual consumers – maturity and category hints in particular – must use this subset instead.

restore_run_workspace(record) → dict[source]

Restore the workspace recorded for a saved run.

The console reports sections that could not be restored and files that have moved or changed.

Parameters:

record – Run record or run-folder path accepted by spacr.workspace.load().

Returns:

dict – Restore report with restored, skipped, and files entries.

reveal_settings() → bool[source]

Open the settings column if it is collapsed; the user asked.

Ctrl+F puts the caret in the settings search, which cannot take it from a column folded away to the left.

Returns:

whether the column is open now.

run_photograph(folder)[source]

The still kept for a run that is no longer live, or None.

Parameters:

folder – the run’s output folder; looked up by absolute path, and an empty value gives None.

running_modules() → list[source]

Return active modules across the application.

Each result contains the module label, its application key, and the elapsed run time in seconds when that information is available. The list is used to identify work that a forced restart will interrupt.

screen_data_destination()[source]

The shared example plate folder the screen pieces unpack into.

sequencing_example_destination()[source]

Where the FASTQ goes: a reads folder beside the other examples.

set_dimension(dimension: str, on: bool) → None[source]

Switch a dimension’s settings on or off.

Driven through the toggle where there is one, so the switch never shows a state the form does not have; a screen built without the action row still moves, which is what lets the settings panel be gated before the row that gates it exists.

Parameters:
  • dimension – "z" (3D) or "t" (time); a dimension this screen does not track is ignored.

  • on – True to show the dimension’s settings, False to hide them.

setting_row_is_visible(key: str) → bool[source]

Whether key’s row is currently on the form.

The read-back the switches are checked against: “visible” for a setting is the state of its ROW, not of its widget, because the widget of a hidden row is still there holding the value it had. False for a key this screen does not render at all.

ASKED OF THE FORM, NOT OF THE SCREEN. isVisible is false for everything on a page that has not been shown yet, which would make this answer “hidden” for the entire settings panel of a module the user has not opened. isHidden and QFormLayout.isRowVisible answer what was hidden ON PURPOSE, which is the question.

Parameters:

key – settings key of the row; a category still waiting to be built is built first so its row can be read.

settings_for_my_data(*, answers: dict | None = None) → dict[source]

Propose settings from the attached tables and apply accepted values.

Parameters:

answers (dict, optional) – Answers to questions the data cannot resolve. Supplying this mapping skips the interactive question page.

Returns:

dict – Settings written to the panel, or an empty mapping when the advisor cannot run or the proposal is declined.

showEvent(event) → None[source]

Re-measure the hover-help strip after stylesheet/font polishing.

Also a second, independent chance to pick up an ambient- background preference that changed while this screen sat in the background. The first is changeEvent(), which fires on every Preferences save; this one covers a preference written without apply_preferences_to_app behind it. Module screens are built once and kept, so without either of them a toggle would need a restart. It costs a settings read and returns without touching anything when nothing changed — see refresh_ambient_background().

Parameters:

event – the show event; passed to the base class, and only a non-spontaneous (application-initiated) show begins a new view for the focus-collapse rule.

show_category_hint(title: str) → None[source]

Show one category’s blurb in the strip under the actions row.

The strip is fed by TITLE, because a hovered header carries its own name and nothing else. A heading nested under another resolves its help by PATH – “Cell” under “Object filtration” is not the “Cell” segmentation category – so what that resolved to when the section was built is read back here rather than looked up again by the bare word, which would hand a filtration sub-heading the blurb about Cellpose models.

Parameters:

title – the category heading as built; its blurb is read from the section’s recorded blurbs, falling back to category_tooltip(), and the translated heading is shown in capitals before it.

show_module_hint(key: str, summary: str = '') → bool[source]

Explain a MODULE in this screen’s strip, for a dock hover.

The window routes a dock hover to whichever page is in front (see MainWindow._show_module_hint), so on a module screen it arrives here. The strip is the same one the per-setting help writes to – deliberately, because it is the bottom of the window either way and a second strip stacked under it would be two places to look.

THE HOLD IS THE MODULE ONE, not the setting one: thirty seconds rather than ten, because these links leave the application. A hovered SETTING overwrites this the moment the pointer reaches the form, and that is the right precedence – the reader has moved on.

Parameters:
  • key – the module to explain.

  • summary – the sentence, already resolved and translated by MainWindow._show_module_hint. It has to arrive from there: module_summary falls back to the registry’s English description, and a screen has no registry to look one up in.

Returns:

whether anything was written.

showing_the_figure_grid() → bool[source]

Whether the grid of every figure is the page on screen.

showing_the_live_graph() → bool[source]

Whether the interactive volcano is the page on screen.

showing_the_results() → bool[source]

Whether the coefficient results are the tab on screen.

the_advisor_can_run() → str[source]

Return an empty string when the advisor can run, otherwise why not.

the_name_carries_the_help() → int[source]

Move every settings tooltip off its field and onto its NAME.

Returns:

how many were moved, so a test can assert a number.

THE HOVER TARGET IS THE SETTING’S NAME. Hovering the box you type in pops the help over the value you are reading or editing, and a field can be focused and clicked, so the popup fights the interaction. The name is inert, which makes it the calm target.

retarget_field_tooltips is how the rest of the tool does this – every dialog and side panel calls it at the end of its __init__ – and the main settings form was the one place that never did. Measured on Mask: 1,538 fields carried their own tooltip and 13 labels had one. _lay_out_setting_row moves the help for a row it lays out itself, which is 77 of that screen’s 1,657; the rest arrive from the lazy row builder, the deferred “rows that are back” pass, and a fold mounting another module’s categories.

Run again after rows appear later, since it only ever moves a tooltip that is still on a field: it is idempotent by construction, and a second pass over rows already moved finds nothing to do.

unregister_workspace() → None[source]

Withdraw this screen’s sections. Called when it is torn down.

workspace_state() → dict[source]

The settings AS EDITED, which is a superset of the run’s dict.

open_run writes the settings the PIPELINE was given. Keys the run did not consume – a path typed into a module the user then switched away from, a threshold set for the next run – are still the user’s work and are not in that file. This is the screen’s whole state.

class spacr.qt.screens.app_screen.ModuleHeader(title: str, description: str = '', instruction: str = '', *, app_key: str | None = None, parent: PySide6.QtWidgets.QWidget | None = None)[source]

Bases: PySide6.QtWidgets.QWidget

The masthead every module page wears: name, description, instruction.

Three pieces of text in a fixed relationship, and the relationship is the point:

  • the module name, large — DisplayHeading, which is 30 px against a 13 px body;

  • the description beside it, one muted line saying what the module is for, with the API documentation link after it;

  • the instruction under the name, one muted line saying what to do on this page.

Trailing controls — a source label, a table picker, a Load button — go on the same row through add_trailing(), right-aligned past the stretch, so a screen that had its own header row keeps it.

The shared component keeps headings and actions consistent across screens. It is transparent because a header is a page region rather than a card; this allows the configured page backdrop to remain visible.

Parameters:
  • title – the module name, shown large.

  • description – one line to the right of the name. Never wrapped — it may shrink below its ideal width rather than force the window wider — and repeated in its own hover help so a truncated one is readable.

  • instruction – one line under the name. Omitted if empty.

  • app_key – registry key. Given one, the module’s API documentation link is the last line of the description’s hover help. NOTHING IS DRAWN BESIDE THE DESCRIPTION: a dot used to be, and a masthead reads as one sentence rather than a sentence and a mark. The link is not lost with it – see spacr.qt.widgets.ApiHelpLabel, which carries the same help every setting’s label carries.

  • parent – parent widget; ownership only.

Build the shared module masthead.

Parameters:
  • title – the module’s name, set at display size.

  • description – one-line blurb; with an app_key it becomes the link into that module’s API help.

  • instruction – what to do first, shown under the title.

  • app_key – the module the description links to; without it the blurb is plain text.

  • parent – parent widget, or None.

add_trailing(widget: PySide6.QtWidgets.QWidget, stretch: int = 0) → PySide6.QtWidgets.QWidget[source]

Put widget on the header row, right of the stretch.

For the screens whose header row also carries controls — Control Chart’s table picker and Load button, Graph Builder’s source label. They keep their row; they stop having to build the title part of it themselves.

Parameters:

widget – the control to append to the header row; it is also returned, so a caller can build and keep it in one expression.

spacr.qt.screens.app_screen.QtGui_QListWidgetItem_helper(fig, idx: int, target=None)[source]

Build a QListWidgetItem with a thumbnail render of fig.

Used in the figures panel’s history strip. target is the widget the strip is on; the render is sized for that screen’s pixel density, and falls back to the primary screen when no widget is given.

Parameters:
  • fig – the Matplotlib figure to render as a PNG thumbnail; a render failure leaves the item without an icon.

  • idx – zero-based position in the history; the item’s text is #<idx + 1>.

spacr.qt.screens.app_screen.dimension_settings() → dict[source]

dimension -> the setting keys that only mean something in it.

READ OFF THE SETTINGS, NOT LISTED HERE. spacr.settings.categories already carries the answer, because the split was made deliberately when the experimental axes were added:

  • "3D Settings (Beta)" is every key that presumes a z axis – z_stack, the segmentation mode, the projection, the two voxel sizes and the anisotropy they derive (all three of which answer “how far apart are two planes”), and stitch_threshold, which links labels BETWEEN planes.

  • "4D Settings (Beta)" is the time half of the same split, and the source says so where the split is written: z_axis is filed under 3D “because 4D builds on the same z plan”, which leaves the 4D list holding “only time-axis and inter-frame tracking controls”.

  • the Timelapse and Motility modules’ own key lists join the time set, because every key in them is a per-frame or between-frame quantity – the frame rate, which tracker links the frames, how far an object may move between two of them, how long it may vanish for.

A key in neither set is dimension-free and stays visible whatever the switches say.

Returns:

a fresh dict of str -> frozenset; callers may keep it.

spacr.qt.screens.app_screen.module_maturity(app_key: str) → str[source]

The stage app_key is drawn in, registry row or not.

app_stage answers stable for a key it has never heard of, which is the right answer for a typo and the wrong one for a module that was folded into a host and had its row deleted: its settings would go from beta-tinted to unmarked on the day the row went, claiming a maturity nobody signed off. So a key with no row is asked of the fold tables, which record what its tile said.

Parameters:

app_key – the module’s registry key.

Returns:

"alpha", "beta" or "stable".

spacr.qt.screens.app_screen.setting_dimension(key: str) → str[source]

The dimension key depends on – "z", "t" or "".

Blank for the great majority of settings, which mean the same thing whatever axes the plate has.

Parameters:

key – settings key, matched exactly against the z (3-D) and t (time-lapse and motility) setting sets of dimension_settings().

spacr.qt.screens.app_screen.settings_section_maturity(app_key: str, title: str) → str[source]

Return the least-mature stage applying to one settings section.

An alpha or beta module colours every one of its settings. A stable module can still contain an explicitly experimental category – an alpha one is named with a trailing α (“Confluency α”), a beta one with (Beta) – in which case that section receives the more cautious stage.

Parameters:
  • app_key – the module’s registry key, whose stage comes from module_maturity().

  • title – the section heading; compared case-insensitively, it is alpha when it is "alpha", ends with α or contains "(alpha)", beta when it is "beta" or contains "(beta)", and stable otherwise.

Returns:

"alpha", "beta" or "stable".

spacr.qt.screens.app_screen.uses_ambient_background(app_key: str) → bool[source]

Whether app_key’s screen gets the generic ambient backdrop.

Every module screen except the ones that already animate something of their own — which today is exactly DNA_RAIN_APPS. Sequencing’s rain is about sequencing: bases falling behind the screen that maps reads to barcodes. Putting a second, unrelated animation behind it would fight it — two independent motions competing for the same pixels, neither readable, and two animation timers running on the one screen that already had one. So a screen gets one animated background or none, never both.

Written as a rule with a name rather than as an else on the rain’s if: the two backdrops are chosen by one decision, and the day a second module earns a themed animation of its own, adding its key to DNA_RAIN_APPS-style membership is all that is needed for the ambient one to step aside.

Parameters:

app_key – id of the app (see APPS in spacr.qt.app).

Returns:

True when the ambient backdrop belongs on that screen.

Nested helpers

AppScreen._analysis_lock_dialog._lock()

Persist the displayed analysis plan and show its immutable identity.

spacr/qt/screens/app_screen.py:11696

AppScreen._confirm_ram_guard.plan_for(_src, n_jobs)

This module’s estimate for n_jobs workers.

spacr/qt/screens/app_screen.py:9926

AppScreen._on_file_issue._file()

Submit the report, returning the failure AS DATA rather than raising.

The call is asynchronous, so an except around the caller can no longer see it – and a report that silently fails to send is worse than one that fails loudly.

spacr/qt/screens/app_screen.py:9766

AppScreen._post_the_report._file()

Build, redact and post the report. Off the GUI thread.

spacr/qt/screens/app_screen.py:9395

AppScreen._refresh_model_explainer.value(key, fallback)

One widget’s value, or the fallback when there is no such widget.

spacr/qt/screens/app_screen.py:4755

AppScreen._remember_runtime_splitter._save(*_args)

Store this splitter’s layout under its key.

spacr/qt/screens/app_screen.py:8185

AppScreen._section_holds_anything.already_built_rows(owner)

Iterate registered rows without forcing deferred captions.

spacr/qt/screens/app_screen.py:2935

AppScreen._section_holds_anything.holds_an_active_slot(owner) → bool

Whether deferred rows belong to a count-requested organelle.

spacr/qt/screens/app_screen.py:2944

AppScreen._with_the_controls.swap(node)

node rebuilt with its stand-ins replaced by controls.

spacr/qt/screens/app_screen.py:3962

AppScreen.load_the_annotate_example._done(result, error)

Restore the button whether the load worked or failed.

spacr/qt/screens/app_screen.py:5860

AppScreen.load_the_example_images.ask(parent, dest, on_done)

Start the demo download with the tar-aware worker.

spacr/qt/screens/app_screen.py:5953

AppScreen.load_the_example_images.done(result, error)

Re-enable the button whether the download worked or failed.

spacr/qt/screens/app_screen.py:5933

AppScreen.load_the_measure_example._done(result, error)

Restore the button whether the load worked or failed.

spacr/qt/screens/app_screen.py:5633

AppScreen.load_the_ops_example.report(text: str, _error: bool) → None

Put progress and failures in the console.

spacr/qt/screens/app_screen.py:5549

AppScreen.load_the_ops_example.use(where) → None

Apply the sample’s settings and say so in the console.

spacr/qt/screens/app_screen.py:5541

AppScreen.load_the_screen_data._done(result, error)

Restore the button whether the load worked or failed.

spacr/qt/screens/app_screen.py:5449

AppScreen.reanchor_example_paths.rehome(value)

Repoint every path in a value, whatever shape it is.

Recurses through lists and tuples: a settings value may be one path or a list of them, and rehoming only the string case leaves the list pointing at a folder that is not there.

spacr/qt/screens/app_screen.py:5335

AppScreen.reanchor_example_paths.rehome_text(text: str)

Repoint one path string at the folder the example now lives in.

spacr/qt/screens/app_screen.py:5309

_fit_to_lines.wrapped_lines(candidate: str) → int

How many lines candidate wraps to at the measured width.

Measured against the font Qt is actually painting, so it stays right at any font scale rather than at the one this was written on.

spacr/qt/screens/app_screen.py:510