spacr.qt.widgets.class_editor

Edit named classes derived from annotation or metadata values.

Class definitions are stored as name -> {column, value} mappings. Values from several columns can be appended to one definition set, and an optional random-complement rule represents objects not claimed by another class. With the metadata basis, the editor offers plate, row, column, field, and well coordinates through the same interface.

Classes

ClassChip

Display one class name and its selected value as a removable pair.

ClassEditorWidget

Edits the classes setting.

Module Contents

class spacr.qt.widgets.class_editor.ClassChip(index: int, rule: spacr.classify_classes.ClassRule, palette, parent=None)[source]

Bases: PySide6.QtWidgets.QWidget

Display one class name and its selected value as a removable pair.

Random-complement classes omit the value pill because they do not select a specific value. Name and value colours come from the active theme’s chip_class and chip_value roles.

Parameters:
  • index – which rule this chip stands for. It is what removed carries, so it must be the rule’s position in the editor’s list rather than a running count of chips built.

  • rule – the rule to show. Read once, at construction: a chip does not follow a rule that changes underneath it.

  • palette – the active theme’s colour roles, as a mapping. Needs at least chip_class, chip_value and bg.

  • parent – parent widget.

Build one class bubble: its name, its value and a remove mark.

Parameters:
  • index – the rule’s position, carried so removal can name it.

  • rule – the class rule this chip stands for.

  • palette – the active theme colours.

  • parent – parent widget, or None.

class spacr.qt.widgets.class_editor.ClassEditorWidget(value: Any = None, parent=None, *, frame: pandas.DataFrame | None = None, basis: str = 'annotation')[source]

Bases: PySide6.QtWidgets.QWidget

Edits the classes setting.

Parameters:
  • value – the current setting – a dict, or the old list of names.

  • frame – the table whose columns and values are offered. Without one the widget still edits an existing dictionary but cannot populate new rows, and says so rather than showing an empty column picker as though the table had no columns.

  • parent – parent widget; ownership only.

  • basis – annotation to derive classes from an annotation column, or metadata to offer plate/row/column/field/well instead. It picks WHICH COLUMNS ARE ON OFFER, not how a rule is stored – both bases produce the same name -> {column, value} mapping – and it can be changed after construction with set_basis().

Build the class editor: a column picker, a two-field entry row and chips.

The column combo is editable because it is filled from a loaded table and there is not always one: with no frame the list came back empty, Add values was disabled, and a non-editable empty combo left no way at all to name a column – so no class could be added and the module could not be configured.

Parameters:
  • value – the classes to start with.

  • parent – parent widget, or None.

  • frame – the loaded table, used to offer columns and their values.

  • basis – which columns the picker offers – "annotation" or the metadata set.

add_random_complement() → None[source]

Add a rule taking a random sample of whatever the others leave.

AT MOST ONE. Two complements would each be defined as “the rest”, which is not a partition and cannot both be true.

add_typed_class() → None[source]

Add one class from the two fields. The chip appears; the fields clear.

A class with no name is refused rather than added blank – ClassRule raises on it anyway, and the message a user needs is which field is empty, not a traceback.

attach_sql_picker(db_path_getter, table: str = 'png_list')[source]

Add a database-backed column picker beside the column field.

The picker reads available columns from the current run database when no table has been loaded into the editor.

Parameters:
  • db_path_getter – callable giving the run folder or database path, called on each press so a path edited later is picked up.

  • table – database table whose columns should be offered.

Returns:

the button, or None if it could not be built.

get_value() → Dict[str, Dict[str, Any]][source]

The same as value(), under the name the settings form calls.

Returns:

one dict per rule.

populate_from_column() → None[source]

Fill the table from the chosen column’s distinct values.

Values already present are left alone, so adding a second column adds to the table rather than replacing what is in it – and re-adding the same column does not duplicate or reset the names already typed.

remove_at(index: int) → None[source]

Remove the class a chip’s close mark belongs to.

Parameters:

index – zero-based position of the class; out of range does nothing.

remove_selected() → None[source]

Drop the selected rules.

rules() → List[spacr.classify_classes.ClassRule][source]

The rules as objects rather than as dicts.

Returns:

the rules, in display order.

set_basis(basis: str) → None[source]

Metadata or annotation: it decides which columns are offered.

Under metadata these become plate / row / column / field / well, which is what replaces location_column plus the two control settings.

Parameters:

basis – the dataset basis, passed on as the dataset_mode setting: "metadata" offers the plate coordinates, "annotation" the table’s annotation columns. The column list is refilled.

set_frame(frame: pandas.DataFrame | None) → None[source]

Offer this table’s columns.

Parameters:

frame – the table whose column names are offered (filtered by the basis), or None when no table is loaded, which disables adding a class and shows a hint.

set_value(value: Any) → None[source]

Show value, whether it is the dict, the old list, or a string.

A settings CSV stores repr(value), so classes comes back as the TEXT "['nc', 'pc']". Without the string branch below, that matched neither the Mapping nor the list arm, fell through to an empty table, and reported SUCCESS: apply_settings_dict returned applied=1 while collect()['classes'] was {}. The class names were dropped without a word – and because {} is a Mapping, classify_classes.normalize_settings then skipped its own legacy-translation branch too, so nothing downstream recovered them. Every other list-shaped key survived that round trip; this was the one that decides what gets trained.

Parameters:

value – a mapping of class name to {column, value, random_complement}, a legacy list or tuple of class names, or the text of either; anything else leaves the table empty. Malformed entries are skipped.

value() → Dict[str, Dict[str, Any]][source]

The class rules, keyed by name.

Returns:

one dict per rule.