spacr.qt.screens.map_barcodes

Barcode QC integration and shared support for folded modules.

The Barcode QC page assesses reads per well, low-depth wells, unmapped reads, barcode collisions, positional effects, library coverage and the resulting abundance threshold. It opens beside the Map Barcodes settings with its full settings form, run controls, console and figures.

This module also provides the common infrastructure used by host screens: install_fold_strip(), FoldOpener, build_settings_screen() and install_window_hooks(). These helpers mount a complete module page, connect host signals and attach its masthead button without duplicating analytical implementations.

Classes

BarcodeSearchPanel

The live search: reads in, measured settings out, nothing written yet.

BarcodeSearchPlan

What one search is going to read, worked out from the settings form.

CategoryFold

One folded module, mounted on its host as extra settings categories.

CategoryFoldSet

Manage category folds and pipeline gates for one host screen.

FoldOpener

Open a folded module and reuse its screen between activations.

Functions

build_barcode_search_card(screen, **kwargs)

Build the live search and the card it sits in, unmounted.

build_registered_screen(→ PySide6.QtWidgets.QWidget)

The screen NAVIGATION builds for key, for a fold button to open.

build_settings_screen(→ PySide6.QtWidgets.QWidget)

Build a fully connected settings screen for module key.

connect_host(→ None)

Connect screen's host signals to host_window's slots.

describe_proposed_changes(proposal, current_settings)

Return the settings a proposal would change, old value beside new.

fold_description(→ Tuple[str, str, str])

Return the display name, description, and maturity stage for key.

folded_module_title(→ str)

Return the window title for folded module key.

hide_as_page(→ bool)

Take screen off host's page strip, keeping the screen.

host_pages(→ Optional[PySide6.QtWidgets.QTabWidget])

Return the host's page strip, creating it when first requested.

install_barcode_search(screen, **kwargs)

Attach the live barcode search to the Map Barcodes screen.

install_fold_strip(...)

Install buttons for folded modules on screen's masthead.

install_folds(...)

Put Map Barcodes' fold strip, its live barcode search and its spatial

install_folds_on(...)

Install the fold strip declared for screen's application key.

install_window_hooks(→ Optional[_StackWatcher])

Install fold strips as screens become current in window.

plan_barcode_search(settings)

Work out which reads and which reference tables a search should read.

restate_fold_button(→ None)

Apply the folded module's registered name, description, and stage.

show_as_page(→ Optional[PySide6.QtWidgets.QWidget])

Add screen to host's page strip and select it.

show_as_window(→ PySide6.QtWidgets.QWidget)

Show screen as its own window, owned by owner's window.

Module Contents

class spacr.qt.screens.map_barcodes.BarcodeSearchPanel(screen=None, parent: PySide6.QtWidgets.QWidget | None = None, *, threaded: bool = True, max_reads: int | None = None, chunk_reads: int | None = None, read_sample: int = READ_SAMPLE_READS)[source]

Bases: PySide6.QtWidgets.QWidget

The live search: reads in, measured settings out, nothing written yet.

Press the search button and the panel samples the reads of one sample from the folder the form names, measures every reference table against them in both orientations and in both mates, and refines what it shows after each chunk of reads. It ends by proposing the settings those measurements imply and waiting, because applying them is the user’s decision.

What is on screen, and why each part is there. The findings table carries the observed rate and the rate expected by coincidence in adjacent columns, with the ratio between them beside both, because a rate alone cannot be told from an accident and this panel exists to stop somebody acting on one. The text window shows reads with their matches coloured by barcode type, because a barcode landing in the same columns on row after row is the evidence that settles an argument a percentage cannot. The proposal shows the value the form holds beside the value the search suggests, so what Apply is about to do is legible before it does it.

It follows the form. Once a search has been asked for, changing any setting the search reads – the sequencing folder, a reference table, the barcode set or the anchor – starts it again after the form has been still for a moment, the way the Mask live preview follows its settings. Settings the search does not read never start one. Apply is the exception to everything live about this panel: the form changes only when it is pressed, so a value somebody typed is never replaced by a measurement that arrived while they were typing.

What it costs. Every file is read inside a submitted job, one chunk at a time, so the interface stays live throughout and a search can be abandoned at any point. Cancelling proposes nothing: an interrupted measurement is an honest partial report and a dishonest recommendation.

Parameters:
  • screen – the Map Barcodes screen whose settings form is read for the search and written by Apply. May be None, which leaves the panel usable as a display with nothing to read from and nothing to write to.

  • parent – parent widget; ownership only.

  • threaded – run the search on worker threads. False runs each step inline, in the same order and through the same handlers, so a test can drive a whole search synchronously.

  • max_reads – how many reads to sample from each file. The engine’s own default when omitted.

  • chunk_reads – how many reads each step of the search takes from each file. The engine’s own default when omitted.

  • read_sample – how many reads the text window shows.

Variables:
  • search_button – starts a search.

  • cancel_button – abandons the search in flight.

  • apply_button – writes the proposed settings into the form; disabled until a finished search has proposed something that differs from what the form already holds.

  • status – one line saying what the search is doing or has found.

  • findings – the table of measurements, one row per reference table per mate per orientation.

  • proposal_label – what Apply would change, and what the search learned that no setting can hold.

  • reads – the text window showing sampled reads with matches coloured.

Build the panel and arm it against one settings screen.

apply_proposal() → Tuple[str, ...][source]

Write the proposed settings into the form, on purpose.

Nothing calls this on its own. A search that finishes enables the button and stops there, because a panel that quietly replaced values somebody typed would be a worse failure than the one it exists to prevent.

Returns:

the keys that were written, in the order they were written.

Abandon the search in flight and propose nothing from it.

The chunk already on a worker thread is not interrupted; it finishes and its result is dropped on arrival, which is what cancelling means for work that holds no lock and cannot be asked to stop in the middle.

Returns:

True when there was a search to cancel.

changeEvent(event) → None[source]

Redraw the measurements when the theme underneath them changes.

The verdict colours are taken from the palette that was on screen when the row was drawn, so a row drawn before a theme change keeps the old theme’s ink until it is drawn again.

Parameters:

event – the Qt change event being delivered.

closeEvent(event) → None[source]

Stop the search rather than let it outlive the panel.

Parameters:

event – the Qt close event being delivered.

current_settings()[source]

Return the settings as the form holds them at this moment.

Returns:

the settings dictionary, empty when there is no form.

is_searching() → bool[source]

Return whether a search is running.

Returns:

True while the panel is working through the reads.

on_apply_clicked(_checked: bool = False) → None[source]

Write the proposed settings into the form.

Parameters:

_checked – Qt’s toggle state, unused.

on_cancel_clicked(_checked: bool = False) → None[source]

Abandon the search in flight.

Parameters:

_checked – Qt’s toggle state, unused.

on_search_clicked(_checked: bool = False) → None[source]

Start a search, or restart one that is already running.

Parameters:

_checked – Qt’s toggle state, unused.

proposal()[source]

Return the proposal a finished search produced.

Returns:

the proposal, or None when no search has finished.

proposed_changes()[source]

Return the settings Apply would write, old value beside new.

Returns:

a tuple of entries, each holding a setting’s key, the value the form holds and the value the search proposes.

report()[source]

Return the most recent report, complete or not.

Returns:

the report, or None when no search has produced one.

shutdown() → None[source]

Abandon any search in flight and leave no worker thread behind.

Safe to call directly when a screen is torn down without a close event, which is how a folded module usually goes away.

Begin a fresh search over the files the settings form names.

Returns rather than raises when there is nothing to search, because the reason is a sentence about the form and the panel shows it.

Returns:

True when a search was started.

class spacr.qt.screens.map_barcodes.BarcodeSearchPlan[source]

What one search is going to read, worked out from the settings form.

Planning is separated from searching because the two fail in different ways and the user needs to be told which one happened. A plan that cannot be made is a sentence about the form, such as a folder holding no sequencing files, and it is worth showing before any read is opened; a search that finds nothing is a measurement, and means something else entirely.

Variables:
  • fastq_files – the sequencing files to read, as a mapping from the label each carries in the report to its path. The labels are the mate names, so a report can say which mate carried which barcode.

  • reference_tables – one entry per reference table, holding the name it is reported under, the path it is read from, and the barcode role it fills.

  • anchor – the fixed vector sequence the mapping run locates its window by, searched alongside the tables so that offsets can be expressed relative to it. Empty when the settings name none.

  • sample – the name of the sample whose reads are being searched.

  • other_samples – how many further samples sit beside it in the same folder. Barcode layout is a property of the library rather than of one sample, so one sample settles it for all of them, but the count is shown so nobody thinks the others were missed.

  • problem – a sentence saying why this plan cannot be searched, or an empty string when it can.

class spacr.qt.screens.map_barcodes.CategoryFold(screen: PySide6.QtWidgets.QWidget, key: str, gates: Sequence[str] = ())[source]

One folded module, mounted on its host as extra settings categories.

The module’s settings form is built through the same path as its own screen. Categories containing settings absent from the host are then mounted on the host and remain hidden until the fold is enabled.

The fold switch exclusively controls the mounted categories’ visibility. They are omitted from _settings_sections because the maturity filter and settings search also change the visibility of sections in that list. Consequently, settings search does not include an inactive folded category.

Settings already provided by the host are not duplicated. Because collect() indexes controls by setting name, duplicate controls would create ambiguous values and could replace values entered on the host. Existing keys are therefore removed from the folded form, and categories with no remaining controls are not mounted.

Parameters:
  • screen – the host module’s AppScreen.

  • key – the folded module’s registry key.

  • gates – setting names the host’s pipeline reads to decide whether to do what this module does. They are forced True while the fold is on and False while it is off, so the run matches what the form is showing.

Record one settings category that folds in and out of the host.

Parameters:
  • screen – the host screen whose form the category joins.

  • key – the fold’s key.

  • gates – the settings whose values decide whether it applies.

collect() → Dict[str, object][source]

Return the settings contributed by this fold.

The host model collects both host and folded settings. This method selects only the keys mounted by the current fold.

mount() → bool[source]

Build the module’s categories and put them on the host, hidden.

Returns:

True when at least one category was mounted. False means the host has no settings form, or the folded module has nothing this host does not already show – both of which leave the host exactly as it was.

set_active(on: bool) → None[source]

Show or hide this module’s categories on the host’s form.

Parameters:

on – True to show this fold’s category sections, False to hide them; coerced with bool().

property active: bool[source]

Whether this module is currently part of the host’s run.

class spacr.qt.screens.map_barcodes.CategoryFoldSet(screen: PySide6.QtWidgets.QWidget, folds: Dict[str, Sequence[str]], implies: Dict[str, Sequence[str]] | None = None)[source]

Manage category folds and pipeline gates for one host screen.

A host declares its folded modules and their associated gates. This class mounts their settings, builds the masthead controls, and synchronizes gate values with the active folds.

Parameters:
  • screen – the host module’s AppScreen.

  • folds – key -> gate names, in the order the strip draws them.

  • implies – dependencies as key -> keys. Activating a dependent fold also activates its prerequisites. For example, the motility assay activates the timelapse branch required for tracking.

Build the set of category folds this screen offers.

Parameters:
  • screen – the host screen.

  • folds – each fold’s key mapped to the settings that gate it; the mapping’s order is the order the strip shows them in.

  • implies – folds that turning one on also turns on.

apply_gates() → Dict[str, bool][source]

Derive and store gate values from all active folds.

Values are recomputed collectively because multiple folds may share a gate. Gates are stored in the settings model defaults rather than in duplicate form controls; collect() includes defaults for keys without widgets.

build_strip(parent: PySide6.QtWidgets.QWidget | None = None) → spacr.qt.widgets.fold_strip.FoldStrip | None[source]

The masthead strip: one checkable button per mounted fold.

is_active(key: str) → bool[source]

Whether key’s categories are showing and its gate is on.

Parameters:

key – application key of the folded module; an unknown key returns False.

mount() → Tuple[str, ...][source]

Mount each fold’s categories on the host in a hidden state.

Returns:

keys of folds that contributed at least one setting.

set_active(key: str, on: bool) → None[source]

Set a fold’s state and update its dependency relationships.

Enabling a dependent fold enables its prerequisites. Disabling a prerequisite disables active dependents. Available strip buttons are updated through their normal signal path to keep display and form state synchronized.

Parameters:
  • key – application key of the folded module; an unknown key is ignored.

  • on – True to enable the fold and its prerequisites, False to disable it and any active fold that depends on it.

sync_from_settings(settings: Dict[str, object]) → Tuple[str, ...][source]

Synchronize fold states with values in a loaded settings mapping.

Fold gates have no dedicated widgets, so bulk settings application cannot update them through the form. This method reads the gate values directly and activates the corresponding folds.

Parameters:

settings – the dict that was applied.

Returns:

the keys switched on by it.

class spacr.qt.screens.map_barcodes.FoldOpener(screen: PySide6.QtWidgets.QWidget, key: str, build: Callable[[PySide6.QtWidgets.QWidget | None], PySide6.QtWidgets.QWidget])[source]

Open a folded module and reuse its screen between activations.

The opener is an object so the fold strip controls its lifetime through the button connection. The module appears as a page on its host when the host supports pages, or as a separate window otherwise. Its screen is constructed once and retained, preventing duplicate database handles or job runners and preserving loaded state when the user changes pages.

Parameters:
  • screen – the host screen the button sits on.

  • key – the folded module’s registry key.

  • build – called with the main window (or None) and returning the folded module’s screen.

Record how to build one folded module’s page, without building it.

Parameters:
  • screen – the host screen the page is opened on.

  • key – the folded module’s registry key.

  • build – called with a parent to build the page, on first open.

open(_checked: bool = False) → PySide6.QtWidgets.QWidget | None[source]

Show the folded module; raise it if it is already up.

spacr.qt.screens.map_barcodes.build_barcode_search_card(screen, **kwargs)[source]

Build the live search and the card it sits in, unmounted.

Returned unmounted, as the live preview’s card is, so that the caller decides where it goes and whether it starts visible.

Parameters:
  • screen – the Map Barcodes screen the search reads and writes.

  • kwargs – passed through to BarcodeSearchPanel.

Returns:

the panel and the card holding it.

spacr.qt.screens.map_barcodes.build_registered_screen(key: str, host_window: PySide6.QtWidgets.QWidget | None = None) → PySide6.QtWidgets.QWidget[source]

The screen NAVIGATION builds for key, for a fold button to open.

Folded modules that still hold a registry row are reached two ways – the button on their host’s masthead and the command palette – and the two must land on the same screen. Asking the window to build it is what guarantees that: _build_screen is the one place that knows which keys have a dedicated screen class, which are catalogue-driven AppScreen screens, and which come from a plugin.

The alternative was a table here mapping ten keys to ten classes, which is the same knowledge written a second time and free to drift from the first.

Falls back to build_settings_screen() when there is no window to ask – the headless and unit-test path, where a settings screen is what the catalogue-driven modules would have produced anyway.

Parameters:
  • key – the folded module’s registry key.

  • host_window – the main window, when there is one.

Returns:

the screen.

spacr.qt.screens.map_barcodes.build_settings_screen(key: str, host_window: PySide6.QtWidgets.QWidget | None = None) → PySide6.QtWidgets.QWidget[source]

Build a fully connected settings screen for module key.

The returned screen has the same host connections and declared pipeline ports as the standalone screen, including error explanation and cluster execution actions. Modules without declared ports omit the chaining controls.

Parameters:
  • key – the folded module’s registry key.

  • host_window – the main window, when there is one to connect to.

Returns:

the screen.

spacr.qt.screens.map_barcodes.connect_host(screen: PySide6.QtWidgets.QWidget, host_window: PySide6.QtWidgets.QWidget | None) → None[source]

Connect screen’s host signals to host_window’s slots.

Connections are derived from spacr.qt.chaining.HOST_CONNECTIONS, the same mapping used by MainWindow._build_screen. Folded and standalone screens therefore expose the same host-level actions.

Parameters:
  • screen – the screen whose host signals, named in HOST_CONNECTIONS, are connected.

  • host_window – the window providing the matching slots; None connects nothing.

spacr.qt.screens.map_barcodes.describe_proposed_changes(proposal, current_settings)[source]

Return the settings a proposal would change, old value beside new.

Showing what will change before it changes is the difference between a convenience and a trap. Somebody who typed a window length has to be able to see that pressing Apply replaces it, and with what, while there is still time to decide not to.

Parameters:
  • proposal – the proposal a finished search produced.

  • current_settings – the settings as the form holds them now.

Returns:

a tuple of entries, each holding the setting’s key, the value the form holds and the value the search proposes, for those settings whose value would actually change.

spacr.qt.screens.map_barcodes.fold_description(key: str) → Tuple[str, str, str][source]

Return the display name, description, and maturity stage for key.

Registry metadata is preferred while the module remains registered. FOLD_FALLBACK supplies the same presentation metadata after a folded module’s standalone registry entry is removed.

Parameters:

key – application key of the folded module, looked up in the app registry, then the declared catalogue, then the fold fallback records.

spacr.qt.screens.map_barcodes.folded_module_title(key: str) → str[source]

Return the window title for folded module key.

The application title table is preferred so renamed modules remain consistent throughout the interface. Fallback metadata is used after a module’s standalone registry entry is removed.

Parameters:

key – application key of the folded module; when no title or name is recorded it is title-cased with underscores as spaces.

spacr.qt.screens.map_barcodes.hide_as_page(screen: PySide6.QtWidgets.QWidget, host: PySide6.QtWidgets.QWidget | None) → bool[source]

Take screen off host’s page strip, keeping the screen.

The counterpart to show_as_page(), for a control that closes what it opened. It takes the same route the strip’s own close mark takes – _close_fold_page() – so a page closed by a switch and a page closed by its cross leave the module in the same state, loaded and off the strip rather than destroyed.

Parameters:
  • screen – the folded module’s widget.

  • host – the host module’s screen.

Returns:

True when a page was taken off the strip, False when the host has no strip or the widget is not on it.

spacr.qt.screens.map_barcodes.host_pages(screen: PySide6.QtWidgets.QWidget, title: str = '') → PySide6.QtWidgets.QTabWidget | None[source]

Return the host’s page strip, creating it when first requested.

The host body becomes a non-closable first page and retains its layout stretch. Pages opened for folded modules can be closed without destroying their underlying screens.

Parameters:
  • screen – the host module’s screen.

  • title – caption for the host page. If omitted, use screen._fold_page_title and then the registered application name.

Returns:

the page strip, or None when the host has no page body.

Attach the live barcode search to the Map Barcodes screen.

The search starts hidden, and a toggle on the screen shows it.

Installed rather than built into the screen for the reason every other panel on this screen is installed from outside: the screen is the generic settings screen, which knows nothing about sequencing and should not have to. Repeated calls return the panel that is already there, because the stack watcher reaches a screen again every time it becomes current.

Parameters:
  • screen – the screen to install into. Anything that is not the Map Barcodes screen is left alone.

  • kwargs – passed through to BarcodeSearchPanel, which is how a test asks for a smaller read sample or an unthreaded search.

Returns:

the panel, or None when the screen is not the Map Barcodes screen or has no runtime panel to mount into.

spacr.qt.screens.map_barcodes.install_fold_strip(screen: PySide6.QtWidgets.QWidget, host_key: str, folded: Sequence[str], builders: Dict[str, Callable[[PySide6.QtWidgets.QWidget | None], PySide6.QtWidgets.QWidget]]) → spacr.qt.widgets.fold_strip.FoldStrip | None[source]

Install buttons for folded modules on screen’s masthead.

Repeated calls return the existing strip. Construction failures are contained so the host screen remains usable without the optional strip.

Parameters:
  • screen – the host module’s screen.

  • host_key – registry key required on screen.

  • folded – the folded modules’ keys, in strip order.

  • builders – mapping from module key to a screen factory.

Returns:

the installed strip, or None when the screen is not the requested host, has no masthead, contains no eligible modules, or strip construction fails.

spacr.qt.screens.map_barcodes.install_folds(screen: PySide6.QtWidgets.QWidget) → spacr.qt.widgets.fold_strip.FoldStrip | None[source]

Put Map Barcodes’ fold strip, its live barcode search and its spatial transcriptomics panel on screen.

The search is installed here rather than through a seam of its own because this is the call every route to the Map Barcodes screen already passes through. A panel installed anywhere else would be present when the screen is reached one way and missing when it is reached another.

Parameters:

screen – the screen to install into.

Returns:

the fold strip, or None when this screen hosts no folds.

spacr.qt.screens.map_barcodes.install_folds_on(screen: PySide6.QtWidgets.QWidget) → spacr.qt.widgets.fold_strip.FoldStrip | None[source]

Install the fold strip declared for screen’s application key.

The owning module is selected through FOLD_HOST_MODULES. Screens without a fold declaration are left unchanged.

Parameters:

screen – the host screen; its app_key selects the owning module in FOLD_HOST_MODULES.

spacr.qt.screens.map_barcodes.install_window_hooks(window) → _StackWatcher | None[source]

Install fold strips as screens become current in window.

Repeated calls return the existing stack watcher rather than connecting an additional callback.

Parameters:

window – the main window.

Returns:

the watcher, or None when the window has no screen stack.

Work out which reads and which reference tables a search should read.

The sequencing folder of a real screen holds several samples, and one of them is enough. Which mate carries which barcode, which orientation the reference tables are stored in relative to the reads, and where in the read the barcodes sit are all properties of the library and the sequencing run rather than of a sample, so measuring them on the first sample settles them for every sample beside it. The others are counted rather than read, and the count is reported so that nobody has to wonder whether they were forgotten.

Nothing here opens a read. It lists a folder and checks that the reference files exist, so it is cheap enough to run whenever the search button is pressed and it can say what is missing before a single byte is decoded.

Parameters:

settings – the Map Barcodes settings as the form holds them.

Returns:

the plan. Its problem is a sentence when there is nothing to search and empty when the plan can be carried out.

spacr.qt.screens.map_barcodes.restate_fold_button(button, key: str) → None[source]

Apply the folded module’s registered name, description, and stage.

The operation has no visible effect while the registry still contains the module because the strip already uses the same metadata. After the registry row is removed, the fallback metadata preserves the module’s accessible label, tooltip, and maturity-stage styling.

Parameters:
  • button – the fold-strip button to update (tooltip, accessible name and stage); None does nothing.

  • key – application key of the folded module whose metadata is applied.

spacr.qt.screens.map_barcodes.show_as_page(screen: PySide6.QtWidgets.QWidget, host: PySide6.QtWidgets.QWidget | None, title: str) → PySide6.QtWidgets.QWidget | None[source]

Add screen to host’s page strip and select it.

Parameters:
  • screen – widget for the folded module.

  • host – the host module’s screen.

  • title – page caption, normally the folded module’s display name.

Returns:

screen, or None when the host cannot contain pages.

spacr.qt.screens.map_barcodes.show_as_window(screen: PySide6.QtWidgets.QWidget, owner: PySide6.QtWidgets.QWidget | None, title: str) → PySide6.QtWidgets.QWidget[source]

Show screen as its own window, owned by owner’s window.

This fallback is used when the host cannot display the screen as a page; see show_as_page(). The main window owns the resulting window so that Qt retains it for the application’s lifetime and closes it with the application.

Parameters:
  • screen – the screen to show; it is reparented as a top-level window, titled, resized and raised.

  • owner – a widget whose top-level window becomes the new window’s parent; None leaves it unparented.

  • title – the window title.

Nested helpers

_SpatialTranscriptomicsPanel.__init__.destroyed(*_args)

Stop the job runner when the panel object is destroyed.

Destruction may follow a reopen, after the initial token retired; this state stays usable without touching the destroyed widget.

spacr/qt/screens/map_barcodes.py:2671

_SpatialTranscriptomicsPanel._path_row.browse(_checked=False)

Fill this row from its folder, input-file or output-file picker.

spacr/qt/screens/map_barcodes.py:2711

_SpatialTranscriptomicsPanel._start_action.work()

Load, register and optionally assign in a worker thread.

spacr/qt/screens/map_barcodes.py:2982

_install_spatial_transcriptomics._show(on: bool) → None

Build the panel on its first showing, then show or hide the card.

spacr/qt/screens/map_barcodes.py:3173