spacr.qt.widgets.feature_dictionary

The in-app feature dictionary: look a measurement up without leaving spaCR.

A finished run writes hundreds of columns per object with names like cell_channel_1_percentile_75. spacr.feature_dict has known what those mean for a while, but only as an export: you could write a markdown file describing a database, and that was the whole interface. So the moment a user actually needs the answer — reading a results table, staring at a regression coefficient, hovering a UMAP axis — they have to leave the app.

This module is the missing half:

FeatureDictionaryPanel

the searchable panel. Search by column name, by substring, or by idea (“intensity”, “texture”, “shape”, “distance”, “how big”, “blurry”), filter by object type and concept, and read the definition, the unit, which objects the feature exists for, which channel it applies to and which module computes it.

FeatureDictionaryDialog / open_feature_dictionary()

the same panel as a non-modal window, optionally opened straight onto one column.

register()

puts the panel in the app registry (Tools section) and its QSS in the theme, through the register_app / register_widget_qss seams — this module owns its own registration and edits neither app.py nor theme.py.

install_window_hooks()

the two reach-me-from-where-I-am routes: a Help ▸ Feature Dictionary… action, and a “What is this?” item on the context menu of any results table in the app.

The context-menu route is deliberately an application-level event filter rather than an edit to each table screen. There are eleven table-bearing screens and none of them claims a context menu today, so a filter reaches all of them — including the ones built lazily, long after this hook ran — and reaches any table added later for free. It stands aside for any widget that has claimed its own context menu (CustomContextMenu / ActionsContextMenu), so adopting one later silently takes precedence over this.

Classes

FeatureDictionaryDialog

FeatureDictionaryPanel in a non-modal window.

FeatureDictionaryPanel

Searchable dictionary of every measurement spaCR writes.

FeatureHelpFilter

Adds What is this? to the context menu of every results table.

Functions

close_feature_dictionary(→ None)

Close and forget the shared dialog. Used by tests and by teardown.

column_name_at(→ Optional[str])

The name of the column under pos in widget, or None.

install_context_menu_filter(→ Optional[FeatureHelpFilter])

Install the table context-menu filter on the QApplication. Idempotent.

install_help_action(→ Optional[PySide6.QtGui.QAction])

Add Feature Dictionary… to the window's Help menu.

install_window_hooks(→ None)

Wire the dictionary into a live main window.

make_screen(→ PySide6.QtWidgets.QWidget)

Screen factory for spacr.qt.app.register_app().

open_feature_dictionary(→ FeatureDictionaryDialog)

Show the dictionary, optionally opened onto column.

register(→ bool)

Register the app row and the QSS block. Idempotent.

remove_context_menu_filter(→ bool)

Remove the filter again. True if there was one.

set_menu_runner(→ None)

Replace the context-menu runner. None restores the default.

Module Contents

class spacr.qt.widgets.feature_dictionary.FeatureDictionaryDialog(parent: PySide6.QtWidgets.QWidget | None = None, column: str | None = None)[source]

Bases: spacr.qt.widgets.workflow_diagram.DiagramDialog

FeatureDictionaryPanel in a non-modal window.

Parameters:
  • parent – parent widget.

  • column – the measurement to open on. None opens on the whole dictionary rather than on a lookup nobody asked for.

Wrap the dictionary panel in a non-modal window.

Parameters:
  • parent – parent widget, or None.

  • column – the measurement to open on; None opens on the whole dictionary.

show_column(column: str) → None[source]

Forward to the panel.

Parameters:

column – the measurement column name to explain, passed to FeatureDictionaryPanel.show_column().

class spacr.qt.widgets.feature_dictionary.FeatureDictionaryPanel(parent: PySide6.QtWidgets.QWidget | None = None, column: str | None = None)[source]

Bases: PySide6.QtWidgets.QWidget

Searchable dictionary of every measurement spaCR writes.

Constructing it costs one spacr.feature_dict.search_features() call and touches no database, so it is cheap to embed and testable without an event loop.

Parameters:
  • parent – optional Qt parent.

  • column – optional column name to open on.

Build the feature dictionary panel.

Parameters:
  • parent – parent widget, or None.

  • column – a measurement to open pinned to; None opens on the whole dictionary.

current_doc() → spacr.feature_dict.FeatureDoc | None[source]

The feature the detail pane is showing, or None.

detail_text() → str[source]

The detail pane’s rendered text — what the user actually reads.

result_keys() → list[str][source]

Curated keys currently listed, best match first.

set_query(text: str) → None[source]

Type text into the search box and re-run the search.

Parameters:

text – the search text; None is read as empty. Any column pinned by show_column() is released.

show_column(column: str) → None[source]

Explain one concrete column name.

Searches for it (so the list shows the feature and its neighbours) and pins the detail pane to that column — its object type, its channel, its resolved unit — rather than to the generic feature.

A name the dictionary cannot explain is reported as unknown. It is never approximated to the nearest-looking entry.

Parameters:

column – the measurement column name, e.g. as it appears in a table header; stripped, and None or empty is reported as not in the dictionary.

class spacr.qt.widgets.feature_dictionary.FeatureHelpFilter[source]

Bases: PySide6.QtCore.QObject

Adds What is this? to the context menu of every results table.

Installed on the QApplication, so it covers the screens that do not exist yet when it is installed — every app screen in spaCR is built lazily on first navigation.

eventFilter(obj: PySide6.QtCore.QObject, event: PySide6.QtCore.QEvent) → bool[source]

Watch the widgets this filter is installed on.

THE EVENT TYPE IS READ FIRST, and the liveness checks follow it. This filter is on the QApplication, so both _still_alive calls used to run for every event in the process – 94,431 of them during one Regression open, and a profile counted the pair at 839,906 calls in one Mask open. Reading the type of an object whose C++ half has gone raises, which the except below already answers with the same False, so the order costs nothing and the checks now run only for a context menu.

Parameters:
  • obj – the object the event is for.

  • event – the event.

Returns:

True to stop the event going further.

spacr.qt.widgets.feature_dictionary.close_feature_dictionary() → None[source]

Close and forget the shared dialog. Used by tests and by teardown.

spacr.qt.widgets.feature_dictionary.column_name_at(widget: PySide6.QtCore.QObject, pos) → str | None[source]

The name of the column under pos in widget, or None.

Handles both halves of the gesture: a right-click on a header section and a right-click on a cell.

Parameters:
  • widget – the widget the right-click landed on: a horizontal QHeaderView, an item view, or an item view’s viewport. Anything else gives None.

  • pos – the click position as a QPoint in widget’s own coordinates.

spacr.qt.widgets.feature_dictionary.install_context_menu_filter(app: PySide6.QtWidgets.QApplication | None = None) → FeatureHelpFilter | None[source]

Install the table context-menu filter on the QApplication. Idempotent.

spacr.qt.widgets.feature_dictionary.install_help_action(window: PySide6.QtWidgets.QMainWindow) → PySide6.QtGui.QAction | None[source]

Add Feature Dictionary… to the window’s Help menu.

Returns the action, or None when there is no Help menu (a bare QMainWindow in a test) or one is already installed.

Parameters:

window – the main window whose Help menu gets the action; the action is inserted before the menu’s first separator, or appended when it has none.

spacr.qt.widgets.feature_dictionary.install_window_hooks(window: PySide6.QtWidgets.QMainWindow) → None[source]

Wire the dictionary into a live main window.

Called from spacr.qt.shortcuts.install(), which runs once from MainWindow.__init__ after the menu bar exists. Every failure is logged and swallowed: a missing help entry must not cost anyone a window.

Parameters:

window – the main window; its Help menu gets the dictionary action, and the process-wide context-menu filter is installed.

spacr.qt.widgets.feature_dictionary.make_screen(host=None) → PySide6.QtWidgets.QWidget[source]

Screen factory for spacr.qt.app.register_app().

spacr.qt.widgets.feature_dictionary.open_feature_dictionary(parent: PySide6.QtWidgets.QWidget | None = None, column: str | None = None) → FeatureDictionaryDialog[source]

Show the dictionary, optionally opened onto column.

Reuses a single window: looking up six columns in a row should leave one dictionary open, not six.

spacr.qt.widgets.feature_dictionary.register() → bool[source]

Register the app row and the QSS block. Idempotent.

Called from spacr.qt.run() before the main window is built, because the sidebar, the menu bar and Home all read the registry during MainWindow.__init__.

Returns:

True when the app row is in the registry afterwards.

spacr.qt.widgets.feature_dictionary.remove_context_menu_filter(app: PySide6.QtWidgets.QApplication | None = None) → bool[source]

Remove the filter again. True if there was one.

spacr.qt.widgets.feature_dictionary.set_menu_runner(runner) → None[source]

Replace the context-menu runner. None restores the default.

Parameters:

runner – a callable runner(menu, global_pos) that shows the QMenu at that global position, or None for the default, which calls menu.exec.

Nested helpers

_doc_html.field(name: str, value: object) → None

Add one field to the entry, skipping empty values.

spacr/qt/widgets/feature_dictionary.py:171