Add first-class support for the Hina microscope - #39
Merged
Conversation
Converts uploaded .nd2 files into composite RGB JPG overlays using arcadia-microscopy-tools. Per-channel intensities are percentile stretched (1st–99th) and blended via `overlay_channels`; Z-stacks collapse to a max-intensity projection, and T/P axes fall back to the first index. Run-level metadata (sizes, channels, dimensions) is parsed once per run via a best-effort `if run.metadata` gate after `ensure_run`, so the first file to arrive wins while every file still produces its own JPG. Also adds the `hina` subcommand to `data-hub-process`, an S3 trigger for `hina-microscope/*.nd2`, and unit tests covering metadata serialization, axis reduction, percentile rescale, and the single-shot metadata gate.
Introduces the Hina microscope as a first-class instrument variant in the web app, mirroring the existing plate reader / gel doc / qPCR pattern. - Add `hina_microscope` to `instrument_type` pg enum (migration 0008) and the edit-instrument dialog's type picker - New `HinaRunsTable` with Channels / Dimensions / Sizes columns surfacing the metadata the Lambda writes from parse_metadata.py (channel name + hex swatch, dimension flags, formatted size string) - New `HinaMicroscopeRunDetail` variant whose Report section is an image carousel (shadcn/ui + embla) over the processed JPGs produced per ND2 file - Shared helpers `getMetadataRecord` and `getMetadataObjectArray` to safely read the nested `sizes` dict and `channels` array-of-dicts
Hina microscope uploads can be 3-4 GB, which immediately exhausts the previous 512 MB /tmp and 1 GB RAM limits (decoded ND2 arrays are even larger than the compressed file). Raise EphemeralStorage to 10 GB, MemorySize to 10 GB, and Timeout to 900 s — all Lambda hard maxes. Also add a pre-cleanup call at the top of `lambda_handler`: the existing `finally: _cleanup_tmp()` doesn't run when the runtime SIGKILLs the process (OOM / timeout), so a warm container can start a new invocation with stale downloads still occupying /tmp.
Requesting an upload transitions a file to `upload_requested`, which only resolves if a watcher is online to push the file to S3. When no watcher is heartbeating, the UI now disables both per-row and bulk Upload buttons and shows a tooltip explaining why, preventing files from getting stuck in `upload_requested` with no agent to action them. The run detail page fetches the instrument (cached) alongside run files and threads an `isWatcherOnline` flag through `RunDetailProps` and each variant into `RunFilesSection` and `RunFilesTable`. Made-with: Cursor
Adds column filter dropdowns for the Hina microscope runs table driven by distinct metadata values queried from the database. Sizes filter matches on the raw JSONB object so different key orderings collapse to a single option, with a pre-formatted label shown in the UI. Also adapts near-white channel colors on the light theme: white swatches used `borderColor`/`color` directly and disappeared against the light surface. A new `getHinaChannelBadgeStyle` helper blends near-white colors with `--foreground` for the border/text and rings the dot with `--border` so the true channel color still reads while staying visible. Made-with: Cursor
Contributor
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds first-class support for the Hina microscope as a new instrument in Data Hub, end-to-end:
.nd2files into composite RGB JPG overlays usingarcadia-microscopy-tools, and extracts run-level metadata (channels, dimensions, sizes).HinaRunsTablewith filterable Channels / Dimensions / Sizes columns and aHinaMicroscopeRunDetailvariant whose report is an image carousel over the per-file JPGs.Changes
Lambda / processing (
201bef4,0fef702)lambda/src/data_hub_lambda/hina_microscope/package:image_processing.ND2Processor— loads ND2, reduces to 2D (Z → max projection, T/P → first index), percentile-stretches (1st–99th) each channel, composites viaoverlay_channelson a brightfield (or zero) background, exports JPG (quality 90).parse_metadata— serializessizes,channels(name / ex / em / hex), andDimensionFlagsto JSON.process_file— download raw → produce JPG → upload processed → create/update file records; run metadata is parsed once per run via anif not run.metadatagate (first file wins).hinaCLI subcommand added todata-hub-process.hina-microscope/*.nd2added toinfra/template.yaml.arcadia-microscopy-tools>=0.3.2added tolambda/pyproject.toml.Timeout: 900,MemorySize: 10240, per-functionEphemeralStorage: 10240._cleanup_tmp()call at invocation start so warm containers that were SIGKILL'd (OOM/timeout) don't start a new run with stale/tmpdownloads.Shared (
201bef4)Instrument.HINA_MICROSCOPE = "hina-microscope"+INSTRUMENT_ID_TO_NAME_MAPentry.Web app — runs table & detail (
a7b7754,b3f6f14)0008_chilly_princess_powerful.sql:ALTER TYPE instrument_type ADD VALUE 'hina_microscope', with the new value wired into the edit-instrument dialog picker and the schema.HinaRunsTablewith Channels / Dimensions / Sizes columns (channel name + hex swatch, dimension flags, formatted size string).HinaMicroscopeRunDetailvariant with aHinaReportSectionpowered by a new shadcnui/carousel(embla-carousel-react) over processed JPGs.getMetadataRecordandgetMetadataObjectArray(+ metadata badges) to safely read nestedsizes/channels.instrumentDetailSearchParams:hina_channel,hina_dimension,hina_size(raw JSONB equality on sizes so key orderings collapse to one option).instrument-runs.tsreturns distinct Hina metadata values for column filter dropdowns.--foregroundfor border/text and ring with--borderso the true channel color still reads.Driveby changes
c76bbc9): when no watcher is heartbeating, per-row and bulk Upload buttons are disabled with a tooltip explaining why, so files don't get stuck inupload_requestedwith no agent to action them. AddsWatcherStatusProvider,WatcherGatedUploadButton, and threadsisWatcherOnlinethroughRunDetailProps→ each variant →RunFilesSection/RunFilesTable. Applies to all instruments, not just Hina.865b437): small config update alongside the new migration.docs/lambda.mdupdated with the new instrument row, CLI subcommand, andarcadia-microscopy-toolsdependency.5dd58ba).Breaking changes
0008_chilly_princess_powerful.sqladdshina_microscopeto theinstrument_typepg enum. Must be applied before deploying the web app build that references it.Globalsblock now run at 10 GB memory / 900 s timeout — verify this is acceptable cost-wise for the other instrument handlers (or scope the overrides per-function if not).Testing
make check-allis green (format / lint / type checks)pytest lambda/tests/hina_microscope/passes (axis reduction, percentile rescale, metadata serialization, single-shot metadata gate)data-hub-process hina <file.nd2>CLI locally against a real ND2 and verify:parse_metadataoutput is JSON-serializable withsizes/channels/dimensionshina-microscope/<run>/<file>.nd2into the raw bucket:uploaded → processing → completedmetadatais populated only on the first file; subsequent files still produce JPGs but don't overwrite metadata/tmpis empty at startHinaRunsTablerenders Channels / Dimensions / Sizes with correct swatches and formatted sizeshina_channel,hina_dimension,hina_size) populate from distinct values and filter correctly; sizes with different key orderings collapse to one optionHinaMicroscopeRunDetailcarousel paginates through processed JPGs