Skip to content

feat: device property readout, and the display range as a histogram panel - #153

Merged
pskeshu merged 2 commits into
gently-project:developmentfrom
pskeshu:feat/device-property-readout
Sep 5, 2026
Merged

feat: device property readout, and the display range as a histogram panel#153
pskeshu merged 2 commits into
gently-project:developmentfrom
pskeshu:feat/device-property-readout

Conversation

@pskeshu

@pskeshu pskeshu commented Sep 5, 2026

Copy link
Copy Markdown
Collaborator

Two commits, both from working remotely on the scope.

e2fb62b — read-only device property dump

GET /api/devices/properties?device=<label>, or no device for the list.

Gently models four properties on the Coherent Scientific Remote — the per-line PowerSetpoint (%) — because those are the four it writes. The adapter exposes many more, and among them are the ones that say whether a laser is actually emitting: enable state, interlock, faults, power readback. None of it was reachable, so #106 has been argued from what the code commands rather than what the hardware reports.

The gap matters most right now: the operator is on this microscope remotely, and cannot verify the light sheet by eye. A camera only reports photons that reach it, which needs the specimen in focus — and the light-sheet view is precisely the surface that cannot be judged out of focus. The controller can report its own state regardless.

Each property returns its value, its allowed values where the adapter declares them, and a read_only flag. Allowed values turn an opaque string into a state machine; read_only marks a readback rather than a setting, which is the distinction #106 turns on.

No require_control — it commands nothing.

4ed9c2f — display range becomes a histogram panel

Two things were wrong with the old control, and the operator named both: it sat on top of the image, and the image is the main thing anyone interacts with.

Nothing sits on the pixels now. The controls moved out of the frame into a panel attached beneath it. The overlay had also been swallowing clicks in the bottom strip of the image — a cost already conceded as a ponytail: note, which was the tell it was in the wrong place. ImageView.attach(id, { controlsHost }) takes an external host. The zoom badge stays, because it reports the view rather than controlling it.

The artefact is the status. Modelled on ImageJ/Fiji's Brightness/Contrast, at the operator's suggestion. Its insight is that the histogram and the mapping belong in one picture: the transfer line is drawn across the data it applies to, so where black and white fall relative to where the signal sits is a single glance. B&C carries no numeric status readout, and neither does this.

  • Log counts — a microscopy histogram is dominated by background, and on a linear axis the part that matters is a flat line along zero.
  • Auto takes the 0.1st/99.9th percentiles, not min/max: a few hot pixels must not define white.
  • Computed client-side from the rendered frame via an offscreen canvas. No endpoint, no traffic, throttled to 400ms.

It is honest about what it shows: a histogram of the frame as displayed — 8-bit, already percentile-stretched per frame by the device layer. Not raw camera counts, and the panel says so. That is the argument for #149, not a limitation to hide: nuclei jammed against the top of the range become something an operator can see rather than something inferred from reading the encoder.


ruff, format and both mypy runs pass. JS suites 7 + 13 + 32.

pskeshu and others added 2 commits September 4, 2026 07:42
`GET /api/devices/properties?device=<label>`, or no device for the list.

Gently models four properties on the Coherent Scientific Remote — the per-line
`PowerSetpoint (%)` — because those are the four it writes. The adapter exposes
many more, and among them are the ones that answer whether a laser is actually
emitting: enable state, interlock, faults, power readback. None of that is
reachable today, so gently-project#106 has been argued from what the code commands rather
than from what the hardware reports.

That gap matters most when nobody can look at the instrument. The operator is
working on this microscope remotely: a camera can only report photons that
reach it, which needs the specimen in focus, and the light-sheet view is
exactly the surface that cannot be judged out of focus. The controller can
report its own state regardless of any of that.

Each property comes back with its value, its allowed values where the adapter
declares them, and a `read_only` flag. The allowed set turns an opaque string
into a state machine you can reason about, and read-only marks a readback
rather than a setting — which is precisely the distinction gently-project#106 turns on.

No `require_control`: it commands nothing.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Two things were wrong with the control this replaces, and the operator named
both: the contrast adjustment sat on top of the image, and the image is the
main thing anyone interacts with.

## Nothing sits on the pixels

The controls moved out of the frame into a panel attached beneath it. An
overlay hides data, and this one also swallowed clicks in the bottom strip of
the image — a cost I had already had to write off as a `ponytail:` note, which
was the tell that it was in the wrong place.

`ImageView.attach(id, { controlsHost })` takes an external host. The zoom badge
stays over the frame, because it reports the view rather than controlling it.

## The artefact is the status

Modelled on ImageJ/Fiji's Brightness/Contrast, which every microscopist already
knows. Its insight is that the histogram and the mapping belong in one picture:
the transfer line is drawn across the data it applies to, so where black and
white fall relative to where the signal actually sits is a single glance. B&C
carries no numeric status readout, and neither does this — the operator's own
suggestion, and it is right.

Counts are on a log axis. A microscopy histogram is dominated by background,
and on a linear axis the part that matters is a flat line along zero.

Auto takes the 0.1st and 99.9th percentiles, not min and max: a handful of hot
pixels must not define white.

The histogram is computed client-side by drawing the frame to an offscreen
canvas and binning it — no new endpoint, no new traffic. Throttled to 400ms,
because the frame rate is far above what an eye needs from a histogram and each
pass is a full readback of the decoded image.

## What it is honest about

It is a histogram of the frame AS DISPLAYED: 8-bit, already percentile-stretched
per frame by the device layer before JPEG encoding. Not raw camera counts. The
panel says so, and the label carries the explanation.

That is not a limitation to hide, it is the argument for gently-project#149. Anything the
server-side stretch clipped is already gone, and this panel is what will make
that visible — nuclei jammed against the top of the range are now something an
operator can see rather than something I inferred from reading the encoder.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@pskeshu
pskeshu merged commit caf1344 into gently-project:development Sep 5, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant