@jax-data-science/sci-image-visualizer 0.3.3 → 0.5.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.
Files changed (98) hide show
  1. package/README.md +268 -4
  2. package/esm2022/index.mjs +21 -1
  3. package/esm2022/lib/contracts/display-types.mjs +20 -2
  4. package/esm2022/lib/contracts/image.contract.mjs +1 -1
  5. package/esm2022/lib/contracts/plot-type-contribution.contract.mjs +66 -0
  6. package/esm2022/lib/contracts/plot-type.mjs +41 -1
  7. package/esm2022/lib/contracts/ports/spatial-data.port.mjs +3 -0
  8. package/esm2022/lib/contracts/spatial-dataset.contract.mjs +45 -0
  9. package/esm2022/lib/contracts/visualizer.contract.mjs +1 -1
  10. package/esm2022/lib/implementations/napari-js/napari-axes-labels.mjs +10 -19
  11. package/esm2022/lib/implementations/napari-js/napari-region-overlay.mjs +71 -7
  12. package/esm2022/lib/implementations/napari-js/napari-scale-bar.mjs +1 -1
  13. package/esm2022/lib/implementations/napari-js/napari-spatial-tooltip.mjs +96 -0
  14. package/esm2022/lib/implementations/napari-js/napari-visualizer.service.mjs +1934 -55
  15. package/esm2022/lib/implementations/napari-js/napari-zoom.mjs +18 -0
  16. package/esm2022/lib/implementations/osd/openseadragon-visualizer.service.mjs +73 -8
  17. package/esm2022/lib/implementations/osd/osd-coordinate-transform.mjs +8 -1
  18. package/esm2022/lib/implementations/osd/osd-region-overlay.mjs +3 -4
  19. package/esm2022/lib/implementations/osd/osd-zoom.mjs +20 -0
  20. package/esm2022/lib/implementations/plotly/omics-trace-builders.mjs +555 -0
  21. package/esm2022/lib/implementations/plotly/plotly.service.mjs +13 -7
  22. package/esm2022/lib/implementations/spatial-data-http/spatial-data-http.service.mjs +304 -0
  23. package/esm2022/lib/implementations/spatial-data-http/spatial-wire.mjs +179 -0
  24. package/esm2022/lib/plot-mode/plot-mode-controller.mjs +329 -0
  25. package/esm2022/lib/routing-visualizer.service.mjs +228 -12
  26. package/esm2022/lib/spatial/embedding-compute.mjs +142 -0
  27. package/esm2022/lib/spatial/gene-search.mjs +77 -0
  28. package/esm2022/lib/spatial/spatial-density.mjs +224 -0
  29. package/esm2022/lib/spatial/spatial-encoding.mjs +232 -0
  30. package/esm2022/lib/spatial/spatial-expression.mjs +257 -0
  31. package/esm2022/lib/spatial/spatial-framing.mjs +60 -0
  32. package/esm2022/lib/spatial/spatial-heatmap.mjs +185 -0
  33. package/esm2022/lib/spatial/spatial-hover.mjs +79 -0
  34. package/esm2022/lib/spatial/spatial-sections.mjs +96 -0
  35. package/esm2022/lib/spatial/spatial-selection.mjs +264 -0
  36. package/esm2022/lib/spatial/spatial-volume-image.mjs +163 -0
  37. package/esm2022/lib/spatial/tsne-worker.mjs +10 -0
  38. package/esm2022/lib/spatial/world-grid.mjs +77 -0
  39. package/esm2022/lib/spatial-controls/spatial-charts/spatial-charts.component.mjs +1278 -0
  40. package/esm2022/lib/spatial-controls/spatial-controls.component.mjs +621 -0
  41. package/esm2022/lib/store/spatial-selection.service.mjs +47 -0
  42. package/esm2022/lib/store/visualizer-store.service.mjs +23 -1
  43. package/esm2022/lib/toolbar/toolbar.component.mjs +61 -21
  44. package/esm2022/lib/visualization.module.mjs +23 -5
  45. package/esm2022/lib/visualizer.component.mjs +527 -44
  46. package/fesm2022/{jax-data-science-sci-image-visualizer-onnx-sam-session-ci1q0xnJ.mjs → jax-data-science-sci-image-visualizer-onnx-sam-session-BwP-A11m.mjs} +6 -4
  47. package/fesm2022/{jax-data-science-sci-image-visualizer-onnx-sam-session-ci1q0xnJ.mjs.map → jax-data-science-sci-image-visualizer-onnx-sam-session-BwP-A11m.mjs.map} +1 -1
  48. package/fesm2022/jax-data-science-sci-image-visualizer-tsne-worker-B_nXDGf0.mjs +12 -0
  49. package/fesm2022/jax-data-science-sci-image-visualizer-tsne-worker-B_nXDGf0.mjs.map +1 -0
  50. package/fesm2022/jax-data-science-sci-image-visualizer.mjs +15971 -7808
  51. package/fesm2022/jax-data-science-sci-image-visualizer.mjs.map +1 -1
  52. package/fesm2022/tsne.worker.js +19091 -0
  53. package/index.d.ts +16 -0
  54. package/lib/contracts/display-types.d.ts +131 -0
  55. package/lib/contracts/image.contract.d.ts +7 -0
  56. package/lib/contracts/plot-type-contribution.contract.d.ts +172 -0
  57. package/lib/contracts/plot-type.d.ts +52 -2
  58. package/lib/contracts/ports/spatial-data.port.d.ts +90 -0
  59. package/lib/contracts/spatial-dataset.contract.d.ts +281 -0
  60. package/lib/contracts/visualizer.contract.d.ts +104 -1
  61. package/lib/implementations/napari-js/napari-axes-labels.d.ts +9 -7
  62. package/lib/implementations/napari-js/napari-region-overlay.d.ts +38 -4
  63. package/lib/implementations/napari-js/napari-scale-bar.d.ts +7 -3
  64. package/lib/implementations/napari-js/napari-spatial-tooltip.d.ts +32 -0
  65. package/lib/implementations/napari-js/napari-visualizer.service.d.ts +497 -16
  66. package/lib/implementations/napari-js/napari-zoom.d.ts +15 -0
  67. package/lib/implementations/osd/openseadragon-visualizer.service.d.ts +21 -0
  68. package/lib/implementations/osd/osd-coordinate-transform.d.ts +6 -0
  69. package/lib/implementations/osd/osd-zoom.d.ts +19 -0
  70. package/lib/implementations/plotly/omics-trace-builders.d.ts +193 -0
  71. package/lib/implementations/plotly/plotly.service.d.ts +9 -0
  72. package/lib/implementations/spatial-data-http/spatial-data-http.service.d.ts +123 -0
  73. package/lib/implementations/spatial-data-http/spatial-wire.d.ts +115 -0
  74. package/lib/plot-mode/plot-mode-controller.d.ts +130 -0
  75. package/lib/routing-visualizer.service.d.ts +49 -6
  76. package/lib/spatial/embedding-compute.d.ts +73 -0
  77. package/lib/spatial/gene-search.d.ts +48 -0
  78. package/lib/spatial/spatial-density.d.ts +73 -0
  79. package/lib/spatial/spatial-encoding.d.ts +155 -0
  80. package/lib/spatial/spatial-expression.d.ts +144 -0
  81. package/lib/spatial/spatial-framing.d.ts +37 -0
  82. package/lib/spatial/spatial-heatmap.d.ts +111 -0
  83. package/lib/spatial/spatial-hover.d.ts +49 -0
  84. package/lib/spatial/spatial-sections.d.ts +59 -0
  85. package/lib/spatial/spatial-selection.d.ts +113 -0
  86. package/lib/spatial/spatial-volume-image.d.ts +67 -0
  87. package/lib/spatial/tsne-worker.d.ts +7 -0
  88. package/lib/spatial/world-grid.d.ts +58 -0
  89. package/lib/spatial-controls/spatial-charts/spatial-charts.component.d.ts +439 -0
  90. package/lib/spatial-controls/spatial-controls.component.d.ts +257 -0
  91. package/lib/store/spatial-selection.service.d.ts +27 -0
  92. package/lib/store/visualizer-store.service.d.ts +13 -0
  93. package/lib/toolbar/toolbar.component.d.ts +36 -8
  94. package/lib/visualization.module.d.ts +28 -24
  95. package/lib/visualizer.component.d.ts +139 -7
  96. package/package.json +6 -2
  97. package/src/lib/assets/spatial-omics-3d.svg +31 -0
  98. package/src/lib/assets/spatial-omics.svg +27 -0
@@ -1,4 +1,4 @@
1
- import { ChangeDetectorRef, AfterViewInit, EventEmitter, NgZone, OnChanges, OnDestroy, OnInit, SimpleChanges } from '@angular/core';
1
+ import { ChangeDetectorRef, AfterViewInit, ElementRef, EventEmitter, Injector, NgZone, OnChanges, OnDestroy, OnInit, SimpleChanges, Type } from '@angular/core';
2
2
  import { Subscription } from 'rxjs';
3
3
  import { MenuItem, MessageService, TreeNode } from 'primeng/api';
4
4
  import { ContextMenu } from 'primeng/contextmenu';
@@ -7,7 +7,9 @@ import { ImageStatePort } from './contracts/ports/image-state.port';
7
7
  import { Polygon } from './models/region';
8
8
  import { RegionOpsService } from './region-ops.service';
9
9
  import { VisualizerStore } from './store/visualizer-store.service';
10
- import { PlotType, PlotTypeDescriptor } from './contracts/plot-type';
10
+ import { PlotType, PlotTypeDescriptor, PlotTypeId } from './contracts/plot-type';
11
+ import { PlotTypeContribution, PlotTypeOption } from './contracts/plot-type-contribution.contract';
12
+ import { PlotModeController } from './plot-mode/plot-mode-controller';
11
13
  import { IVisualizer } from './contracts/visualizer.contract';
12
14
  import { SamToolService } from './toolbar/segmentation/sam-tool.service';
13
15
  import { SamPointToolService } from './toolbar/segmentation/sam-point-tool.service';
@@ -15,6 +17,7 @@ import { CellSegmentToolService } from './toolbar/segmentation/cell-segment-tool
15
17
  import { NumberParamSpec, SelectParamSpec, ToolParamSpec, ToolbarToolContribution } from './contracts/toolbar-tool.contract';
16
18
  import { ToolbarToolVisibility } from './contracts/toolbar-config';
17
19
  import { VizConfig } from './contracts/viz-config';
20
+ import { SpatialDataPort } from './contracts/ports/spatial-data.port';
18
21
  import * as i0 from "@angular/core";
19
22
  export declare class VisualizerComponent implements OnInit, OnChanges, AfterViewInit, OnDestroy {
20
23
  private state;
@@ -28,6 +31,8 @@ export declare class VisualizerComponent implements OnInit, OnChanges, AfterView
28
31
  private samPointTool;
29
32
  private regionOps;
30
33
  private vizConfig?;
34
+ private spatialData?;
35
+ private injector?;
31
36
  /** Per-instance toast key. MessageService is a global singleton, so two live
32
37
  * `<visualizer>` instances (main viewer + pipeline-dialog preview) sharing
33
38
  * one key would each render the same message — a duplicate toast. A unique
@@ -177,6 +182,8 @@ export declare class VisualizerComponent implements OnInit, OnChanges, AfterView
177
182
  selectedColormap: any;
178
183
  /** Channels & Histogram dialog visibility (opened from the toolbar). */
179
184
  showChannelHistogram: boolean;
185
+ /** Spatial-omics controls dialog visibility (toolbar button). */
186
+ showSpatialControls: boolean;
180
187
  /** Region Editor dialog visibility (opened from the toolbar). */
181
188
  showRegionEditor: boolean;
182
189
  /** Region Editor dialog width. On open it is set to the configured host
@@ -200,9 +207,48 @@ export declare class VisualizerComponent implements OnInit, OnChanges, AfterView
200
207
  wireframeActive: boolean;
201
208
  /** napari 3D decimate factor (1 = Full … 8 = ⅛; default ½); changing it re-plots. */
202
209
  resolutionScale: number;
203
- /** Plot types the active backend advertises (3D gated by capability). */
210
+ /** The selector's entries: the built-in plot types the active backend
211
+ * advertises (3D gated by capability), then any contributed modes
212
+ * ({@link PLOT_TYPE_CONTRIBUTIONS}). */
213
+ plotTypeMenu: PlotTypeOption[];
214
+ /**
215
+ * The built-in plot types on offer — {@link plotTypeMenu} without contributed
216
+ * modes. Kept with its original type so existing readers are unaffected.
217
+ */
204
218
  plotTypeOptions: PlotTypeDescriptor[];
205
- selectedPlotType: PlotType;
219
+ /**
220
+ * What the selector shows: a built-in type or a contributed mode's id. Every
221
+ * rendering and tool decision goes through {@link basePlotType} instead, so a
222
+ * contributed mode behaves exactly like the built-in type it rides on.
223
+ */
224
+ selectedPlotTypeId: PlotTypeId;
225
+ /**
226
+ * The built-in plot type being rendered. With no contributed mode active this
227
+ * is the selection itself; during one it is the mode's `baseType`. Kept with its
228
+ * original `PlotType` type for existing readers — use {@link selectedPlotTypeId}
229
+ * for the selector's id. Assigning selects that built-in type.
230
+ */
231
+ get selectedPlotType(): PlotType;
232
+ set selectedPlotType(type: PlotType);
233
+ /** Contributed plot modes and their single live session. */
234
+ readonly plotModes: PlotModeController;
235
+ /**
236
+ * The live contributed mode's side panel, as the template renders it: an
237
+ * Angular component with its own injector, or a plain host element a `mount`
238
+ * panel rendered into. Null while no contributed session is live.
239
+ */
240
+ plotModePanel: {
241
+ title: string;
242
+ component: Type<unknown> | null;
243
+ injector: Injector | null;
244
+ host: HTMLElement | null;
245
+ } | null;
246
+ private destroying;
247
+ /** Where a `mount` panel's host element is attached once the dialog renders. */
248
+ set plotModePanelSlot(ref: ElementRef<HTMLElement> | undefined);
249
+ /** The built-in type actually rendered for {@link selectedPlotTypeId}: itself
250
+ * for a built-in type, `baseType` for a contributed mode. */
251
+ get basePlotType(): PlotType;
206
252
  /** Floating intensity-profile inset (LINE mode). */
207
253
  readonly intensityInsetDiv = "intensity-inset-plot";
208
254
  profilePanelPos: {
@@ -230,6 +276,10 @@ export declare class VisualizerComponent implements OnInit, OnChanges, AfterView
230
276
  private profileDragMoveListener?;
231
277
  private profileDragUpListener?;
232
278
  private profileResizeListener?;
279
+ /** True while the 3D spatial cloud is the active mode. The controls drop the ROI
280
+ * selection there: region tools are screen-space, and against an orbiting
281
+ * camera a drawn rectangle has no fixed meaning in the data. */
282
+ get isSpatial3dMode(): boolean;
233
283
  /** LINE plot type shows the image + draggable line ROI + intensity inset. */
234
284
  get isProfileMode(): boolean;
235
285
  /** True for the Image plot type, which renders as a natively pan/zoom-able
@@ -239,6 +289,24 @@ export declare class VisualizerComponent implements OnInit, OnChanges, AfterView
239
289
  /** Isosurface band as a 0–255 slider position, mapped onto the volume's real
240
290
  * intensity range by the renderer. Defaults to the full range. */
241
291
  isoRange: number[];
292
+ /** Whether a spatial-omics dataset is currently published on
293
+ * `SPATIAL_DATA_PORT` — gates the spatial plot types in the selector. */
294
+ private hasSpatialDataset;
295
+ /** Whether that dataset's observations carry a z, gating the 3D spatial mode. */
296
+ private hasSpatial3dDataset;
297
+ /** Whether it carries a registered volume. Change detection only: a volume
298
+ * appearing is what publishes it as the image, and the plot-type gates then
299
+ * see an ordinary grayscale stack. */
300
+ private hasSpatialVolume;
301
+ /** Dataset identity + capability shape the last emission was handled at, so a
302
+ * switch between two datasets of the same shape is not mistaken for a repeat. */
303
+ private spatialDatasetKey;
304
+ /** Dataset + geometry the currently published volume image was built from, so a
305
+ * re-emitted dataset doesn't re-fetch megabytes or reset the user's scrub. */
306
+ private volumeImageKey;
307
+ /** Blob URLs backing that image — ours to revoke. */
308
+ private volumeImageUrls;
309
+ private spatialDatasetSubscription?;
242
310
  plotWidthSubscription?: Subscription;
243
311
  imageLoadingSubscription?: Subscription;
244
312
  imgLoadingMessageSubscription?: Subscription;
@@ -250,7 +318,7 @@ export declare class VisualizerComponent implements OnInit, OnChanges, AfterView
250
318
  private wheelListener?;
251
319
  /** Debounced z-slice scrubbing (see SliceScrubber — refactoring plan Step 7). */
252
320
  private readonly scrubber;
253
- constructor(state: ImageStatePort, plotService: IVisualizer, messageService: MessageService, ngZone: NgZone, cdr: ChangeDetectorRef, session: VisualizerStore, samTool: SamToolService, cellSegmentTool: CellSegmentToolService, samPointTool: SamPointToolService, regionOps: RegionOpsService, vizConfig?: VizConfig | undefined, toolContributions?: readonly ToolbarToolContribution[]);
321
+ constructor(state: ImageStatePort, plotService: IVisualizer, messageService: MessageService, ngZone: NgZone, cdr: ChangeDetectorRef, session: VisualizerStore, samTool: SamToolService, cellSegmentTool: CellSegmentToolService, samPointTool: SamPointToolService, regionOps: RegionOpsService, vizConfig?: VizConfig | undefined, toolContributions?: readonly ToolbarToolContribution[], spatialData?: SpatialDataPort | undefined, plotTypeContributions?: readonly PlotTypeContribution[], injector?: Injector | undefined);
254
322
  /**
255
323
  * Plot types offered in the selector for the current image:
256
324
  * - Outside **test mode**, only the curated default set (descriptors with a
@@ -263,12 +331,55 @@ export declare class VisualizerComponent implements OnInit, OnChanges, AfterView
263
331
  * - scalar-intensity types (contour, surface, isosurface) hidden for RGB
264
332
  * images — they map a single intensity per pixel. Image and Heatmap render
265
333
  * any image.
334
+ * - spatial-omics types hidden until a `SpatialDataset` is published on
335
+ * `SPATIAL_DATA_PORT` — the mode has nothing to draw without observations,
336
+ * exactly as a volume has nothing to draw without a stack.
337
+ */
338
+ /**
339
+ * Track whether a spatial-omics dataset is available. A dataset appearing (or
340
+ * being cleared) changes which plot types make sense, so it drives the same
341
+ * recompute + reconcile that the image stream and the test-mode toggle do.
342
+ *
343
+ * No-op when the host provides no `SPATIAL_DATA_PORT` — the spatial types then
344
+ * stay hidden for the life of the component.
266
345
  */
346
+ private watchSpatialDataset;
347
+ /**
348
+ * Publish a dataset's reference volume AS the image, and open the 2D Image view
349
+ * on it.
350
+ *
351
+ * The volume is a 3D image delivered in one file, so for a dataset that has no
352
+ * section image it is the honest thing to put on screen: the slice bar scrubs z,
353
+ * and the contrast window, colormaps and region tools all work because the
354
+ * volume genuinely is the image now. The 3D cloud stays one menu pick away.
355
+ *
356
+ * Keyed by dataset + geometry: the dataset stream re-emits on things like a
357
+ * colour-column change, and rebuilding then would re-fetch the voxels and throw
358
+ * the user back to the middle slice.
359
+ */
360
+ private showVolumeAsImage;
361
+ /** Forget the published volume image so re-selecting the dataset rebuilds it.
362
+ * The URLs deliberately stay alive: the host may still be displaying that image
363
+ * at this instant, and revoking under it would break every later tile read. They
364
+ * are freed when the next volume replaces them, or on destroy. */
365
+ private dropVolumeImage;
366
+ private revokeVolumeImageUrls;
267
367
  private computePlotTypeOptions;
268
368
  ngOnChanges(changes: SimpleChanges): void;
269
369
  /** If the active plot type is no longer in the offered options (e.g. test mode
270
370
  * turned off while a test-only type was active, or a scalar type carried onto
271
371
  * an RGB image), fall back to the default 2D Image view. */
372
+ /** Whether the live spatial dataset brings pixels of its own — a tissue image it
373
+ * registers onto, or a volume that is published as a z-stack image. */
374
+ private spatialDatasetHasPixels;
375
+ /**
376
+ * The host published NO image — a spatial dataset that brings none does this.
377
+ *
378
+ * Without handling the empty emission, `imageInfo` keeps the LAST image's metadata: the
379
+ * selector goes on offering pixel modes for pixels that are gone, and every
380
+ * `isStack`/`isGrayscale` decision is made against a file that is no longer loaded.
381
+ */
382
+ private onImageCleared;
272
383
  private reconcileSelectedPlotType;
273
384
  ngOnInit(): void;
274
385
  ngAfterViewInit(): void;
@@ -302,6 +413,8 @@ export declare class VisualizerComponent implements OnInit, OnChanges, AfterView
302
413
  selectColormap(colormapNode: TreeNode): void;
303
414
  /** Open the Channels & Histogram dialog (toolbar button). */
304
415
  openChannelHistogram(): void;
416
+ /** Toolbar → open the spatial-omics controls. */
417
+ openSpatialControls(): void;
305
418
  /** Open the Region Editor dialog (toolbar button). The editor stays linked to
306
419
  * this plotting instance through the root RegionStore singleton, so it works
307
420
  * the same as the former right-panel Regions tab. */
@@ -473,9 +586,28 @@ export declare class VisualizerComponent implements OnInit, OnChanges, AfterView
473
586
  * the toolbar/context-menu logic relies on, deactivates 2D-only tools when
474
587
  * moving to a 3D type, then re-plots.
475
588
  */
476
- onSelectPlotType(type: PlotType): void;
589
+ onSelectPlotType(selected: PlotTypeId): void;
590
+ /**
591
+ * Start the selected contributed mode's session, once its base view has
592
+ * plotted. No-op for a built-in type, or when the base on screen is not the
593
+ * one the mode rides on. A backend that cannot provide a viewport for it
594
+ * (e.g. OSD fell back to Plotly) counts as a failed activation.
595
+ */
596
+ private activateSelectedPlotMode;
597
+ /** Render the live mode's panel. Activation can resolve outside Angular (an
598
+ * OSD callback, a contribution's own promise), hence the zone re-entry. */
599
+ private showPlotModePanel;
600
+ /** Drop the panel (destroying a component panel) before the session ends. */
601
+ private hidePlotModePanel;
602
+ /**
603
+ * A contributed mode could not start. Its base type is already on screen —
604
+ * the base plotted first — so just select it: nothing needs to re-plot.
605
+ */
606
+ private fallBackFromPlotMode;
607
+ /** Run change detection; returns what it threw (logged), or null. */
608
+ private detectChangesSafely;
477
609
  /** Deactivate whatever tool is armed and clear every tool mode. */
478
610
  private deactivateActiveTool;
479
- static ɵfac: i0.ɵɵFactoryDeclaration<VisualizerComponent, [null, null, null, null, null, null, null, null, null, null, { optional: true; }, { optional: true; }]>;
611
+ static ɵfac: i0.ɵɵFactoryDeclaration<VisualizerComponent, [null, null, null, null, null, null, null, null, null, null, { optional: true; }, { optional: true; }, { optional: true; }, { optional: true; }, { optional: true; }]>;
480
612
  static ɵcmp: i0.ɵɵComponentDeclaration<VisualizerComponent, "visualizer", never, { "toolbarTools": { "alias": "toolbarTools"; "required": false; }; "testMode": { "alias": "testMode"; "required": false; }; }, { "isStackEvent": "isStackEvent"; "isGrayscaleEvent": "isGrayscaleEvent"; }, never, ["*"], false, never>;
481
613
  }
package/package.json CHANGED
@@ -1,6 +1,9 @@
1
1
  {
2
2
  "name": "@jax-data-science/sci-image-visualizer",
3
- "version": "0.3.3",
3
+ "version": "0.5.0",
4
+ "engines": {
5
+ "node": ">=20.9.0"
6
+ },
4
7
  "description": "Browser-based scientific image visualization for Angular — gigapixel whole-slide (OpenSeadragon), 2D/3D (Plotly) and WebGPU (napari-js) rendering, with region/annotation editing and in-browser SAM segmentation.",
5
8
  "keywords": [
6
9
  "angular",
@@ -34,9 +37,10 @@
34
37
  "access": "public"
35
38
  },
36
39
  "dependencies": {
40
+ "@jax-js/jax": "^0.1.24",
37
41
  "cellpose-js": "^0.6.0",
38
42
  "fast-png": "^6.4.0",
39
- "napari-js": "^0.11.1",
43
+ "napari-js": "^0.14.0",
40
44
  "openseadragon": "^6.0.2",
41
45
  "plotly.js-dist-min": "^3.0.1",
42
46
  "tslib": "^2.3.0"
@@ -0,0 +1,31 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 512 512">
2
+ <!-- Spatial omics in 3D: the same observations as spatial-omics.svg — dots
3
+ whose SIZE varies with the value they carry — but arranged on a cube
4
+ lattice instead of a flat grid. Two square planes of four, the back one
5
+ offset up-right and drawn smaller, which is the whole 3D cue: no edges,
6
+ no perspective lines, nothing that needs a stroke to survive.
7
+
8
+ Sized for a 16px toolbar icon (1rem in the toolbar, 1.1rem in the
9
+ plot-mode dropdown), which drives every choice, exactly as in the 2D
10
+ icon it sits beside:
11
+ - Solid fills only. Both call sites tint with `filter: brightness(0) …`,
12
+ which flattens every colour to one — tone cannot carry meaning, so
13
+ the arrangement has to.
14
+ - Ink at 6-14% of the viewBox and 23% of the box overall, matching
15
+ spatial-omics.svg so the pair reads at one weight in the toolbar.
16
+ - Eight dots, not the 2D icon's nine plus a second layer: at 16px the
17
+ gaps are what make a lattice legible, and 4+4 keeps every gap above
18
+ 2px where an 18-dot stack would silt up into a blob. -->
19
+ <g fill="#000000">
20
+ <!-- front plane -->
21
+ <circle cx="77" cy="180" r="59"/>
22
+ <circle cx="331" cy="180" r="42"/>
23
+ <circle cx="77" cy="434" r="71"/>
24
+ <circle cx="331" cy="434" r="50"/>
25
+ <!-- back plane, offset (+127, -127) and scaled to 0.78 -->
26
+ <circle cx="204" cy="53" r="38"/>
27
+ <circle cx="458" cy="53" r="48"/>
28
+ <circle cx="204" cy="307" r="33"/>
29
+ <circle cx="458" cy="307" r="43"/>
30
+ </g>
31
+ </svg>
@@ -0,0 +1,27 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 512 512">
2
+ <!-- Spatial omics: an array of observations (spots / cells) whose SIZE varies
3
+ with the value they carry — the thing this plot mode draws.
4
+ Deliberately frameless, so it does not read as cells.svg (the cellpose
5
+ button, a framed dot cluster) sitting in the same toolbar.
6
+
7
+ Sized for a 16px toolbar icon, which drives every choice:
8
+ - Solid fills only. The toolbar tints icons with
9
+ `filter: brightness(0) …`, which flattens every colour to black — a
10
+ white highlight inside a dark shape simply disappears, so shape has to
11
+ carry the meaning, not tone.
12
+ - Ink at ~7-13% of the viewBox. Thin strokes (the 6/512 and 12/512 of the
13
+ previous version) render sub-pixel at 16px, antialias to ~20-40% alpha,
14
+ and the recolour filter then washes them out to an illegible smudge.
15
+ - No low-opacity decoration: invisible at 16px either way. -->
16
+ <g fill="#000000">
17
+ <circle cx="128" cy="128" r="34"/>
18
+ <circle cx="256" cy="128" r="52"/>
19
+ <circle cx="384" cy="128" r="40"/>
20
+ <circle cx="128" cy="256" r="52"/>
21
+ <circle cx="256" cy="256" r="68"/>
22
+ <circle cx="384" cy="256" r="34"/>
23
+ <circle cx="128" cy="384" r="40"/>
24
+ <circle cx="256" cy="384" r="34"/>
25
+ <circle cx="384" cy="384" r="52"/>
26
+ </g>
27
+ </svg>