Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Without the jar: open `src/main/resources/org/cellmigrationlab/labconstrictor/qu

## What it does
* Pick an app and a tool. Numbers (range, unit), choices, checkboxes, text, files and folders become fields; parameters of a group sit under a heading, advanced ones in a collapsed section, optional ones without a default have a "set" box (unticked = the tool gets nothing), and `enabled_when` greys fields out.
* **Image inputs**: the image open in QuPath, any image of the open project, or a file. QuPath's image is exported losslessly as TIFF (the whole image, or the part chosen under **Image area**, see below). The pixel size of the chosen image or typed file (its header is read) fills the tool's pixel-size field (micrometres) until you edit the field (then your value is kept); pixels that are not square are said in the status line ("pixel size differs: Y .. µm, X .. µm - the tool takes one value and gets X").
* **Image inputs**: the image open in QuPath, any image of the open project, or a file. QuPath's image is exported losslessly as TIFF (the whole image, or the part chosen under **Image area**, see below). The pixel size of the chosen image or typed file fills the tool's pixel-size field (see **Pixel size** below).
* Results open in a window: values, tables (as a table: the first 100 000 rows, then "table 'name' (N rows, first M shown; the full table is in P)", the Napari wording; cells with commas, quotes and line breaks are read as CSV says), images (a preview, the path and an "Open in QuPath" button), alignment matrices, files, messages (also shown under the status line) and points.
* **Interaction hints** of the manifest: a `choices_from` parameter is a dropdown filled by another tool of the app (a text field when that tool cannot answer), `clear_after_run` parameters are reset after a successful run, a `Collapsed` group is a folded section, and an output with `Replace()` reuses the results window of the tool instead of opening a new one.
* **Channel selector**: an image input declared with `PickChannel()` gets a Channel chooser (the channel names of the chosen image, or of a file); the tool receives only that channel.
Expand All @@ -24,6 +24,15 @@ Without the jar: open `src/main/resources/org/cellmigrationlab/labconstrictor/qu
* Results are kept in `~/.labconstrictor/results/<time>_<6 hex>_<app>_<tool>` (names made safe), like the command line. The host never deletes a results folder or a run record (retention belongs to the Tools reference code, QuPath issue #14). Every run that reached the tool leaves a record `~/.labconstrictor/runs/<time>_<app>_<tool>/run.json` (none ever deleted by the host, the Tools format plus `"host": "qupath"`), and every log line is also appended to the shared `~/.labconstrictor/logs/labconstrictor.log` (Tools line format, `qupath:` prefix, 1 MB rotation with 5 backups), so `labconstrictor-tools logs` and `support-bundle` see QuPath runs.
* **Same rules as the other hosts** (the host-parity inventory of labconstrictor-tools): a form shows parameters in the Napari/Fiji order (a group gathered where it first appears; a Collapsed group is folded where it first appears; advanced last); `clear_after_run` resets every type of field; `enabled_when` follows text, number, choice, yes/no and "set" drivers (`""` counts as unset, numbers compare as numbers); a whole-number box holds ±(2^53 - 1) at most, declared limits or not (the largest whole number a double holds exactly, Tools `notebook.MAX_FORM_INTEGER`; a typed number beyond it stops at the limit), a decimal box without declared limits ±1e15; a choice of integers is sent as an integer; a missing input says `'L' is required`; NaN is refused with `'L' must be a finite number`; a folder input must be a folder; a worker that is idle for 10 minutes is closed; a worker ended after Cancel reads `cancelled (worker stopped)`; a worker that died is explained with the Tools sentences (a missing package first, then the exit code); a tool with a parameter type this host does not know is refused alone (`this tool cannot be shown: ...`); two tools with one label are listed as `label (id)` and the apps are sorted by name; `Copy as command` writes Python text the way `repr` does (a newline cannot break the snippet) and says `there is no clipboard to copy to` when there is none; message results show `- ` items as bullets; a result file that is missing, or a result type this version does not know, is said in one sentence.

## Pixel size (calibration)
A tool parameter linked to an image with `PixelSizeOf` (micrometres per pixel) is a text box with a button "Use the image's calibration". It follows the chosen image, the typed file and the image open in QuPath until you type a value (then your value stays, also when the image changes; press the button, or empty the box, to take the image's calibration again).

* **Unknown is a value.** Only an explicit length unit plus a number is a calibration; the number alone never is. A source without a unit (QuPath's `px`), with a unit that is not a length, with a damaged unit text (U+FFFD) or with pixels that are not square (X and Y differ by more than 0.1 %, relative to the larger) is unknown: the box is emptied (tooltip "not calibrated: 'image' has no pixel size"), a warning goes to the status line, and the value of another image never stays. Within 0.1 % the box takes the mean of X and Y.
* **Units** come from the unit catalog of the installed labconstrictor-tools (`conformance.json`, loaded with `python -m labconstrictor_tools.conformance --path` of a registered app; this script keeps no list): symbols (`um`, `nm`, the micro sign forms, the Angstrom signs, ...) are matched as exact text, words (`micron`, ` MILLIMETER `, ...) case-insensitively after trimming. When the catalog cannot be loaded every calibration is unknown and the status says so.
* **Where it comes from.** The image open in QuPath and project images: QuPath's `PixelCalibration` through the catalog. A file input: its own TIFF tags (OME `PhysicalSize` or ImageJ `unit=` first; the resolution tags only for `INCH` or `CENTIMETER` and not when they look like a 72 or 96 dpi default; `NONE` is unknown); other file formats through QuPath's reader. For a TIFF that QuPath itself read (a project image, the open image) and whose calibration was not entered in QuPath, the TIFF rules apply as well, because QuPath's reader turns a 72 dpi tag into 352.8 um per pixel; a calibration entered in QuPath ("Set pixel width/height") is explicit and is kept. A file wins over the open image when the image input is a file.
* **A run needs a value.** A linked parameter that is not `Optional` and is unset blocks the run: `'pixel_size' needs a value: 'image' has no pixel size. Enter it in um.` (the declared default is never a stand-in). An `Optional[float]` that is unset sends `null`.
* **The request** carries the number in the manifest parameter and the reserved input `_calibration` (per axis, x and y, in um, with `source` image, file or user and the raw number and unit text); tools never see it, the run record (`run.json`, `inputs`) keeps it. A request with a pixel-size value and no `_calibration` entry is a bug.

## Large images: the Image area and the size guard
Every image or labels input that uses the image open in QuPath ("Current image: ...") has an **Image area** chooser beside the image chooser:

Expand Down Expand Up @@ -91,6 +100,8 @@ The `gui_test_parity_*` bodies need the registered `interactions` app (its Pytho

`BODY=gui_test_parity_results_body.groovy tests/run_gui_test.sh` builds result tables of 150 000, 100 000, 2 001 and a few rows, with quoted commas, doubled quotes and multi-line cells, and checks the rows shown and the sentence (12 checks).

`BODY=gui_test_calibration_body.groovy tests/run_gui_test.sh` runs CAL-01..CAL-20 and CAL-T1..CAL-T9 of `conformance.json` through the form (a file input, project images and the image open in QuPath, one real worker run each for a required and an optional field) and checks the request and the `_calibration` input, not only the field; the images are written by `tests/calibration_fixtures.py` (tifffile) with the Python of the registered `frame` app.

`BODY=gui_test_parity_pixel_body.groovy LC_HOME=<scratch folder named lhome_pixel> tests/run_gui_test.sh` reads the pixel size of files (ImageJ unit, centimetre TIFF unit), keeps a typed value, says non-square pixels, reports an unreadable file (15 checks).

`BODY=gui_test_parity_form_body.groovy LC_HOME=<scratch folder named lhome_form> tests/run_gui_test.sh` registers a synthetic app and checks the form order, ClearAfterRun for every type, EnabledWhen for every driver, number limits (whole numbers up to 2^53 - 1, held and typed), integer choices, required and non-finite inputs (55 checks).
Expand Down
Loading
Loading