spacr.object_settings_table

The repeated per-object settings, as one row per question.

78 of Mask’s 201 settings are the SAME 20 questions asked once per object type – cell_diameter, nucleus_diameter, pathogen_diameter, organelle_diameter and so on across twenty shapes. A table was chosen over tabs and over leaving the names flat.

WHY A TABLE IS NOT A COSMETIC CHOICE. The organelle count is arbitrary, up to spacr.organelle_types.MAX_ORGANELLES of 26. A flat vocabulary grows by TWENTY SETTINGS per organelle, so the module would be asking several hundred questions at the ceiling. In a table a new organelle is a new COLUMN and the number of questions does not move. The two instructions meet exactly here, and this is the shape that lets 326 land.

WHAT THIS MODULE IS AND IS NOT. It is the MODEL: it reads a flat settings dict into a table and writes a table back out, losslessly. It draws nothing. A GUI renders to_table() and calls from_table() on edit, and the headless path never has to know the table exists – the stored keys are unchanged, so no settings file, notebook or tutorial migrates.

THAT IS THE WHOLE POINT OF DOING IT THIS WAY. The obvious alternative – storing a nested {question: {object: value}} structure – would be a file-format change, and every saved settings file, every published tutorial, and the headless spacr-run path would have to move with it. The presentation is what was wrong, so only the presentation changes.

Functions

column_label(→ str)

What a column header reads.

families(→ Dict[str, List[str]])

{question: [objects that ask it]}, objects in display order.

from_table(→ Dict[str, object])

Flatten a table back to settings keys, over base if given.

questions(→ List[str])

The distinct questions in keys, in first-seen order.

to_table(→ Dict[str, Dict[str, object]])

Read a flat settings dict as {question: {object: value}}.

widen(→ Dict[str, Dict[str, object]])

Add a column for obj, copying like's answers where it has them.

Module Contents

spacr.object_settings_table.column_label(obj: str) → str[source]

What a column header reads.

organelleb is a storage spelling, not a thing a user recognises. The letter suffixes exist because object types are embedded in underscore-separated object keys and organelle2 is ambiguous with label 2 – an implementation constraint that has no business appearing in a column header.

Parameters:

obj – an object name from OBJECT_ORDER, e.g. "cell" or "organelleb". Organelle slots get their numbered label; any other name has underscores turned into spaces and is capitalised.

spacr.object_settings_table.families(keys: Iterable[str]) → Dict[str, List[str]][source]

{question: [objects that ask it]}, objects in display order.

Parameters:

keys – flat settings names such as "cell_min_area"; names that do not start with a known object followed by _ are skipped.

spacr.object_settings_table.from_table(table: Mapping[str, Mapping[str, object]], base: Mapping[str, object] | None = None) → Dict[str, object][source]

Flatten a table back to settings keys, over base if given.

LOSSLESS WITH to_table(), which is what makes the table safe to use as an editing surface: what the user sees is the settings file, rearranged and not transformed. A test round-trips every default settings dict.

Parameters:
  • table – {question: {object: value}}.

  • base – the settings the table came from. Keys the table does not cover are carried through unchanged, so a caller can edit the per-object half without holding the rest.

spacr.object_settings_table.questions(keys: Iterable[str]) → List[str][source]

The distinct questions in keys, in first-seen order.

ONE ENTRY PER SHAPE, however many objects ask it. cell_diameter and nucleus_diameter are one question, which is the entire saving.

Parameters:

keys – flat settings names such as "cell_diameter"; names that do not start with a known object followed by _ are skipped.

spacr.object_settings_table.to_table(settings: Mapping[str, object]) → Dict[str, Dict[str, object]][source]

Read a flat settings dict as {question: {object: value}}.

Only the keys that ARE per-object questions are taken. Everything else – src, verbose, n_jobs – is not a table row and is left where it is; a caller wanting the whole settings dict back uses from_table() with the original.

A question a given object does not ask is ABSENT from its row rather than present as None. cytoplasm has no channel, no diameter and no detection method because it is derived rather than found in a channel, and a blank cell says that where a None would read as “not set yet”.

Parameters:

settings – a flat settings dict, e.g. Mask’s settings; it is only read.

spacr.object_settings_table.widen(table: Mapping[str, Mapping[str, object]], obj: str, *, like: str | None = None) → Dict[str, Dict[str, object]][source]

Add a column for obj, copying like’s answers where it has them.

THE OPERATION 326 NEEDS, and the reason the table exists. Adding an organelle is one call that adds one column; in the flat vocabulary it is twenty new settings that every consumer, tooltip table and translation catalog has to learn.

Parameters:
  • obj – the object to add, e.g. 'organellec'.

  • like – an existing object whose answers to copy as the starting point. Defaults to the first organelle when obj is one, because a second mitochondrion should start where the first one is rather than at a global default nobody chose.

Nested helpers

_filter_text._num(value)

One bound as compact text; blank for an unset bound.

spacr/object_settings_table.py:178

_parse_filter_text._side(value)

One side of the range as a number; None when left blank.

spacr/object_settings_table.py:218