@jax-data-science/sci-image-visualizer 0.12.1 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2022/lib/contracts/channel-histogram-api.contract.mjs +19 -1
- package/esm2022/lib/contracts/display-types.mjs +7 -1
- package/esm2022/lib/contracts/image.contract.mjs +1 -1
- package/esm2022/lib/contracts/region-editor-api.contract.mjs +1 -1
- package/esm2022/lib/contracts/spatial-dataset.contract.mjs +1 -1
- package/esm2022/lib/contracts/visualizer.contract.mjs +1 -1
- package/esm2022/lib/geometry/reconstruct.mjs +11 -1
- package/esm2022/lib/implementations/napari-js/napari-image-2d-scene.mjs +17 -2
- package/esm2022/lib/implementations/napari-js/napari-spatial-2d-scene.mjs +88 -10
- package/esm2022/lib/implementations/napari-js/napari-spatial-3d-scene.mjs +62 -13
- package/esm2022/lib/implementations/napari-js/napari-spatial-encoding.mjs +21 -1
- package/esm2022/lib/implementations/napari-js/napari-spatial-scene.mjs +5 -1
- package/esm2022/lib/implementations/napari-js/napari-visualizer.service.mjs +9 -1
- package/esm2022/lib/implementations/napari-js/spatial-tiles/categorical-lookup.mjs +26 -3
- package/esm2022/lib/implementations/napari-js/spatial-tiles/cell-layers.mjs +3 -2
- package/esm2022/lib/implementations/napari-js/spatial-tiles/density-layer.mjs +20 -4
- package/esm2022/lib/implementations/napari-js/spatial-tiles/transcript-hover.mjs +4 -2
- package/esm2022/lib/implementations/napari-js/spatial-tiles/transcript-jobs.mjs +4 -2
- package/esm2022/lib/implementations/napari-js/spatial-tiles/transcript-layers.mjs +42 -15
- package/esm2022/lib/implementations/osd/openseadragon-visualizer.service.mjs +3 -1
- package/esm2022/lib/region-editor/region-editor.component.mjs +13 -1
- package/esm2022/lib/routing-visualizer.service.mjs +4 -1
- package/esm2022/lib/spatial/lod.mjs +6 -3
- package/esm2022/lib/spatial/spatial-controls.facade.mjs +78 -23
- package/esm2022/lib/spatial/spatial-gene-filter.mjs +138 -0
- package/esm2022/lib/spatial/spatial-selection.mjs +70 -1
- package/esm2022/lib/spatial/spatial-tile-merge.mjs +42 -1
- package/esm2022/lib/spatial-controls/spatial-cells-panel/spatial-cells-panel.component.mjs +3 -3
- package/esm2022/lib/spatial-controls/spatial-controls.component.mjs +54 -11
- package/esm2022/lib/spatial-controls/spatial-gene-style/spatial-gene-style.component.mjs +66 -0
- package/esm2022/lib/spatial-controls/spatial-gene-tree/spatial-gene-tree.component.mjs +106 -26
- package/esm2022/lib/spatial-controls/spatial-groups-panel/spatial-groups-panel.component.mjs +3 -3
- package/esm2022/lib/spatial-controls/spatial-key/spatial-key.component.mjs +3 -3
- package/esm2022/lib/spatial-controls/spatial-marker-genes-form/spatial-marker-genes-form.component.mjs +3 -3
- package/esm2022/lib/spatial-controls/spatial-observations-panel/spatial-observations-panel.component.mjs +110 -8
- package/esm2022/lib/spatial-controls/spatial-transcripts-panel/spatial-transcripts-panel.component.mjs +41 -9
- package/esm2022/lib/store/region-selection.mjs +21 -4
- package/esm2022/lib/store/region-store.service.mjs +22 -3
- package/esm2022/lib/store/spatial-selection.service.mjs +13 -1
- package/esm2022/lib/store/visualizer-store.service.mjs +50 -1
- package/esm2022/lib/toolbar/toolbar-help-dialog/toolbar-help-dialog.component.mjs +3 -3
- package/fesm2022/{jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-DnPlIP2F.mjs → jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-DvFp1jNH.mjs} +1777 -793
- package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-DvFp1jNH.mjs.map +1 -0
- package/fesm2022/{jax-data-science-sci-image-visualizer-onnx-sam-session-Bs987_-E.mjs → jax-data-science-sci-image-visualizer-onnx-sam-session-D7lSUAM1.mjs} +2 -2
- package/fesm2022/{jax-data-science-sci-image-visualizer-onnx-sam-session-Bs987_-E.mjs.map → jax-data-science-sci-image-visualizer-onnx-sam-session-D7lSUAM1.mjs.map} +1 -1
- package/fesm2022/jax-data-science-sci-image-visualizer.mjs +2 -2
- package/lib/contracts/channel-histogram-api.contract.d.ts +14 -0
- package/lib/contracts/display-types.d.ts +27 -0
- package/lib/contracts/image.contract.d.ts +2 -0
- package/lib/contracts/region-editor-api.contract.d.ts +3 -0
- package/lib/contracts/spatial-dataset.contract.d.ts +7 -0
- package/lib/contracts/visualizer.contract.d.ts +28 -2
- package/lib/geometry/reconstruct.d.ts +6 -0
- package/lib/implementations/napari-js/napari-image-2d-scene.d.ts +7 -0
- package/lib/implementations/napari-js/napari-spatial-2d-scene.d.ts +13 -2
- package/lib/implementations/napari-js/napari-spatial-encoding.d.ts +5 -0
- package/lib/implementations/napari-js/napari-spatial-scene.d.ts +4 -0
- package/lib/implementations/napari-js/napari-visualizer.service.d.ts +5 -0
- package/lib/implementations/napari-js/spatial-tiles/categorical-lookup.d.ts +6 -1
- package/lib/implementations/napari-js/spatial-tiles/transcript-hover.d.ts +4 -0
- package/lib/implementations/napari-js/spatial-tiles/transcript-layers.d.ts +3 -1
- package/lib/routing-visualizer.service.d.ts +1 -0
- package/lib/spatial/lod.d.ts +3 -1
- package/lib/spatial/spatial-controls.facade.d.ts +19 -2
- package/lib/spatial/spatial-gene-filter.d.ts +44 -0
- package/lib/spatial/spatial-selection.d.ts +16 -1
- package/lib/spatial/spatial-tile-merge.d.ts +17 -0
- package/lib/spatial-controls/spatial-controls.component.d.ts +14 -3
- package/lib/spatial-controls/spatial-gene-style/spatial-gene-style.component.d.ts +30 -0
- package/lib/spatial-controls/spatial-gene-tree/spatial-gene-tree.component.d.ts +39 -7
- package/lib/spatial-controls/spatial-observations-panel/spatial-observations-panel.component.d.ts +33 -1
- package/lib/spatial-controls/spatial-transcripts-panel/spatial-transcripts-panel.component.d.ts +13 -1
- package/lib/store/region-selection.d.ts +14 -3
- package/lib/store/region-store.service.d.ts +14 -1
- package/lib/store/spatial-selection.service.d.ts +8 -0
- package/lib/store/visualizer-store.service.d.ts +13 -0
- package/package.json +1 -1
- package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-DnPlIP2F.mjs.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { LruCache } from 'napari-js';
|
|
2
2
|
import * as ort from 'onnxruntime-web';
|
|
3
|
-
import { g as getOrtWasmBase, f as fetchModel, r as runEncoder, a as runDecoder } from './jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-
|
|
3
|
+
import { g as getOrtWasmBase, f as fetchModel, r as runEncoder, a as runDecoder } from './jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-DvFp1jNH.mjs';
|
|
4
4
|
import '@angular/core';
|
|
5
5
|
import '@angular/common/http';
|
|
6
6
|
import 'rxjs';
|
|
@@ -237,4 +237,4 @@ class OnnxSamSession {
|
|
|
237
237
|
}
|
|
238
238
|
|
|
239
239
|
export { OnnxSamSession };
|
|
240
|
-
//# sourceMappingURL=jax-data-science-sci-image-visualizer-onnx-sam-session-
|
|
240
|
+
//# sourceMappingURL=jax-data-science-sci-image-visualizer-onnx-sam-session-D7lSUAM1.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jax-data-science-sci-image-visualizer-onnx-sam-session-Bs987_-E.mjs","sources":["../../src/lib/toolbar/segmentation/pending-calls.ts","../../src/lib/toolbar/segmentation/onnx-sam-session.ts"],"sourcesContent":["/** A reply from the SAM worker: progress for, or the result of, call `id`. */\nexport interface WorkerReply {\n id: number;\n type: string;\n /** Present on `type: 'progress'` replies. */\n fraction?: number;\n /** Present on `type: 'error'` replies. */\n error?: string;\n [key: string]: unknown;\n}\n\ninterface Pending {\n resolve: (reply: WorkerReply) => void;\n reject: (err: Error) => void;\n onProgress?: (fraction: number) => void;\n}\n\n/**\n * Request/response bookkeeping for a worker RPC: each call gets an id and a\n * promise that its reply settles. Every exit path (dispose, a worker crash)\n * must {@link rejectAll}, or awaiting callers never reach their `finally` and a\n * tool's busy flag sticks forever (RT-8).\n */\nexport class PendingCalls {\n private seq = 0;\n private readonly pending = new Map<number, Pending>();\n\n /** Calls still awaiting a reply. */\n get size(): number {\n return this.pending.size;\n }\n\n /** Register a new call; post the message with the returned id. */\n open(onProgress?: (fraction: number) => void): { id: number; promise: Promise<WorkerReply> } {\n const id = ++this.seq;\n const promise = new Promise<WorkerReply>((resolve, reject) => {\n this.pending.set(id, { resolve, reject, onProgress });\n });\n return { id, promise };\n }\n\n /** Route a worker reply to its call: progress, error or result. */\n handle(reply: WorkerReply): void {\n const p = this.pending.get(reply.id);\n if (!p) return;\n if (reply.type === 'progress') {\n p.onProgress?.(reply.fraction ?? 0);\n return;\n }\n this.pending.delete(reply.id);\n if (reply.type === 'error') p.reject(new Error(reply.error ?? 'SAM worker error.'));\n else p.resolve(reply);\n }\n\n /** Reject every pending call with `err` and forget them. */\n rejectAll(err: Error): void {\n const calls = Array.from(this.pending.values());\n this.pending.clear();\n for (const p of calls) p.reject(err);\n }\n}\n","import { LruCache } from 'napari-js';\nimport * as ort from 'onnxruntime-web';\n\nimport { ISamSession, SamEmbedding, SamMaskResult, SamModelDef, SamPrompt } from '../../contracts/sam.contract';\nimport { fetchModel, runEncoder, runDecoder, type CoreEmbedding } from './sam-onnx-core';\nimport { getOrtWasmBase } from './ort-runtime-config';\nimport { PendingCalls, WorkerReply } from './pending-calls';\n\n/**\n * onnxruntime-web implementation of {@link ISamSession} (jit-ui#90), with two\n * execution modes chosen per model:\n *\n * - **in-process** (main thread) — for small WASM models flagged `inProcess`\n * (e.g. micro-sam ViT-T). Fast load + inference with no Web Worker spawn /\n * second ORT runtime / message round-trips; the brief encode runs on the main\n * thread (fine for a tiny model).\n * - **worker** — for WebGPU models (e.g. ViT-B, patho-sam fp16) whose heavy\n * encode would otherwise freeze the tab. Runs in {@link ./onnx-sam.worker} so\n * the UI stays responsive (the spinner animates).\n *\n * Both modes share their inference math via {@link ./sam-onnx-core}. Lazy-imported\n * by the SAM tools so onnxruntime-web / the worker never load in unit tests or\n * the initial bundle.\n */\nexport class OnnxSamSession implements ISamSession {\n private mode: 'inproc' | 'worker' | null = null;\n private loaded = false;\n private inputSize = 1024;\n\n // ── worker mode ──\n private worker: Worker | null = null;\n private readonly calls = new PendingCalls();\n\n // ── in-process mode ──\n private encoder: ort.InferenceSession | null = null;\n private decoder: ort.InferenceSession | null = null;\n private nextToken = 1;\n /** The few most recently used embeddings, by token (one per recently viewed image). */\n private readonly embeddings = new LruCache<CoreEmbedding, number>(3);\n\n async loadModel(model: SamModelDef, onProgress?: (fraction: number) => void): Promise<void> {\n if (!model.encoderUrl || !model.decoderUrl) {\n throw new Error(`SAM model \"${model.id}\" has no ONNX URLs configured.`);\n }\n this.inputSize = model.inputSize;\n const hasGpu = typeof navigator !== 'undefined' && 'gpu' in navigator;\n const eps: string[] = model.encoderProviders ?? (hasGpu ? ['webgpu', 'wasm'] : ['wasm']);\n const usesWebGpu = eps.includes('webgpu');\n // WebGPU must run in the worker (else it freezes the main thread); small\n // WASM models opt into the faster in-process path via `inProcess`.\n this.mode = !usesWebGpu && model.inProcess ? 'inproc' : 'worker';\n\n if (this.mode === 'inproc') {\n ort.env.wasm.wasmPaths = getOrtWasmBase();\n const encBuf = await fetchModel(model.encoderUrl, onProgress, model.revision);\n const decBuf = await fetchModel(model.decoderUrl, undefined, model.revision);\n this.encoder = await ort.InferenceSession.create(encBuf, { executionProviders: eps });\n this.decoder = await ort.InferenceSession.create(decBuf, { executionProviders: ['wasm'] });\n } else {\n await this.call(\n {\n type: 'load',\n encoderUrl: model.encoderUrl,\n decoderUrl: model.decoderUrl,\n revision: model.revision,\n wasmPaths: getOrtWasmBase(),\n inputSize: model.inputSize,\n encoderProviders: model.encoderProviders,\n },\n [],\n onProgress,\n );\n }\n this.loaded = true;\n }\n\n isLoaded(): boolean {\n return this.loaded;\n }\n\n async embed(image: { data: Uint8ClampedArray; width: number; height: number }): Promise<SamEmbedding> {\n if (this.mode === 'inproc') {\n const e = await runEncoder(this.encoder!, image.data, image.width, image.height, this.inputSize);\n const token = this.nextToken++;\n this.embeddings.set(token, e);\n return {\n data: new Float32Array(0),\n dims: e.dims,\n scale: e.scale,\n imageWidth: e.imageWidth,\n imageHeight: e.imageHeight,\n token,\n };\n }\n // worker: transfer the RGBA buffer (callers pass a fresh frame buffer).\n const buffer = image.data.buffer;\n const res = await this.call({ type: 'embed', width: image.width, height: image.height, buffer }, [buffer]);\n return {\n data: new Float32Array(0),\n dims: res['dims'] as number[],\n scale: res['scale'] as number,\n imageWidth: res['imageWidth'] as number,\n imageHeight: res['imageHeight'] as number,\n token: res['token'] as number,\n };\n }\n\n async decode(embedding: SamEmbedding, prompt: SamPrompt): Promise<SamMaskResult> {\n if (this.mode === 'inproc') {\n const e = this.embeddings.get(embedding.token as number);\n if (!e) throw new Error('SAM embedding expired; re-encode the image.');\n return runDecoder(this.decoder!, e, prompt);\n }\n const res = await this.call({ type: 'decode', token: embedding.token, prompt });\n return {\n mask: new Uint8Array(res['buffer'] as ArrayBuffer),\n width: res['width'] as number,\n height: res['height'] as number,\n iou: res['iou'] as number,\n };\n }\n\n /** Release the worker / ORT sessions. Calls still in flight reject (RT-8), so\n * their callers' `finally` blocks run (e.g. a tool's busy flag clears). */\n dispose(): void {\n this.dropWorker(new Error('SAM session disposed'));\n this.encoder?.release?.();\n this.decoder?.release?.();\n this.encoder = this.decoder = null;\n this.embeddings.clear();\n this.loaded = false;\n this.mode = null;\n }\n\n // ── worker plumbing ──────────────────────────────────────────────────────\n private ensureWorker(): Worker {\n if (this.worker) return this.worker;\n const worker = new Worker(new URL('./onnx-sam.worker', import.meta.url), { type: 'module' });\n worker.onmessage = (ev: MessageEvent<WorkerReply>) => this.calls.handle(ev.data);\n worker.onerror = (ev: ErrorEvent) => {\n // A crashed worker can't serve the loaded model any more: drop it, so the\n // next run reloads instead of posting to a dead worker.\n this.dropWorker(new Error(ev.message || 'SAM worker crashed.'));\n this.loaded = false;\n this.mode = null;\n };\n this.worker = worker;\n return worker;\n }\n\n /** Terminate the worker (if any) and reject every call still waiting on it. */\n private dropWorker(err: Error): void {\n this.worker?.terminate();\n this.worker = null;\n this.calls.rejectAll(err);\n }\n\n private call(\n msg: Record<string, unknown>,\n transfer: Transferable[] = [],\n onProgress?: (f: number) => void,\n ): Promise<WorkerReply> {\n const worker = this.ensureWorker();\n const { id, promise } = this.calls.open(onProgress);\n worker.postMessage({ ...msg, id }, transfer);\n return promise;\n }\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"jax-data-science-sci-image-visualizer-onnx-sam-session-D7lSUAM1.mjs","sources":["../../src/lib/toolbar/segmentation/pending-calls.ts","../../src/lib/toolbar/segmentation/onnx-sam-session.ts"],"sourcesContent":["/** A reply from the SAM worker: progress for, or the result of, call `id`. */\nexport interface WorkerReply {\n id: number;\n type: string;\n /** Present on `type: 'progress'` replies. */\n fraction?: number;\n /** Present on `type: 'error'` replies. */\n error?: string;\n [key: string]: unknown;\n}\n\ninterface Pending {\n resolve: (reply: WorkerReply) => void;\n reject: (err: Error) => void;\n onProgress?: (fraction: number) => void;\n}\n\n/**\n * Request/response bookkeeping for a worker RPC: each call gets an id and a\n * promise that its reply settles. Every exit path (dispose, a worker crash)\n * must {@link rejectAll}, or awaiting callers never reach their `finally` and a\n * tool's busy flag sticks forever (RT-8).\n */\nexport class PendingCalls {\n private seq = 0;\n private readonly pending = new Map<number, Pending>();\n\n /** Calls still awaiting a reply. */\n get size(): number {\n return this.pending.size;\n }\n\n /** Register a new call; post the message with the returned id. */\n open(onProgress?: (fraction: number) => void): { id: number; promise: Promise<WorkerReply> } {\n const id = ++this.seq;\n const promise = new Promise<WorkerReply>((resolve, reject) => {\n this.pending.set(id, { resolve, reject, onProgress });\n });\n return { id, promise };\n }\n\n /** Route a worker reply to its call: progress, error or result. */\n handle(reply: WorkerReply): void {\n const p = this.pending.get(reply.id);\n if (!p) return;\n if (reply.type === 'progress') {\n p.onProgress?.(reply.fraction ?? 0);\n return;\n }\n this.pending.delete(reply.id);\n if (reply.type === 'error') p.reject(new Error(reply.error ?? 'SAM worker error.'));\n else p.resolve(reply);\n }\n\n /** Reject every pending call with `err` and forget them. */\n rejectAll(err: Error): void {\n const calls = Array.from(this.pending.values());\n this.pending.clear();\n for (const p of calls) p.reject(err);\n }\n}\n","import { LruCache } from 'napari-js';\nimport * as ort from 'onnxruntime-web';\n\nimport { ISamSession, SamEmbedding, SamMaskResult, SamModelDef, SamPrompt } from '../../contracts/sam.contract';\nimport { fetchModel, runEncoder, runDecoder, type CoreEmbedding } from './sam-onnx-core';\nimport { getOrtWasmBase } from './ort-runtime-config';\nimport { PendingCalls, WorkerReply } from './pending-calls';\n\n/**\n * onnxruntime-web implementation of {@link ISamSession} (jit-ui#90), with two\n * execution modes chosen per model:\n *\n * - **in-process** (main thread) — for small WASM models flagged `inProcess`\n * (e.g. micro-sam ViT-T). Fast load + inference with no Web Worker spawn /\n * second ORT runtime / message round-trips; the brief encode runs on the main\n * thread (fine for a tiny model).\n * - **worker** — for WebGPU models (e.g. ViT-B, patho-sam fp16) whose heavy\n * encode would otherwise freeze the tab. Runs in {@link ./onnx-sam.worker} so\n * the UI stays responsive (the spinner animates).\n *\n * Both modes share their inference math via {@link ./sam-onnx-core}. Lazy-imported\n * by the SAM tools so onnxruntime-web / the worker never load in unit tests or\n * the initial bundle.\n */\nexport class OnnxSamSession implements ISamSession {\n private mode: 'inproc' | 'worker' | null = null;\n private loaded = false;\n private inputSize = 1024;\n\n // ── worker mode ──\n private worker: Worker | null = null;\n private readonly calls = new PendingCalls();\n\n // ── in-process mode ──\n private encoder: ort.InferenceSession | null = null;\n private decoder: ort.InferenceSession | null = null;\n private nextToken = 1;\n /** The few most recently used embeddings, by token (one per recently viewed image). */\n private readonly embeddings = new LruCache<CoreEmbedding, number>(3);\n\n async loadModel(model: SamModelDef, onProgress?: (fraction: number) => void): Promise<void> {\n if (!model.encoderUrl || !model.decoderUrl) {\n throw new Error(`SAM model \"${model.id}\" has no ONNX URLs configured.`);\n }\n this.inputSize = model.inputSize;\n const hasGpu = typeof navigator !== 'undefined' && 'gpu' in navigator;\n const eps: string[] = model.encoderProviders ?? (hasGpu ? ['webgpu', 'wasm'] : ['wasm']);\n const usesWebGpu = eps.includes('webgpu');\n // WebGPU must run in the worker (else it freezes the main thread); small\n // WASM models opt into the faster in-process path via `inProcess`.\n this.mode = !usesWebGpu && model.inProcess ? 'inproc' : 'worker';\n\n if (this.mode === 'inproc') {\n ort.env.wasm.wasmPaths = getOrtWasmBase();\n const encBuf = await fetchModel(model.encoderUrl, onProgress, model.revision);\n const decBuf = await fetchModel(model.decoderUrl, undefined, model.revision);\n this.encoder = await ort.InferenceSession.create(encBuf, { executionProviders: eps });\n this.decoder = await ort.InferenceSession.create(decBuf, { executionProviders: ['wasm'] });\n } else {\n await this.call(\n {\n type: 'load',\n encoderUrl: model.encoderUrl,\n decoderUrl: model.decoderUrl,\n revision: model.revision,\n wasmPaths: getOrtWasmBase(),\n inputSize: model.inputSize,\n encoderProviders: model.encoderProviders,\n },\n [],\n onProgress,\n );\n }\n this.loaded = true;\n }\n\n isLoaded(): boolean {\n return this.loaded;\n }\n\n async embed(image: { data: Uint8ClampedArray; width: number; height: number }): Promise<SamEmbedding> {\n if (this.mode === 'inproc') {\n const e = await runEncoder(this.encoder!, image.data, image.width, image.height, this.inputSize);\n const token = this.nextToken++;\n this.embeddings.set(token, e);\n return {\n data: new Float32Array(0),\n dims: e.dims,\n scale: e.scale,\n imageWidth: e.imageWidth,\n imageHeight: e.imageHeight,\n token,\n };\n }\n // worker: transfer the RGBA buffer (callers pass a fresh frame buffer).\n const buffer = image.data.buffer;\n const res = await this.call({ type: 'embed', width: image.width, height: image.height, buffer }, [buffer]);\n return {\n data: new Float32Array(0),\n dims: res['dims'] as number[],\n scale: res['scale'] as number,\n imageWidth: res['imageWidth'] as number,\n imageHeight: res['imageHeight'] as number,\n token: res['token'] as number,\n };\n }\n\n async decode(embedding: SamEmbedding, prompt: SamPrompt): Promise<SamMaskResult> {\n if (this.mode === 'inproc') {\n const e = this.embeddings.get(embedding.token as number);\n if (!e) throw new Error('SAM embedding expired; re-encode the image.');\n return runDecoder(this.decoder!, e, prompt);\n }\n const res = await this.call({ type: 'decode', token: embedding.token, prompt });\n return {\n mask: new Uint8Array(res['buffer'] as ArrayBuffer),\n width: res['width'] as number,\n height: res['height'] as number,\n iou: res['iou'] as number,\n };\n }\n\n /** Release the worker / ORT sessions. Calls still in flight reject (RT-8), so\n * their callers' `finally` blocks run (e.g. a tool's busy flag clears). */\n dispose(): void {\n this.dropWorker(new Error('SAM session disposed'));\n this.encoder?.release?.();\n this.decoder?.release?.();\n this.encoder = this.decoder = null;\n this.embeddings.clear();\n this.loaded = false;\n this.mode = null;\n }\n\n // ── worker plumbing ──────────────────────────────────────────────────────\n private ensureWorker(): Worker {\n if (this.worker) return this.worker;\n const worker = new Worker(new URL('./onnx-sam.worker', import.meta.url), { type: 'module' });\n worker.onmessage = (ev: MessageEvent<WorkerReply>) => this.calls.handle(ev.data);\n worker.onerror = (ev: ErrorEvent) => {\n // A crashed worker can't serve the loaded model any more: drop it, so the\n // next run reloads instead of posting to a dead worker.\n this.dropWorker(new Error(ev.message || 'SAM worker crashed.'));\n this.loaded = false;\n this.mode = null;\n };\n this.worker = worker;\n return worker;\n }\n\n /** Terminate the worker (if any) and reject every call still waiting on it. */\n private dropWorker(err: Error): void {\n this.worker?.terminate();\n this.worker = null;\n this.calls.rejectAll(err);\n }\n\n private call(\n msg: Record<string, unknown>,\n transfer: Transferable[] = [],\n onProgress?: (f: number) => void,\n ): Promise<WorkerReply> {\n const worker = this.ensureWorker();\n const { id, promise } = this.calls.open(onProgress);\n worker.postMessage({ ...msg, id }, transfer);\n return promise;\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
export { A as ALL_GENES, b as ALL_TOOLBAR_TOOLS, c as ANNOTATION_IMAGE_MAX_DIM, C as CANVAS_TOOL_IDS, d as CELL_SEGMENTER, e as CHANNEL_HISTOGRAM_API, h as CellposeSegmenterService, i as ChannelHistogramComponent, D as DEFAULT_CATEGORICAL_PALETTE, j as DEFAULT_FALLBACK_PALETTE, k as DEFAULT_MUTED_OPACITY, l as DEFAULT_SAM_MODEL_ID, m as DEFAULT_SPATIAL_VIEW, H as HexColorPickerComponent, I as IMAGE_STATE_PORT,
|
|
1
|
+
export { A as ALL_GENES, b as ALL_TOOLBAR_TOOLS, c as ANNOTATION_IMAGE_MAX_DIM, C as CANVAS_TOOL_IDS, d as CELL_SEGMENTER, e as CHANNEL_HISTOGRAM_API, h as CellposeSegmenterService, i as ChannelHistogramComponent, D as DEFAULT_CATEGORICAL_PALETTE, j as DEFAULT_FALLBACK_PALETTE, k as DEFAULT_MUTED_OPACITY, l as DEFAULT_SAM_MODEL_ID, m as DEFAULT_SPATIAL_VIEW, n as DEFAULT_VISIBLE_CHANNELS, H as HexColorPickerComponent, I as IMAGE_STATE_PORT, o as INSTANCE_SEGMENTER, p as ImageConverterService, L as LUT_COLORS, M as MISSING_COLOR, q as MultiPolygon, N as NAPARI_DECIMATE_OPTIONS, s as NAPARI_DEFAULT_DECIMATE, t as NO_CATEGORY, u as NO_OBSERVATION, P as PLOT_MODE_CONTEXT, v as PLOT_MODE_SESSION, w as PLOT_TYPE_CONTRIBUTIONS, x as PLOT_TYPE_DESCRIPTORS, y as PREFERENCES_PORT, z as PlotType, B as Polygon, E as ProcessingImage, R as REGION_EDITOR_API, F as REGION_IO_PORT, G as REGION_SOURCE_MIN_CHARS, J as Rectangle, K as Region, O as RegionEditorComponent, Q as RoutingVisualizerService, S as SAM_MODELS, T as SEMANTIC_SEGMENTER, U as SPATIAL_DATA_PORT, V as SPATIAL_WIRE_VERSION, W as ShapeSelection, X as SpatialChartsComponent, Y as SpatialControlsComponent, Z as SpatialDataHttpService, _ as SpatialSelectionStore, $ as SupersededError, a0 as TILE_ACCESS_PORT, a1 as TOOLBAR_TOOLS, a2 as VISUALIZER, a3 as VIZ_ALERT_TOAST_KEY, a4 as VIZ_CONFIG, a5 as VIZ_TOAST_KEY, a6 as ViewerFeature, a7 as VisualizationModule, a8 as VisualizerComponent, a9 as assertManifestVersion, aa as benefitsFromGrouping, ab as buildOmicsTraces, ac as capabilitiesOf, ad as clearSamModelCache, ae as contrastWindow, af as contributedPlotTypeOption, ag as countMask, ah as cropImage, ai as datasetFromManifest, aj as decodeColumn, ak as decodeCoords, al as decodeFeatureVector, am as decodePolygons, an as decodeRadius, ao as defaultChannelVisible, ap as defaultPresetSet, aq as dialogToolContributions, ar as emptySelection, as as encodeCategorical, at as encodeContinuous, au as expandZips, av as findColumnMeta, aw as getDefaultSamModelId, g as getOrtWasmBase, ax as getPlotTypeDescriptor, ay as getSamModel, az as hasZarrMetadata, aA as hydrateBounds, aB as importFile, aC as isBuiltinPlotType, aD as isCanvasToolId, aE as isCategoricalColumn, aF as isContinuousColumn, aG as isDialogToolContribution, aH as isEmptyPresetSet, aI as isLabelVolumeName, aJ as isLittleEndian, aK as isNapari3d, aL as isNapariIsosurface, aM as isNapariScatter, aN as isNapariScatter3d, aO as isNapariSurface, aP as isNapariVolume, aQ as isSamModelReady, aR as isSpatialOmics, aS as isSpatialOmics3d, aT as isThreeDimensional, aU as isZipName, aV as labelClasses, aW as labelSliceGeoJson, aX as lutFor, aY as markerDiameters, aZ as maskToIndices, a_ as mutedFromSelection, a$ as omicsLayout, b0 as openAnnotations, b1 as openGeoJsonRegionSource, b2 as openHttpRegionSource, b3 as parsePresetSet, b4 as planRegionImport, b5 as pointInRing, b6 as provideVisualization, b7 as readAnnotationSlices, b8 as readLabelVolume, b9 as readOmeZarrLabels, ba as readZip, bb as rendererOwnsWheel, bc as resolveCategoryColors, bd as selectByCategory, be as selectInRegions, bf as setDefaultSamModel, bg as setOrtWasmBase, bh as setSamModelUrls, bi as sortToolContributions, bj as visibleToolContributions } from './jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-DvFp1jNH.mjs';
|
|
2
2
|
import '@angular/core';
|
|
3
3
|
import '@angular/common/http';
|
|
4
4
|
import 'napari-js';
|
|
5
5
|
import 'rxjs';
|
|
6
6
|
import 'rxjs/operators';
|
|
7
|
-
import 'onnxruntime-web';
|
|
8
7
|
import 'napari-js/geometry';
|
|
8
|
+
import 'onnxruntime-web';
|
|
9
9
|
import 'fast-png';
|
|
10
10
|
import 'fzstd';
|
|
11
11
|
import '@angular/core/rxjs-interop';
|
|
@@ -18,6 +18,20 @@ export interface IChannelState {
|
|
|
18
18
|
gamma: number;
|
|
19
19
|
visible: boolean;
|
|
20
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* How many channels of a multichannel image start visible. Each visible channel is drawn
|
|
23
|
+
* from tiles of its own, so a 22-channel plate showed every channel at once and asked the
|
|
24
|
+
* server for 22 tiles per position on every pan and zoom. Channels past these start hidden
|
|
25
|
+
* (one click shows them), and a hidden channel fetches no tiles.
|
|
26
|
+
*/
|
|
27
|
+
export declare const DEFAULT_VISIBLE_CHANNELS = 4;
|
|
28
|
+
/**
|
|
29
|
+
* Whether channel `index` of `count` starts visible: as the image says when its
|
|
30
|
+
* `channelInfo` does, else every channel of an image with at most
|
|
31
|
+
* {@link DEFAULT_VISIBLE_CHANNELS}, and the first {@link DEFAULT_VISIBLE_CHANNELS} of one with more.
|
|
32
|
+
* Only a boolean says: a descriptor's `null` (a JSON field left empty) leaves the default.
|
|
33
|
+
*/
|
|
34
|
+
export declare function defaultChannelVisible(index: number, count: number, specified?: boolean | null): boolean;
|
|
21
35
|
/** The standard LUT pseudo-colours (mirrors Fiji's Merge Channels palette) for
|
|
22
36
|
* quick per-channel assignment. */
|
|
23
37
|
export declare const LUT_COLORS: ReadonlyArray<{
|
|
@@ -225,6 +225,26 @@ export interface SpatialViewState {
|
|
|
225
225
|
* not drawn, nor the transcripts inside them. Cleared when the group column changes.
|
|
226
226
|
*/
|
|
227
227
|
hiddenGroups: string[];
|
|
228
|
+
/**
|
|
229
|
+
* Genes whose observations are drawn: with any set, only the observations that express
|
|
230
|
+
* them (a value above 0) are drawn — the markers, the cell outlines and the transcripts
|
|
231
|
+
* inside them, in 2D and in the 3D cloud — and the rest are hidden. Empty draws every
|
|
232
|
+
* observation. Cleared when the dataset changes.
|
|
233
|
+
*/
|
|
234
|
+
observationGenes: string[];
|
|
235
|
+
/** Whether an observation must express any of {@link observationGenes}, or all of them. */
|
|
236
|
+
observationGenesMatch: 'any' | 'all';
|
|
237
|
+
/**
|
|
238
|
+
* Colour (and mark) the filtered observations by their gene: each drawn observation in the
|
|
239
|
+
* colour and icon of the picked gene it expresses most (relative to that gene's highest
|
|
240
|
+
* value), in place of {@link colorBy}. Off, {@link colorBy} colours them as before.
|
|
241
|
+
*/
|
|
242
|
+
observationGenesColorBy: boolean;
|
|
243
|
+
/** `#rrggbb` per gene of {@link observationGenes}; a gene left out takes the palette's colour
|
|
244
|
+
* for its place in the list. */
|
|
245
|
+
observationGeneColors: Record<string, string>;
|
|
246
|
+
/** The icon per gene of {@link observationGenes} (2D); a gene left out is drawn as a circle. */
|
|
247
|
+
observationGeneGlyphs: Record<string, TranscriptGlyphName>;
|
|
228
248
|
/** Draw the tissue image (the Images section's switch). */
|
|
229
249
|
showImage: boolean;
|
|
230
250
|
/** Draw the annotation regions (the Annotations section's switch). Selecting from them
|
|
@@ -258,6 +278,13 @@ export interface SpatialViewState {
|
|
|
258
278
|
* marker per transcript once those fit {@link transcriptBudget}.
|
|
259
279
|
*/
|
|
260
280
|
transcriptAllGenes: boolean;
|
|
281
|
+
/**
|
|
282
|
+
* Genes of "All genes" switched off with their eye toggle — its own list, so hiding a gene
|
|
283
|
+
* there leaves the selection's {@link transcriptHiddenGenes} alone, and the other way round.
|
|
284
|
+
* Led by `'*'` (`ALL_GENES`), it lists the genes still shown instead: `['*']` hides every
|
|
285
|
+
* gene, `['*', 'KRT5']` shows KRT5 alone, without naming the thousands of others.
|
|
286
|
+
*/
|
|
287
|
+
transcriptAllGenesHidden: string[];
|
|
261
288
|
/**
|
|
262
289
|
* Most transcript markers drawn at once. The level of detail is chosen to stay under it,
|
|
263
290
|
* which is what keeps pan and zoom responsive however dense the data is.
|
|
@@ -21,6 +21,8 @@ export interface IChannelInfo {
|
|
|
21
21
|
minAllowed?: number;
|
|
22
22
|
/** Pixel-type maximum (e.g. 65535 for unsigned 16-bit). Native-unit ceiling. */
|
|
23
23
|
maxAllowed?: number;
|
|
24
|
+
/** Whether the channel starts visible; else the first `DEFAULT_VISIBLE_CHANNELS` do. */
|
|
25
|
+
visible?: boolean;
|
|
24
26
|
}
|
|
25
27
|
/** Per-series image metadata (physical size + dimensions). */
|
|
26
28
|
export interface IImageMetadata {
|
|
@@ -177,6 +177,9 @@ export interface IRegionEditorApi {
|
|
|
177
177
|
setClassesHidden?(classes: readonly string[], hidden: boolean): void;
|
|
178
178
|
/** Select every region of these classes on the slice, the source's included (taken). */
|
|
179
179
|
selectRegionClasses?(classes: readonly string[], additive?: boolean): Promise<void>;
|
|
180
|
+
/** The classes the selection was picked as by {@link selectRegionClasses}; [] once anything
|
|
181
|
+
* else is selected (a row, a region drawn or clicked). */
|
|
182
|
+
getPickedRegionClasses$?(): Observable<readonly string[]>;
|
|
180
183
|
/** {@link getGeoJsonString} merged with the region source behind the regions (see
|
|
181
184
|
* `RegionStore.getGeoJsonWithSource`); `slice` names a folder stack's slice. */
|
|
182
185
|
getGeoJsonStringWithSource?(regions: Region[], slice?: number): Promise<string>;
|
|
@@ -278,6 +278,13 @@ export interface SpatialTranscriptTilesMeta {
|
|
|
278
278
|
count?: number;
|
|
279
279
|
/** Real genes (control probes excluded). Names come from the feature search. */
|
|
280
280
|
geneCount: number;
|
|
281
|
+
/**
|
|
282
|
+
* The genes an all-gene tile's `gene` codes index, in code order (the port's
|
|
283
|
+
* `TranscriptTileQuery.genes` with `[ALL_GENES]`); an empty name is a code those tiles never
|
|
284
|
+
* carry (a control probe). Optional: without it "All genes" still draws, but cannot hide one
|
|
285
|
+
* of its genes.
|
|
286
|
+
*/
|
|
287
|
+
genes?: string[];
|
|
281
288
|
hasZ: boolean;
|
|
282
289
|
levels: (SpatialTileLevel & {
|
|
283
290
|
/** True when an entry stands for several transcripts (see {@link SpatialTranscriptTile.weight}). */
|
|
@@ -305,6 +305,12 @@ export interface SpatialCategoricalView {
|
|
|
305
305
|
/** Per-observation category index, or `NO_CATEGORY`. */
|
|
306
306
|
codes: Uint16Array;
|
|
307
307
|
}
|
|
308
|
+
/**
|
|
309
|
+
* How "Select from ROIs" selects: inside the volumes of the region classes picked
|
|
310
|
+
* in the Region Editor (Spatial omics 3D, the regions on the dataset's reference
|
|
311
|
+
* volume shown), or by the drawn regions.
|
|
312
|
+
*/
|
|
313
|
+
export type RoiSelectionMode = 'class-volumes' | 'regions';
|
|
308
314
|
/**
|
|
309
315
|
* Controls for the SPATIAL_OMICS plot type: what the observation markers are
|
|
310
316
|
* coloured by, and how they are drawn. Capability-gated like
|
|
@@ -384,6 +390,9 @@ export interface ISpatialControls {
|
|
|
384
390
|
hi: number;
|
|
385
391
|
max: number;
|
|
386
392
|
} | null>;
|
|
393
|
+
/** True while the observation gene filter could not be applied (an expression read failed):
|
|
394
|
+
* the observations then still show the last filter that could be. */
|
|
395
|
+
getGeneFilterFailed$?(): Observable<boolean>;
|
|
387
396
|
/**
|
|
388
397
|
* The z positions of the sections the dataset was imaged at, ascending — or
|
|
389
398
|
* null when its z is continuous rather than sectioned (so there are no sections
|
|
@@ -399,9 +408,26 @@ export interface ISpatialControls {
|
|
|
399
408
|
/**
|
|
400
409
|
* Select every observation inside the currently-drawn regions (their union).
|
|
401
410
|
* Reuses the existing ROI tools — rectangle, polygon, freehand, wand, brush —
|
|
402
|
-
* so there is no separate marquee to learn.
|
|
411
|
+
* so there is no separate marquee to learn. In the 3D cloud, the region classes
|
|
412
|
+
* picked in the Region Editor (see {@link getPickedRegionClasses$}) select the
|
|
413
|
+
* observations inside their volumes instead, when the regions sit on the
|
|
414
|
+
* dataset's reference volume; without a pick, the lassos drawn over the cloud.
|
|
415
|
+
* Resolves how many were selected — or null when it was superseded while the
|
|
416
|
+
* classes' outlines were read (a newer selection, a Clear, another dataset, view
|
|
417
|
+
* or pick), in which case nothing was published.
|
|
418
|
+
*/
|
|
419
|
+
selectFromRegions(): Promise<number | null>;
|
|
420
|
+
/**
|
|
421
|
+
* How {@link selectFromRegions} would select now: inside the picked classes'
|
|
422
|
+
* volumes, or by the drawn regions. The rule it runs by, so a panel describing
|
|
423
|
+
* the button can never disagree with what it does.
|
|
424
|
+
*/
|
|
425
|
+
roiSelectionMode?(): RoiSelectionMode;
|
|
426
|
+
/**
|
|
427
|
+
* The region classes the region selection was picked as (a class tree node with
|
|
428
|
+
* its subclasses, a surface clicked in 3D); [] for any other selection.
|
|
403
429
|
*/
|
|
404
|
-
|
|
430
|
+
getPickedRegionClasses$?(): Observable<readonly string[]>;
|
|
405
431
|
/** Select every observation in one category of a categorical column — the
|
|
406
432
|
* legend click. Rejects for an unknown or continuous column. */
|
|
407
433
|
selectCategory(column: string, categoryIndex: number): Promise<number>;
|
|
@@ -28,6 +28,12 @@ export interface ReconstructOptions {
|
|
|
28
28
|
* {@link loftLines}). Empty when no slice has an area and no two slices have lines.
|
|
29
29
|
*/
|
|
30
30
|
export declare function reconstruct(slices: readonly SliceOutlines[], opts?: ReconstructOptions): Mesh;
|
|
31
|
+
/**
|
|
32
|
+
* Fill one slice's outlines into `mask`, a `width × height` grid of image px (pixel i spanning
|
|
33
|
+
* [i, i + 1)), as the reconstruction fills them: each feature even-odd, the features as their
|
|
34
|
+
* union, sampled at pixel centres. Cells already set stay set. Open lines enclose nothing.
|
|
35
|
+
*/
|
|
36
|
+
export declare function fillOutlines(mask: Uint8Array, width: number, height: number, outlines: SliceOutlines): void;
|
|
31
37
|
/**
|
|
32
38
|
* The area inside `rings` (interleaved `x, y`), even-odd: a ring inside an odd number of others is
|
|
33
39
|
* a hole. Exact for rings that do not cross (a polygon set's exteriors and holes).
|
|
@@ -101,6 +101,13 @@ export declare class Image2dScene implements NapariScene {
|
|
|
101
101
|
/** Channel states + grayscale colormap → live-apply to the rendered layers (no re-fetch; only z
|
|
102
102
|
* changes re-fetch), and recolour the navigator thumbnail. */
|
|
103
103
|
private followDisplayState;
|
|
104
|
+
/**
|
|
105
|
+
* Put the current channel states back on the rendered layers: each channel's visibility, window,
|
|
106
|
+
* gamma and tint, and which of an RGB image's layers draw it. For a caller that changed the
|
|
107
|
+
* layers' visibility wholesale (the spatial view showing its tissue again), so the channels
|
|
108
|
+
* the user or the defaults switched off stay off. Nothing to do before the image is drawn.
|
|
109
|
+
*/
|
|
110
|
+
reapplyDisplayState(): void;
|
|
104
111
|
/** Apply the current channel states / colormap to the live layers (no re-fetch), delegating the
|
|
105
112
|
* per-channel layer mutations to the {@link MultiChannelImageView}. */
|
|
106
113
|
private applyDisplayState;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ImageLayer, Viewer } from 'napari-js';
|
|
2
2
|
import { IHistogram } from '../../contracts/channel-histogram-api.contract';
|
|
3
3
|
import { SpatialDataset } from '../../contracts/spatial-dataset.contract';
|
|
4
|
-
import { SpatialViewState } from '../../contracts/display-types';
|
|
4
|
+
import { SpatialViewState, TranscriptGlyphName } from '../../contracts/display-types';
|
|
5
5
|
import { SpatialSelectionMask } from '../../spatial/spatial-selection';
|
|
6
6
|
import { NapariSpatialTileLayers } from './napari-spatial-tiles';
|
|
7
7
|
import { Image2dScene } from './napari-image-2d-scene';
|
|
@@ -157,7 +157,18 @@ export declare class Spatial2dScene extends SpatialSceneBase implements NapariSc
|
|
|
157
157
|
* selected to colour by. Categorical columns use the column's own palette; continuous columns
|
|
158
158
|
* and gene vectors go through the active colormap with a percentile-clipped window.
|
|
159
159
|
*/
|
|
160
|
-
|
|
160
|
+
/** The observations the view's gene filter keeps (1 = drawn), or null when it has none.
|
|
161
|
+
* Rejects when an expression read fails. */
|
|
162
|
+
private filterMask;
|
|
163
|
+
/** The markers' colours (and icons, by gene) before the gene filter hides any of them. */
|
|
164
|
+
private markerStyle;
|
|
165
|
+
/** {@link faceColors} before the gene filter: what the colour source and the selection make of them. */
|
|
166
|
+
private sourceColors;
|
|
161
167
|
/** Continuous values → RGBA through the active colormap and a clipped window. */
|
|
162
168
|
encodeContinuous(values: Float32Array, view: SpatialViewState, muted?: Uint8Array | null): Float32Array;
|
|
163
169
|
}
|
|
170
|
+
/** Per-observation napari-js symbol codes: each observation's gene's icon (`codes` index
|
|
171
|
+
* `glyphs`), a disc where it has none. */
|
|
172
|
+
export declare function glyphSymbols(codes: Uint16Array, glyphs: readonly TranscriptGlyphName[]): Uint8Array;
|
|
173
|
+
/** The symbols of the drawn subset (all of them when `indices` is undefined). */
|
|
174
|
+
export declare function gatherSymbols(symbols: Uint8Array | null, indices?: Uint32Array): Uint8Array | null;
|
|
@@ -94,6 +94,11 @@ export declare function encodeSpatialContinuous(values: Float32Array, view: Spat
|
|
|
94
94
|
export type PointColors = Float32Array | RGBA;
|
|
95
95
|
/** Whether a colour input is one RGBA per point rather than one broadcast RGBA. */
|
|
96
96
|
export declare function isPerPoint(colors: PointColors): colors is Float32Array;
|
|
97
|
+
/**
|
|
98
|
+
* `colors` with every observation `shown` leaves at 0 made transparent: the observations a gene
|
|
99
|
+
* filter leaves out. A broadcast colour becomes per-point, since the points now differ.
|
|
100
|
+
*/
|
|
101
|
+
export declare function hideUnshown(colors: PointColors, shown: Uint8Array): Float32Array;
|
|
97
102
|
/** Per-point colours for the drawn subset. A broadcast tuple stays broadcast —
|
|
98
103
|
* it is one colour for every point either way. */
|
|
99
104
|
export declare function gatherColors(colors: PointColors, indices?: Uint32Array): PointColors;
|
|
@@ -26,6 +26,8 @@ export interface SpatialTileSinks {
|
|
|
26
26
|
max: number;
|
|
27
27
|
}): void;
|
|
28
28
|
loadingChanged(layers: string[]): void;
|
|
29
|
+
/** Whether the observation gene filter could be applied; see {@link SpatialSession.reportGeneFilter}. */
|
|
30
|
+
geneFilterFailed?(failed: boolean): void;
|
|
29
31
|
}
|
|
30
32
|
/** The 2D scene the tile layers currently draw into. */
|
|
31
33
|
export interface SpatialTileOwner {
|
|
@@ -64,6 +66,8 @@ export declare class SpatialSession {
|
|
|
64
66
|
private tileLayers;
|
|
65
67
|
private tileOwner;
|
|
66
68
|
constructor(port: SpatialDataPort | null, selection: SpatialSelectionStore | null, sinks: SpatialTileSinks);
|
|
69
|
+
/** Tell the panel whether the observation gene filter could be applied this rebuild. */
|
|
70
|
+
reportGeneFilter(failed: boolean): void;
|
|
67
71
|
/** The tile layers, if they were ever built. */
|
|
68
72
|
get tiles(): NapariSpatialTileLayers | null;
|
|
69
73
|
/**
|
|
@@ -80,6 +80,8 @@ export declare class NapariVisualizerService extends BaseStoreVisualizer impleme
|
|
|
80
80
|
hi: number;
|
|
81
81
|
max: number;
|
|
82
82
|
} | null>;
|
|
83
|
+
/** The observation gene filter could not be applied (an expression read failed). */
|
|
84
|
+
readonly geneFilterFailed$: BehaviorSubject<boolean>;
|
|
83
85
|
/** "x reloading…" at the bottom of the canvas: the tile layers' loads and the observations'. */
|
|
84
86
|
private readonly badge;
|
|
85
87
|
/** The store's display state (colormap, reverse, invert) and the colormaps derived from it. */
|
|
@@ -150,6 +152,9 @@ export declare class NapariVisualizerService extends BaseStoreVisualizer impleme
|
|
|
150
152
|
/** Observations projected to canvas pixels under the 3D camera (the spatial 3D cloud), indexed
|
|
151
153
|
* by observation with NaN for any not drawn; null when no cloud is mounted. */
|
|
152
154
|
getSpatialScreenProjection(obs: SpatialObservations): Float32Array | null;
|
|
155
|
+
/** The ids of the regions drawn over the 3D cloud in screen space (its lassos); [] in 2D. Every
|
|
156
|
+
* other region in the store is in image space, and means nothing at canvas pixels. */
|
|
157
|
+
getSpatialLassoIds(): number[];
|
|
153
158
|
private fitCameraSoon;
|
|
154
159
|
/** @deprecated Plotly-specific; host re-drives plot() from its image stream. */
|
|
155
160
|
reloadAndPlot(): void;
|
|
@@ -21,6 +21,11 @@ export declare class CategoricalLookup {
|
|
|
21
21
|
constructor(port: SpatialDataPort);
|
|
22
22
|
/** Codes of the column `name`, or null when it is not categorical. */
|
|
23
23
|
codes(name: string): Promise<CategoricalCodes | null>;
|
|
24
|
-
/**
|
|
24
|
+
/**
|
|
25
|
+
* The observations not drawn: those of the groups switched off, and those the gene filter
|
|
26
|
+
* leaves out. Null when nothing is hidden.
|
|
27
|
+
*/
|
|
25
28
|
hiddenCodes(dataset: SpatialDataset, view: SpatialViewState): Promise<HiddenCodes | null>;
|
|
29
|
+
/** Codes of the group column that are switched off, or null when none are. */
|
|
30
|
+
private hiddenGroupCodes;
|
|
26
31
|
}
|
|
@@ -62,6 +62,10 @@ export interface DrawnTranscripts {
|
|
|
62
62
|
merged: SpatialTranscriptTile;
|
|
63
63
|
/** The layer the entries are drawn in, one marker per entry in the same order. */
|
|
64
64
|
layer: PointsLayer;
|
|
65
|
+
/**
|
|
66
|
+
* The genes the entries' `gene` codes index: the selection's, or for every gene's individual
|
|
67
|
+
* transcripts the dataset's gene list (`transcriptTiles.genes`; empty without one).
|
|
68
|
+
*/
|
|
65
69
|
genes: string[];
|
|
66
70
|
/** For a grouped gene selection: each entry's group, and the groups' names. */
|
|
67
71
|
entryGroup?: Int32Array;
|
|
@@ -6,7 +6,7 @@ import { TranscriptGlyph } from '../../../spatial/glyphs';
|
|
|
6
6
|
import type { CategoricalLookup } from './categorical-lookup';
|
|
7
7
|
import type { OrderedLayerGroups, TileGroup } from './layer-groups';
|
|
8
8
|
import type { PlanContext } from './plan-context';
|
|
9
|
-
import type { TranscriptHover } from './transcript-hover';
|
|
9
|
+
import type { TranscriptHover, TranscriptKind } from './transcript-hover';
|
|
10
10
|
import { type TranscriptJobPlanner } from './transcript-jobs';
|
|
11
11
|
/**
|
|
12
12
|
* The napari-js point symbol each transcript icon is drawn as. Every icon has a counterpart of
|
|
@@ -14,6 +14,8 @@ import { type TranscriptJobPlanner } from './transcript-jobs';
|
|
|
14
14
|
* differs.
|
|
15
15
|
*/
|
|
16
16
|
export declare const GLYPH_SYMBOLS: Readonly<Record<TranscriptGlyph, PointSymbol>>;
|
|
17
|
+
/** The view the markers are coloured by, for what was loaded. */
|
|
18
|
+
export declare function colorViewFor(view: SpatialViewState, kind: TranscriptKind, clustered: boolean, hasCellTypes: boolean): SpatialViewState;
|
|
17
19
|
/**
|
|
18
20
|
* The transcript markers of the 2D spatial view: runs the planner's job, drops hidden groups
|
|
19
21
|
* and genes, groups a selection under the marker budget, colours the entries and draws them as
|
|
@@ -361,6 +361,7 @@ export declare class RoutingVisualizerService implements IVisualizer, IRegionEdi
|
|
|
361
361
|
getHiddenClasses$(): Observable<ReadonlySet<string>>;
|
|
362
362
|
setClassesHidden(classes: readonly string[], hidden: boolean): void;
|
|
363
363
|
selectRegionClasses(classes: readonly string[], additive?: boolean): Promise<void>;
|
|
364
|
+
getPickedRegionClasses$(): Observable<readonly string[]>;
|
|
364
365
|
getGeoJsonStringWithSource(regions: Region[], slice?: number): Promise<string>;
|
|
365
366
|
enterStackMode(slices: Map<number, Region[]>, initialZ?: number, saveLayout?: 'combined' | 'per-slice-file'): void;
|
|
366
367
|
exitStackMode(): void;
|
package/lib/spatial/lod.d.ts
CHANGED
|
@@ -35,7 +35,9 @@ export declare function isCuratedColumn(name: string): boolean;
|
|
|
35
35
|
* The categorical column that names each cell's type: the view's choice when it is a
|
|
36
36
|
* column of this dataset, else the first categorical column that is not a curated
|
|
37
37
|
* annotation (a pipeline's clustering is the default; curation is opted into), else
|
|
38
|
-
* any categorical column.
|
|
38
|
+
* any categorical column. A column of one category, such as the `region` a SpatialData
|
|
39
|
+
* table links its cells to their shapes with, names no type and is only used when chosen;
|
|
40
|
+
* a dataset with nothing else has no cell types (null).
|
|
39
41
|
*/
|
|
40
42
|
export declare function cellTypeColumnFor(dataset: SpatialDataset, view: Pick<SpatialViewState, 'cellTypeColumn'>): string | null;
|
|
41
43
|
/** A stable string id for a tile key, `level/gx/gy` — usable as a Map key. */
|
|
@@ -24,8 +24,16 @@ export interface SpatialRendererFeeds {
|
|
|
24
24
|
max: number;
|
|
25
25
|
} | null>;
|
|
26
26
|
};
|
|
27
|
+
readonly geneFilterFailed$?: {
|
|
28
|
+
asObservable(): Observable<boolean>;
|
|
29
|
+
};
|
|
27
30
|
/** Observations projected to canvas pixels by the 3D camera, or null when the cloud is not mounted. */
|
|
28
31
|
getSpatialScreenProjection(obs: SpatialObservations): Float32Array | null;
|
|
32
|
+
/** The ids of the regions drawn over the 3D cloud in screen space (its lassos). */
|
|
33
|
+
getSpatialLassoIds(): number[];
|
|
34
|
+
/** Image px per voxel of the volume the region surfaces sit in; null when the plotted image is
|
|
35
|
+
* not a volume's stack (the regions are then not in the reference volume's grid). */
|
|
36
|
+
regionVoxelStep(): number | null;
|
|
29
37
|
}
|
|
30
38
|
/** What the facade works over: the shared stores, the renderer feeds and the router's view state. */
|
|
31
39
|
export interface SpatialControlsContext {
|
|
@@ -53,12 +61,21 @@ export declare class SpatialControlsFacade {
|
|
|
53
61
|
private readonly ctx;
|
|
54
62
|
/** The controls; one object for the facade's life, so consumers can hold it. */
|
|
55
63
|
readonly controls: ISpatialControls;
|
|
56
|
-
/** Latest dataset, mirrored so `selectFromRegions()`
|
|
57
|
-
* runs from a button click and must not await a round-trip. */
|
|
64
|
+
/** Latest dataset, mirrored so `selectFromRegions()` answers from the dataset on
|
|
65
|
+
* screen — it runs from a button click and must not await a round-trip. */
|
|
58
66
|
private dataset;
|
|
59
67
|
private readonly sub;
|
|
68
|
+
/** Bumped per class-volume selection (and on dispose): only the latest may publish. */
|
|
69
|
+
private roiRequest;
|
|
60
70
|
constructor(port: SpatialDataPort, ctx: SpatialControlsContext);
|
|
61
71
|
/** Release the port subscription (the router's injector is being destroyed). */
|
|
62
72
|
dispose(): void;
|
|
73
|
+
/**
|
|
74
|
+
* How "Select from ROIs" selects now — the one rule its executor and the panel's description
|
|
75
|
+
* share: inside the picked classes' volumes in the 3D cloud, when the dataset has a reference
|
|
76
|
+
* volume (and no tissue image) and the plotted image is that volume's stack, so the regions sit
|
|
77
|
+
* in its grid; by the drawn regions otherwise.
|
|
78
|
+
*/
|
|
79
|
+
private roiSelectionMode;
|
|
63
80
|
private build;
|
|
64
81
|
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { SpatialViewState, TranscriptGlyphName } from '../contracts/display-types';
|
|
2
|
+
/** One gene's value for every observation: the port's `getFeatureVector`. */
|
|
3
|
+
export type FeatureVectorSource = (gene: string) => Promise<Float32Array>;
|
|
4
|
+
type GeneFilterView = Pick<SpatialViewState, 'observationGenes' | 'observationGenesMatch'>;
|
|
5
|
+
/** Whether the view draws only the observations expressing some genes. */
|
|
6
|
+
export declare function hasGeneFilter(view: Partial<GeneFilterView>): boolean;
|
|
7
|
+
/** What decides the gene filter, for the layers' cache keys: '' when there is none. */
|
|
8
|
+
export declare function geneFilterKey(view: Partial<GeneFilterView>): string;
|
|
9
|
+
/**
|
|
10
|
+
* 1 for each of `count` observations that expresses the genes — a value above 0 in any of
|
|
11
|
+
* `vectors`, or in all of them — else 0. A missing value (NaN) is not expressed.
|
|
12
|
+
*/
|
|
13
|
+
export declare function expressingMask(vectors: readonly Float32Array[], count: number, match: 'any' | 'all'): Uint8Array;
|
|
14
|
+
/**
|
|
15
|
+
* The view's gene filter as a per-observation mask (1 = drawn), or null when it has none. Every
|
|
16
|
+
* layer asks on every rebuild, so the mask of the same vectors is built once.
|
|
17
|
+
*/
|
|
18
|
+
export declare function observationGeneMask(view: GeneFilterView, count: number, read: FeatureVectorSource): Promise<Uint8Array | null>;
|
|
19
|
+
/** The colour a gene of the observation filter is drawn in: the view's own, else the palette's
|
|
20
|
+
* for its place in the list. */
|
|
21
|
+
export declare function observationGeneColor(view: Pick<SpatialViewState, 'observationGenes' | 'observationGeneColors'>, gene: string): string;
|
|
22
|
+
/** The icon a gene of the observation filter is drawn as (2D): the view's own, else a circle. */
|
|
23
|
+
export declare function observationGeneGlyph(view: Pick<SpatialViewState, 'observationGeneGlyphs'>, gene: string): TranscriptGlyphName;
|
|
24
|
+
/** Whether the filtered observations are coloured by their gene (rather than by `colorBy`). */
|
|
25
|
+
export declare function colorsByObservationGene(view: Pick<SpatialViewState, 'observationGenes' | 'observationGenesColorBy'>): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Each observation's gene among `vectors`: the index of the one it expresses most relative to
|
|
28
|
+
* that gene's own highest value — so a gene expressed at low counts everywhere is not always
|
|
29
|
+
* outvoted by a highly expressed one — or {@link NO_CATEGORY} where it expresses none.
|
|
30
|
+
*/
|
|
31
|
+
export declare function dominantGenes(vectors: readonly Float32Array[], count: number): Uint16Array;
|
|
32
|
+
/**
|
|
33
|
+
* How the filtered observations are drawn, by gene: each observation's gene (an index into the
|
|
34
|
+
* view's genes, see {@link dominantGenes}) with the genes' colours and icons. Null when the view
|
|
35
|
+
* does not colour by them.
|
|
36
|
+
*/
|
|
37
|
+
export declare function observationGeneStyle(view: GeneFilterView & Pick<SpatialViewState, 'observationGenesColorBy' | 'observationGeneColors' | 'observationGeneGlyphs'>, count: number, read: FeatureVectorSource): Promise<{
|
|
38
|
+
codes: Uint16Array;
|
|
39
|
+
colors: string[];
|
|
40
|
+
glyphs: TranscriptGlyphName[];
|
|
41
|
+
} | null>;
|
|
42
|
+
/** What decides how the filtered observations are drawn by gene, for cache keys. */
|
|
43
|
+
export declare function observationGeneStyleKey(view: Pick<SpatialViewState, 'observationGenes' | 'observationGenesColorBy' | 'observationGeneColors' | 'observationGeneGlyphs'>): string;
|
|
44
|
+
export {};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Region } from '../models/region';
|
|
2
|
+
import { SliceOutlines } from '../geometry/reconstruct';
|
|
2
3
|
import { RingBounds as Bounds } from '../geometry/ring';
|
|
3
|
-
import { SpatialImageRef, SpatialObservations, SpatialSelectionMask } from '../contracts/spatial-dataset.contract';
|
|
4
|
+
import { SpatialImageRef, SpatialObservations, SpatialSelectionMask, SpatialVolumeMeta } from '../contracts/spatial-dataset.contract';
|
|
4
5
|
/**
|
|
5
6
|
* Which observations fall inside a set of drawn regions.
|
|
6
7
|
*
|
|
@@ -95,6 +96,20 @@ export declare function selectInRegions(observations: SpatialObservations, image
|
|
|
95
96
|
* never selected.
|
|
96
97
|
*/
|
|
97
98
|
export declare function selectInRegionsProjected(screen: Float32Array, count: number, regions: readonly Region[]): SpatialSelectionMask;
|
|
99
|
+
/**
|
|
100
|
+
* Observations inside the VOLUME a stack of outlines encloses: a region class (an
|
|
101
|
+
* atlas structure with its substructures) through every section of the dataset's
|
|
102
|
+
* reference volume, as its 3D reconstruction shows it.
|
|
103
|
+
*
|
|
104
|
+
* The outlines are in the volume's own grid — x, y in voxels, z the slice — which
|
|
105
|
+
* is where regions imported onto the volume's stack sit. An observation is in voxel
|
|
106
|
+
* `(⌊x / vx⌋, ⌊y / vy⌋, ⌊z / vz⌋)` (see `volumeImageRef`), and selected when its
|
|
107
|
+
* slice's outlines cover that voxel, filled as the reconstruction fills them. One
|
|
108
|
+
* slice is rasterised at a time, so a structure through the whole brain costs one
|
|
109
|
+
* slice's mask, not the volume's. An observation outside the volume, or without a
|
|
110
|
+
* z, is never selected.
|
|
111
|
+
*/
|
|
112
|
+
export declare function selectInClassVolumes(observations: SpatialObservations, volume: SpatialVolumeMeta, slices: readonly SliceOutlines[]): SpatialSelectionMask;
|
|
98
113
|
/**
|
|
99
114
|
* Whether two selections hold exactly the same observations.
|
|
100
115
|
*
|
|
@@ -15,6 +15,23 @@ export declare function filterRings(rings: SpatialPolygonTile, hidden: {
|
|
|
15
15
|
} | null): SpatialPolygonTile;
|
|
16
16
|
/** Slots (indices into the selected genes) switched off with their eye toggle. */
|
|
17
17
|
export declare function hiddenGeneSlots(view: SpatialViewState): Uint8Array | null;
|
|
18
|
+
/**
|
|
19
|
+
* Whether "All genes" is switched off as a whole with the gene tree's root eye: its hidden
|
|
20
|
+
* list is `[ALL_GENES]` (every gene hidden, none excepted). Hiding every gene by name would
|
|
21
|
+
* need the gene list, which a dataset need not have.
|
|
22
|
+
*/
|
|
23
|
+
export declare function allGenesHidden(view: Pick<SpatialViewState, 'transcriptAllGenes' | 'transcriptAllGenesHidden'>): boolean;
|
|
24
|
+
/** Whether an "All genes" hidden list hides every gene, none excepted. */
|
|
25
|
+
export declare function everyGeneOff(off: readonly string[]): boolean;
|
|
26
|
+
/** Whether a gene of "All genes" is drawn, by its hidden list (see `transcriptAllGenesHidden`). */
|
|
27
|
+
export declare function allGeneShownBy(off: readonly string[]): (gene: string) => boolean;
|
|
28
|
+
/** "All genes"'s hidden list with `gene` shown (`on`) or hidden, in the list's own form. */
|
|
29
|
+
export declare function toggleAllGeneHidden(off: readonly string[], gene: string, on: boolean): string[];
|
|
30
|
+
/**
|
|
31
|
+
* Codes (indices into `genes`, the dataset's all-gene code order) switched off with their eye
|
|
32
|
+
* toggle while every gene is drawn; null when none is, or without the gene list.
|
|
33
|
+
*/
|
|
34
|
+
export declare function hiddenAllGeneCodes(view: Pick<SpatialViewState, 'transcriptAllGenesHidden'>, genes: readonly string[] | undefined): Uint8Array | null;
|
|
18
35
|
/** Entries in a hidden group's cell, or of a hidden gene, removed (with their sizes). */
|
|
19
36
|
export declare function filterTranscripts(t: SpatialTranscriptTile, px: Float32Array, hidden: {
|
|
20
37
|
codes: Uint16Array;
|