spacr.qt.screens.convert¶
Format Converter — vendor microscopy files into Yokogawa TIFFs, with the mapping on screen before anything is written.
The screen exists because the conversion step is where a screen silently
goes wrong. Rename 384 wells’ worth of ND2 into
plate1_A01_T0001F001L01A01Z01C01.tif and the filenames stop carrying
any trace of where they came from; get the well assignment wrong and
nobody finds out until the hit list is being followed up, weeks later.
So this screen does two things spacr.io.convert_to_yokogawa() never
did: it shows the source → target table before writing, and it emits a
map file that turns every converted name back into the original one.
Layout:
┌───────────────────────────────────────────────────────────────────┐
│ /data/run1 [Choose source…] │
│ Layout [auto ▾] Z [keep every plane ▾] Plate names [plate1 ▾] │
│ /data/run1_yokogawa [Choose destination…] │
│ [Preview] [Convert] │
├───────────────────────────────────────────────────────────────────┤
│ source target plate well fld │
│ run1/wt/f01_C1.tif plate1_A01_T0001F001…C01.tif plate1 A01 1 │
│ run1/wt/f01_C2.tif plate1_A01_T0001F001…C02.tif plate1 A01 1 │
│ … │
├───────────────────────────────────────────────────────────────────┤
│ 20 file(s) would be written from 20 source(s). │
│ 1 plate(s), 1 well(s), 2 channel id(s). │
├───────────────────────────────────────────────────────────────────┤
│ Previewed 20 output file(s). Nothing has been written. │
└───────────────────────────────────────────────────────────────────┘
Design notes:
The preview is the product.
spacr.convert.scan()andspacr.convert.plan()write nothing at all;Convertis a separate press. A plan with a blocking error (two sources colliding on one output name) leavesConvertdisabled — the fix is upstream, in the folder layout, not in a “yes, overwrite” button.Everything heavy is in
spacr.convert, which imports neither torch nor cellpose, so this stays a view and the logic is testable headless.Off the GUI thread. Scanning a plate’s worth of ND2 headers takes seconds; converting takes minutes. Both go through
spacr.qt.bridge.make_thread(), and the completion handler is reached through a bound method (ConvertScreen._job_settled) rather than a closure, becausePipelineWorker.finishedis emitted in the worker thread and a closure connected to it would build widget children there. Tests passthreaded=False.No modal dialogs on any error path. A missing folder, an absent
nd2reader, a name collision — all of it lands in the inline status label and the summary pane. A QMessageBox would hang a headless run.
Classes¶
Pick a source tree, review the mapping, convert, read the summary. |
|
Read-only table model over a |
Module Contents¶
- class spacr.qt.screens.convert.ConvertScreen(parent=None, threaded: bool = True)[source]¶
Bases:
PySide6.QtWidgets.QWidgetPick a source tree, review the mapping, convert, read the summary.
- Parameters:
parent – parent widget.
threaded – when False every job runs inline on the calling thread. Tests use it so assertions are exact; the app leaves it True so a 40-minute conversion does not freeze the window.
Build the screen and arm its drop zone.
- Parameters:
parent – parent widget, or
None.threaded – preview and convert on a worker thread. Set
Falsein tests sopreviewfinishes before it returns.
- plan() spacr.convert.ConversionPlan | None[source]¶
The plan currently on screen, or None.
- preview() bool[source]¶
Scan the source and build the plan. Writes nothing.
- Returns:
True when the scan was started (or, unthreaded, completed) — False when the source is unusable, with the reason in the inline status label.
- preview_value(row: int, column: str) str[source]¶
One preview cell by column name (test/introspection helper).
- Parameters:
row – zero-based row of the preview table.
column – column name in the plan frame, e.g.
"target"; an unknown column or out-of-range row gives"".
- result() spacr.convert.ConversionResult | None[source]¶
The result of the last conversion, or None.
- run_convert() bool[source]¶
Convert the previewed plan into the destination folder.
- Returns:
True when the job was started, False when it was refused — with the reason inline.
- set_destination(path: str) None[source]¶
Set the destination folder.
- Parameters:
path – the output folder;
Noneor empty clears the field.
- set_layout_mode(value: str) None[source]¶
Choose the source layout (see
LAYOUT_CHOICES).- Parameters:
value –
"auto","plate_well","well"or"flat"; any other value raisesValueError.
- set_plate_naming(value: str) None[source]¶
Choose how output plates are named.
- Parameters:
value –
"index"(plate1,plate2, …) or"name"(keep the folder name); any other value raisesValueError.
- set_resume(enabled: bool) None[source]¶
Enable or disable field-checkpoint resume.
- Parameters:
enabled –
Trueto switch the Resume toggle on.
- set_source(path: str) None[source]¶
Point the screen at a source folder without opening a dialog.
- Parameters:
path – the source folder; when no destination is set yet, the destination becomes a sibling folder named after it with a
_yokogawasuffix.
- set_z_handling(value: str) None[source]¶
Choose how z planes are treated (see
Z_CHOICES).- Parameters:
value –
"keep"(every plane),"max"(max-project) or"first"(first plane only); any other value raisesValueError.
- class spacr.qt.screens.convert.PlanTableModel(parent=None)[source]¶
Bases:
PySide6.QtCore.QAbstractTableModelRead-only table model over a
ConversionPlan.to_frame()frame.A model rather than a QTableWidget because the preview for a full plate is tens of thousands of rows and populating that many QTableWidgetItems freezes the window for seconds.
- Parameters:
parent – parent widget.
Create an empty conversion-plan model.
- Parameters:
parent – parent object, or
None.
- columnCount(parent=QModelIndex()) int[source]¶
How many columns the plan shows.
- Parameters:
parent – unused; the model is flat.
- Returns:
the column count.
- data(index, role=Qt.DisplayRole)[source]¶
One cell of the plan.
- Parameters:
index – the cell.
role – the Qt display role.
- Returns:
the cell’s value for that role, or None.
- frame() pandas.DataFrame[source]¶
The frame currently displayed.
- headerData(section, orientation, role=Qt.DisplayRole)[source]¶
One header label.
- Parameters:
section – the row or column number.
orientation – which header.
role – the Qt display role.
- Returns:
the label, or None.
- rowCount(parent=QModelIndex()) int[source]¶
How many files the conversion plan covers.
- Parameters:
parent – unused; the model is flat.
- Returns:
the row count.
- set_frame(frame: pandas.DataFrame | None) None[source]¶
Replace the displayed frame, keeping only the known columns.
- Parameters:
frame – the plan frame from
ConversionPlan.to_frame();Noneor an empty frame shows an empty table with every preview column.
Nested helpers¶
- ConvertScreen.preview._job()¶
Scan the source and plan the conversion. Off the GUI thread.
spacr/qt/screens/convert.py:672
- ConvertScreen.run_convert._job()¶
Run the conversion. Off the GUI thread.
spacr/qt/screens/convert.py:776