@jax-data-science/sci-image-visualizer 0.17.0 → 0.18.1

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 (121) hide show
  1. package/esm2022/lib/contracts/display-types.mjs +3 -2
  2. package/esm2022/lib/contracts/image.contract.mjs +1 -1
  3. package/esm2022/lib/contracts/ports/spatial-data.port.mjs +1 -1
  4. package/esm2022/lib/contracts/region-editor-api.contract.mjs +1 -1
  5. package/esm2022/lib/contracts/region-store.contract.mjs +1 -1
  6. package/esm2022/lib/contracts/spatial-dataset.contract.mjs +1 -1
  7. package/esm2022/lib/contracts/visualizer.contract.mjs +1 -1
  8. package/esm2022/lib/geometry/cell-meshes.mjs +37 -0
  9. package/esm2022/lib/geometry/place.mjs +47 -0
  10. package/esm2022/lib/implementations/napari-js/napari-camera-depth.mjs +93 -0
  11. package/esm2022/lib/implementations/napari-js/napari-loading-state.mjs +1 -1
  12. package/esm2022/lib/implementations/napari-js/napari-region-overlay.mjs +2 -2
  13. package/esm2022/lib/implementations/napari-js/napari-scene.mjs +1 -1
  14. package/esm2022/lib/implementations/napari-js/napari-spatial-2d-scene.mjs +81 -15
  15. package/esm2022/lib/implementations/napari-js/napari-spatial-3d-cells.mjs +746 -0
  16. package/esm2022/lib/implementations/napari-js/napari-spatial-3d-scene.mjs +325 -18
  17. package/esm2022/lib/implementations/napari-js/napari-spatial-3d-transcripts.mjs +182 -24
  18. package/esm2022/lib/implementations/napari-js/napari-spatial-hover.mjs +95 -5
  19. package/esm2022/lib/implementations/napari-js/napari-spatial-scene.mjs +15 -1
  20. package/esm2022/lib/implementations/napari-js/napari-spatial-tiles.mjs +30 -2
  21. package/esm2022/lib/implementations/napari-js/napari-visualizer.service.mjs +40 -1
  22. package/esm2022/lib/implementations/napari-js/napari-volume-region-meshes.mjs +111 -28
  23. package/esm2022/lib/implementations/napari-js/napari-volume-scene.mjs +14 -2
  24. package/esm2022/lib/implementations/napari-js/spatial-tiles/cell-layers.mjs +180 -48
  25. package/esm2022/lib/implementations/napari-js/spatial-tiles/transcript-layers.mjs +28 -8
  26. package/esm2022/lib/implementations/osd/osd-region-overlay.mjs +2 -2
  27. package/esm2022/lib/implementations/spatial-data-http/spatial-data-http.service.mjs +10 -1
  28. package/esm2022/lib/region-editor/class-tree/class-tree.component.mjs +30 -3
  29. package/esm2022/lib/region-editor/classes-panel/classes-panel.component.mjs +15 -3
  30. package/esm2022/lib/region-editor/region-editor.component.mjs +24 -4
  31. package/esm2022/lib/region-source/region-source-ops.mjs +7 -1
  32. package/esm2022/lib/region-source/region-tiles.mjs +1 -1
  33. package/esm2022/lib/region-source/worker-region-source.mjs +24 -1
  34. package/esm2022/lib/routing-visualizer.service.mjs +404 -7
  35. package/esm2022/lib/spatial/observations-in-selection.mjs +83 -0
  36. package/esm2022/lib/spatial/plane-cells.mjs +119 -0
  37. package/esm2022/lib/spatial/spatial-controls.facade.mjs +298 -5
  38. package/esm2022/lib/spatial/spatial-encoding.mjs +35 -3
  39. package/esm2022/lib/spatial/spatial-hover.mjs +34 -1
  40. package/esm2022/lib/spatial/spatial-planes.mjs +49 -0
  41. package/esm2022/lib/spatial/spatial-selection.mjs +2 -2
  42. package/esm2022/lib/spatial/spatial-tile-merge.mjs +38 -1
  43. package/esm2022/lib/spatial/transcripts-in-selection.mjs +208 -0
  44. package/esm2022/lib/spatial-controls/spatial-cells-panel/spatial-cells-panel.component.mjs +42 -65
  45. package/esm2022/lib/spatial-controls/spatial-color-by/spatial-color-by.component.mjs +187 -0
  46. package/esm2022/lib/spatial-controls/spatial-controls.component.mjs +47 -12
  47. package/esm2022/lib/spatial-controls/spatial-gene-tree/spatial-gene-tree.component.mjs +3 -3
  48. package/esm2022/lib/spatial-controls/spatial-groups-panel/spatial-groups-panel.component.mjs +38 -10
  49. package/esm2022/lib/spatial-controls/spatial-key/spatial-key.component.mjs +3 -3
  50. package/esm2022/lib/spatial-controls/spatial-marker-genes-form/spatial-marker-genes-form.component.mjs +3 -3
  51. package/esm2022/lib/spatial-controls/spatial-observations-panel/spatial-observations-panel.component.mjs +79 -57
  52. package/esm2022/lib/spatial-controls/spatial-selection-observations/spatial-selection-observations.component.mjs +101 -0
  53. package/esm2022/lib/spatial-controls/spatial-selection-transcripts/spatial-selection-transcripts.component.mjs +94 -0
  54. package/esm2022/lib/spatial-controls/spatial-transcripts-panel/spatial-transcripts-panel.component.mjs +9 -3
  55. package/esm2022/lib/store/region-source-scope.mjs +10 -1
  56. package/esm2022/lib/store/region-store.service.mjs +33 -2
  57. package/esm2022/lib/toolbar/toolbar.component.mjs +10 -3
  58. package/esm2022/lib/visualizer/spatial-region-set.mjs +95 -0
  59. package/esm2022/lib/visualizer.component.mjs +40 -4
  60. package/fesm2022/{jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-DHrHO2ay.mjs → jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-YrNqv8wH.mjs} +4521 -759
  61. package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-YrNqv8wH.mjs.map +1 -0
  62. package/fesm2022/{jax-data-science-sci-image-visualizer-onnx-sam-session-CKEUwNta.mjs → jax-data-science-sci-image-visualizer-onnx-sam-session-Dph35S7m.mjs} +2 -2
  63. package/fesm2022/{jax-data-science-sci-image-visualizer-onnx-sam-session-CKEUwNta.mjs.map → jax-data-science-sci-image-visualizer-onnx-sam-session-Dph35S7m.mjs.map} +1 -1
  64. package/fesm2022/jax-data-science-sci-image-visualizer.mjs +1 -1
  65. package/fesm2022/region-source.worker.js +84 -2
  66. package/lib/contracts/display-types.d.ts +90 -4
  67. package/lib/contracts/image.contract.d.ts +6 -0
  68. package/lib/contracts/ports/spatial-data.port.d.ts +7 -0
  69. package/lib/contracts/region-editor-api.contract.d.ts +9 -0
  70. package/lib/contracts/region-store.contract.d.ts +6 -0
  71. package/lib/contracts/spatial-dataset.contract.d.ts +7 -1
  72. package/lib/contracts/visualizer.contract.d.ts +43 -1
  73. package/lib/geometry/cell-meshes.d.ts +27 -0
  74. package/lib/geometry/place.d.ts +45 -0
  75. package/lib/implementations/napari-js/napari-camera-depth.d.ts +23 -0
  76. package/lib/implementations/napari-js/napari-loading-state.d.ts +1 -1
  77. package/lib/implementations/napari-js/napari-scene.d.ts +12 -0
  78. package/lib/implementations/napari-js/napari-spatial-2d-scene.d.ts +19 -3
  79. package/lib/implementations/napari-js/napari-spatial-3d-cells.d.ts +141 -0
  80. package/lib/implementations/napari-js/napari-spatial-3d-scene.d.ts +87 -0
  81. package/lib/implementations/napari-js/napari-spatial-3d-transcripts.d.ts +49 -8
  82. package/lib/implementations/napari-js/napari-spatial-hover.d.ts +22 -0
  83. package/lib/implementations/napari-js/napari-spatial-scene.d.ts +12 -0
  84. package/lib/implementations/napari-js/napari-spatial-tiles.d.ts +15 -0
  85. package/lib/implementations/napari-js/napari-visualizer.service.d.ts +27 -1
  86. package/lib/implementations/napari-js/napari-volume-region-meshes.d.ts +38 -19
  87. package/lib/implementations/napari-js/napari-volume-scene.d.ts +2 -0
  88. package/lib/implementations/napari-js/spatial-tiles/cell-layers.d.ts +53 -0
  89. package/lib/implementations/napari-js/spatial-tiles/transcript-layers.d.ts +11 -2
  90. package/lib/implementations/spatial-data-http/spatial-data-http.service.d.ts +7 -0
  91. package/lib/region-editor/class-tree/class-tree.component.d.ts +16 -1
  92. package/lib/region-editor/classes-panel/classes-panel.component.d.ts +10 -1
  93. package/lib/region-editor/region-editor.component.d.ts +4 -0
  94. package/lib/region-source/region-source-ops.d.ts +12 -0
  95. package/lib/region-source/region-tiles.d.ts +8 -0
  96. package/lib/region-source/worker-region-source.d.ts +18 -0
  97. package/lib/routing-visualizer.service.d.ts +140 -1
  98. package/lib/spatial/observations-in-selection.d.ts +43 -0
  99. package/lib/spatial/plane-cells.d.ts +37 -0
  100. package/lib/spatial/spatial-controls.facade.d.ts +59 -0
  101. package/lib/spatial/spatial-encoding.d.ts +14 -1
  102. package/lib/spatial/spatial-hover.d.ts +23 -0
  103. package/lib/spatial/spatial-planes.d.ts +22 -0
  104. package/lib/spatial/spatial-selection.d.ts +2 -1
  105. package/lib/spatial/spatial-tile-merge.d.ts +9 -0
  106. package/lib/spatial/transcripts-in-selection.d.ts +95 -0
  107. package/lib/spatial-controls/spatial-cells-panel/spatial-cells-panel.component.d.ts +19 -28
  108. package/lib/spatial-controls/spatial-color-by/spatial-color-by.component.d.ts +64 -0
  109. package/lib/spatial-controls/spatial-controls.component.d.ts +17 -2
  110. package/lib/spatial-controls/spatial-groups-panel/spatial-groups-panel.component.d.ts +16 -6
  111. package/lib/spatial-controls/spatial-observations-panel/spatial-observations-panel.component.d.ts +26 -23
  112. package/lib/spatial-controls/spatial-selection-observations/spatial-selection-observations.component.d.ts +48 -0
  113. package/lib/spatial-controls/spatial-selection-transcripts/spatial-selection-transcripts.component.d.ts +43 -0
  114. package/lib/spatial-controls/spatial-transcripts-panel/spatial-transcripts-panel.component.d.ts +3 -1
  115. package/lib/store/region-source-scope.d.ts +4 -0
  116. package/lib/store/region-store.service.d.ts +21 -0
  117. package/lib/toolbar/toolbar.component.d.ts +6 -1
  118. package/lib/visualizer/spatial-region-set.d.ts +55 -0
  119. package/lib/visualizer.component.d.ts +14 -0
  120. package/package.json +1 -1
  121. package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-DHrHO2ay.mjs.map +0 -1
@@ -0,0 +1,37 @@
1
+ import type { SpatialImageRef, SpatialObservations, SpatialPolygonTile } from '../contracts/spatial-dataset.contract';
2
+ import type { TileFeature } from '../region-source/region-tiles';
3
+ /** Each observation's index by its id, or null when the observations carry no ids. */
4
+ export declare function observationIndex(obs: SpatialObservations): Map<string, number> | null;
5
+ /** A feature's cell id: its id without the slice a folder region set qualifies it with. */
6
+ export declare function cellIdOf(featureId: string): string;
7
+ /**
8
+ * The rings of `tiles`' features (each once, though a feature is in every tile it meets), owned by
9
+ * their cells, in observation units (the region set's are the image's pixels: back through `ref`).
10
+ * A feature of no observation, and an open one (a polyline), is left out; each ring of a feature
11
+ * (its parts and holes) is a ring of its cell.
12
+ */
13
+ export declare function planeCellRings(tiles: readonly {
14
+ features: readonly TileFeature[];
15
+ }[], index: ReadonlyMap<string, number>, ref: SpatialImageRef | null | undefined): SpatialPolygonTile;
16
+ /** One plane's tiles of a region set: the plane's slice index (its place among the set's planes). */
17
+ export interface PlaneTiles {
18
+ slice: number;
19
+ tiles: readonly {
20
+ features: readonly TileFeature[];
21
+ }[];
22
+ }
23
+ /**
24
+ * Each cell's outlines on every plane it spans, from the planes' tiles (a feature once, though in
25
+ * every tile it meets), for the 3D reconstruction of each cell by itself (`CellOutlines`, slice k
26
+ * at z = k). Only cells of `classes` (all when null), whose outlines' centre over all planes is in
27
+ * `within` (`[x0, y0, x1, y1]`, image px; anywhere when absent): the tiles fetched for an area hold
28
+ * the cells crossing its edge too, which belong to the area their centre is in.
29
+ */
30
+ export declare function cellOutlinesFromTiles(planes: readonly PlaneTiles[], index: ReadonlyMap<string, number>, classes: ReadonlySet<string> | null, within?: readonly [number, number, number, number]): {
31
+ cell: number;
32
+ label: string | null;
33
+ slices: {
34
+ z: number;
35
+ rings: Float32Array[];
36
+ }[];
37
+ }[];
@@ -1,3 +1,4 @@
1
+ import type { Cells3dStatus } from '../contracts/display-types';
1
2
  import { Observable } from 'rxjs';
2
3
  import { PlotType } from '../contracts/plot-type';
3
4
  import { SpatialDataPort } from '../contracts/ports/spatial-data.port';
@@ -27,6 +28,9 @@ export interface SpatialRendererFeeds {
27
28
  readonly geneFilterFailed$?: {
28
29
  asObservable(): Observable<boolean>;
29
30
  };
31
+ readonly cells3dStatus$?: {
32
+ asObservable(): Observable<Cells3dStatus | null>;
33
+ };
30
34
  /** Observations projected to canvas pixels by the 3D camera, or null when the cloud is not mounted. */
31
35
  getSpatialScreenProjection(obs: SpatialObservations): Float32Array | null;
32
36
  /** The ids of the regions drawn over the 3D cloud in screen space (its lassos). */
@@ -45,6 +49,19 @@ export interface SpatialControlsContext {
45
49
  plotType(): PlotType;
46
50
  /** The displayed slice (a volume-backed dataset selects within one section). */
47
51
  zIndex(): number;
52
+ /**
53
+ * The dataset region set's planes while they slice an image of one plane (see the router's
54
+ * `getDatasetPlanes$`): the slice is then one of them, and a region selects within it. Optional.
55
+ */
56
+ planes?(): readonly number[] | null;
57
+ /**
58
+ * The dataset region set's planes (its `sliceZ`), whether or not they slice the image (a stack of
59
+ * as many planes is sliced by its own slices): the 2D view shows plane `zIndex()`'s transcripts.
60
+ * Optional.
61
+ */
62
+ slicePlanes?(): readonly number[] | null;
63
+ /** Emits when the plot type, the slice shown or the dataset's planes change. Optional. */
64
+ readonly viewChanged$?: Observable<unknown>;
48
65
  }
49
66
  /**
50
67
  * The spatial-omics controls (`ISpatialControls`) over a host's `SPATIAL_DATA_PORT`.
@@ -77,5 +94,47 @@ export declare class SpatialControlsFacade {
77
94
  * in its grid; by the drawn regions otherwise.
78
95
  */
79
96
  private roiSelectionMode;
97
+ /**
98
+ * The selections the "in selection" lists follow, as they change: the latest of three, as the user
99
+ * made them — the selected cells (a cell clicked, a legend group, a brush), the classes picked in
100
+ * the region editor (in spatial 3D the cell types of the type surfaces), or the regions selected on
101
+ * the image (2D only). Clearing the latest goes back to the one before, when it still stands. Emits
102
+ * (debounced) the sources standing, latest last, whenever the selection, the regions, the plane
103
+ * shown, the plot type, the dataset or `viewKey` of the view state change.
104
+ */
105
+ private selectionChanges$;
106
+ /**
107
+ * `work` as a stream: what it reports through `progress`, then its answer (or `failed`'s message);
108
+ * unsubscribing abandons it (`cancelled()` then says so).
109
+ */
110
+ private runCancellable;
111
+ /**
112
+ * What the latest selection in `active` is (see {@link selectionChanges$}), and where it applies:
113
+ * through the whole volume in spatial 3D; on the plane shown in 2D when the dataset's planes slice
114
+ * it and what is listed carries z (`hasZ`). `what` names what is listed, for the hints.
115
+ */
116
+ private resolveSelection;
117
+ /** The transcripts of the selection, by gene (see {@link selectionChanges$}). */
118
+ private transcriptsInSelection$;
119
+ /**
120
+ * Count the transcripts of the latest selection in `active`: through the whole volume in spatial
121
+ * 3D, on the plane shown in 2D when the dataset's planes slice it.
122
+ */
123
+ private transcriptsOf;
124
+ /** The observations of the selection, by group (see {@link selectionChanges$}). */
125
+ private observationsInSelection$;
126
+ /**
127
+ * The observations of the latest selection in `active`, by the grouping the observations are
128
+ * coloured by (else the cell types): every one in spatial 3D; in 2D, those on the plane shown when
129
+ * the dataset's planes slice it. One cell is described too: its id and its values.
130
+ */
131
+ private observationsOf;
132
+ /**
133
+ * The categorical column the picked classes are cell types of: the dataset's cell-type column
134
+ * when it holds any of them, else the first categorical column that does; null when none does.
135
+ */
136
+ private cellTypeColumnOf;
137
+ /** How far from a cell's centre its transcripts are looked for, in observation units. */
138
+ private cellReach;
80
139
  private build;
81
140
  }
@@ -33,7 +33,10 @@ export declare const DEFAULT_MUTED_OPACITY = 0.15;
33
33
  * Fallback categorical palette. Colour-blind-safe and stable, so a category
34
34
  * without an authored colour still lands somewhere sensible and lands there
35
35
  * every run (`fallbackColorFor` hashes the name — same name, same colour).
36
- * Okabe–Ito, plus two greys for long tails.
36
+ * Okabe–Ito and three greys, then twelve more (Tol's muted, a few of Paired), so a grouping of up
37
+ * to 22 groups (the MERFISH ileum's 20 cell types) has no two alike; the first ten come first, so a
38
+ * grouping of ten or fewer keeps its colours. jit-bioformats' `SegmentationRegionSet.PALETTE` (a 3D
39
+ * segmentation's region set, coloured at conversion) must stay this, colour for colour.
37
40
  */
38
41
  export declare const DEFAULT_CATEGORICAL_PALETTE: string[];
39
42
  interface MuteOptions {
@@ -129,4 +132,14 @@ export declare function isGrayscaleLut(lut: readonly Rgb[]): boolean;
129
132
  * them can disagree about what a colour means, whichever way the choice falls.
130
133
  */
131
134
  export declare function spatialContinuousLut(colormapValue: unknown, reverse?: boolean, override?: ColormapValue | null): Rgb[];
135
+ /**
136
+ * Fade the transcripts outside a selection, as the cells and markers are: while `selected` (an
137
+ * observation mask) selects any cell, every packed-RGBA entry of `rgba` whose cell (`ownerOf(i)`)
138
+ * is not selected, or that is in no cell, has its alpha scaled to {@link DEFAULT_MUTED_OPACITY}.
139
+ * The selection's own transcripts keep their colour. Nothing changes without a selection.
140
+ */
141
+ export declare function fadeOutsideSelection(rgba: Float32Array, count: number, ownerOf: (i: number) => number, selected: {
142
+ mask: Uint8Array;
143
+ count: number;
144
+ } | null): void;
132
145
  export {};
@@ -35,3 +35,26 @@ export type HoverSource = {
35
35
  * cell whose annotation is genuinely missing.
36
36
  */
37
37
  export declare function hoverText(source: HoverSource | null, index: number): string[] | null;
38
+ /**
39
+ * What the 3D view says of a cell under the pointer (a 3D segmentation's, drawn by itself or as
40
+ * its type's surface): its type (the cell-type column), its id, and a few of its measurements.
41
+ */
42
+ export interface CellInfo {
43
+ /** The cell-type column, its categories and each observation's code (null without one). */
44
+ typeName: string | null;
45
+ categories: readonly string[];
46
+ codes: Uint16Array | null;
47
+ /** Cells per category, by code. */
48
+ counts: Uint32Array | null;
49
+ ids?: readonly string[];
50
+ /** Measurements shown (the dataset's continuous columns, a few). */
51
+ measures: readonly {
52
+ name: string;
53
+ values: Float32Array;
54
+ unit?: string;
55
+ }[];
56
+ }
57
+ /** The tooltip of cell `index`: its type, its id, the colouring's value (when not the type), measurements. */
58
+ export declare function cellText(info: CellInfo | null, index: number, color: HoverSource | null): string[] | null;
59
+ /** The tooltip of a cell type's surface: its name (and title), and how many cells it has. */
60
+ export declare function cellTypeText(info: CellInfo | null, key: string, label?: string): string[];
@@ -0,0 +1,22 @@
1
+ import { SpatialObservations } from '../contracts/spatial-dataset.contract';
2
+ /**
3
+ * The planes a spatial dataset's region set was outlined on (its `sliceZ`, in observation units,
4
+ * one per slice in slice order), as the 2D view slices them over an image of one plane: plane `k`
5
+ * holds whatever lies nearer to it than to its neighbours, so each z belongs to exactly one plane
6
+ * and the planes together hold the whole depth.
7
+ *
8
+ * Pure, like `spatial-sections.ts` (which offers a sectioned dataset's own z values; these are the
9
+ * planes its segmentation was imaged at).
10
+ */
11
+ /**
12
+ * The z band of plane `k`: from halfway to the plane before to halfway to the one after (open
13
+ * ended past the first and the last). The planes may run either way; `[lo, hi)` comes out ordered.
14
+ */
15
+ export declare function planeBand(planes: readonly number[], k: number): [number, number];
16
+ /** Whether `z` lies in `band` (`[lo, hi)`; a non-finite z lies in none). */
17
+ export declare function inBand(z: number, band: readonly [number, number]): boolean;
18
+ /**
19
+ * Indices of the observations on plane `k` (see {@link planeBand}). Every observation is when the
20
+ * dataset carries no z: a flat dataset has nothing to slice.
21
+ */
22
+ export declare function observationsOnPlane(obs: SpatialObservations, planes: readonly number[], k: number): Uint32Array;
@@ -42,8 +42,9 @@ export declare function mutedFromSelection(selection: SpatialSelectionMask): Uin
42
42
  * the shared `geometry/ring` one the region overlays and tools use.
43
43
  */
44
44
  export declare function pointInRing(xs: readonly number[], ys: readonly number[], px: number, py: number): boolean;
45
+ export declare function inBounds(b: Bounds, px: number, py: number): boolean;
45
46
  /** A region flattened to something testable: bounds + a hit test. */
46
- interface Shape {
47
+ export interface Shape {
47
48
  bounds: Bounds;
48
49
  hit(px: number, py: number): boolean;
49
50
  }
@@ -40,6 +40,15 @@ export declare function filterTranscripts(t: SpatialTranscriptTile, px: Float32A
40
40
  merged: SpatialTranscriptTile;
41
41
  px: Float32Array;
42
42
  };
43
+ /**
44
+ * The transcripts of a tile whose z lies in `band` (`[lo, hi)`, see `planeBand`), with their
45
+ * marker sizes: the 2D view of one plane of a 3D assay. An aggregated entry stands for transcripts
46
+ * at several depths, so a tile of them is kept whole.
47
+ */
48
+ export declare function transcriptsInBand(t: SpatialTranscriptTile, px: Float32Array, band: readonly [number, number]): {
49
+ merged: SpatialTranscriptTile;
50
+ px: Float32Array;
51
+ };
43
52
  /** The median of `v`, from a sample of about 1024 values. */
44
53
  export declare function median(v: Float32Array): number;
45
54
  /** Concatenate tiles' rings into one set, dropping rings already seen (a cell straddling
@@ -0,0 +1,95 @@
1
+ import type { SpatialDataPort } from '../contracts/ports/spatial-data.port';
2
+ import { type SpatialBounds, type SpatialImageRef, type SpatialObservations, type SpatialTileLevel } from '../contracts/spatial-dataset.contract';
3
+ import type { TileKey } from './lod';
4
+ import { type Shape } from './spatial-selection';
5
+ /**
6
+ * The transcripts of a selection, by gene: the molecules of the selected cells (each transcript
7
+ * tile names the cell every molecule lies in), or those inside drawn regions — over the whole depth
8
+ * (spatial 3D) or on one plane (the 2D view of a sliced dataset).
9
+ *
10
+ * Read from the finest level of the transcript pyramid, every gene (`ALL_GENES`), and only the
11
+ * tiles the selection touches: a cell's transcripts lie near it, a region's inside its bounds.
12
+ * Pure but for the port; the facade decides what is selected.
13
+ */
14
+ /** At most this many tiles are read for one list; a selection spanning more is counted in part. */
15
+ export declare const TRANSCRIPT_LIST_MAX_TILES = 2048;
16
+ /** About this many transcripts at most are read for one list (estimated from the dataset's mean). */
17
+ export declare const TRANSCRIPT_LIST_MAX_TRANSCRIPTS = 20000000;
18
+ /**
19
+ * How far from a cell's centre its transcripts are looked for, in microns: past the largest cells'
20
+ * reach (a cell's molecules lie inside its outline; Baysor cells of the ileum are up to ~25 µm).
21
+ */
22
+ export declare const CELL_REACH_MICRONS = 30;
23
+ /**
24
+ * How many level-0 tiles one list may read: {@link TRANSCRIPT_LIST_MAX_TILES}, fewer when the
25
+ * dataset's tiles are dense (its transcripts over the tiles of its bounds), so that about
26
+ * {@link TRANSCRIPT_LIST_MAX_TRANSCRIPTS} are read at most — a whole cell type of a sparse section
27
+ * is read whole, of a dense one in part.
28
+ */
29
+ export declare function tileBudget(meta: {
30
+ bounds: SpatialBounds;
31
+ count?: number;
32
+ levels: readonly SpatialTileLevel[];
33
+ }): number;
34
+ /** One gene's transcripts in the selection. */
35
+ export interface GeneCount {
36
+ name: string;
37
+ count: number;
38
+ }
39
+ /** What {@link countTranscripts} found. */
40
+ export interface TranscriptCount {
41
+ total: number;
42
+ /** Distinct cells the counted transcripts lie in (those in no cell are not counted here). */
43
+ cells: number;
44
+ /** Genes by count, most first. */
45
+ genes: GeneCount[];
46
+ /** Some tiles could not be read (or were left out): the counts are a lower bound. */
47
+ partial: boolean;
48
+ }
49
+ /** Which transcripts count: those of these cells, or those inside these shapes (image px). */
50
+ export type TranscriptFilter = {
51
+ kind: 'cells';
52
+ mask: Uint8Array;
53
+ } | {
54
+ kind: 'shapes';
55
+ shapes: readonly Shape[];
56
+ imageRef?: SpatialImageRef;
57
+ };
58
+ /**
59
+ * Level-0 tiles within `reach` of the selected cells' centres (observation units), clipped to
60
+ * `bounds`. When there are more than `max`, those holding the most selected cells are kept and
61
+ * `partial` says so.
62
+ */
63
+ export declare function tilesAroundCells(obs: SpatialObservations, mask: Uint8Array, reach: number, levels: readonly SpatialTileLevel[], bounds: SpatialBounds | null | undefined, max?: number): {
64
+ tiles: TileKey[];
65
+ partial: boolean;
66
+ };
67
+ /**
68
+ * Level-0 tiles under `shapes` (image px, mapped to observation units through `imageRef`), clipped
69
+ * to `bounds`; at most `max`, the most covered first.
70
+ */
71
+ export declare function tilesUnderShapes(shapes: readonly Shape[], imageRef: SpatialImageRef | undefined, levels: readonly SpatialTileLevel[], bounds: SpatialBounds | null | undefined, max?: number): {
72
+ tiles: TileKey[];
73
+ partial: boolean;
74
+ };
75
+ /**
76
+ * Count the transcripts of `tiles` (level 0, every gene) that pass `filter` and, when given, lie in
77
+ * the z `band`, by gene (`names` are the dataset's genes by code, `transcriptTiles.genes`).
78
+ * Resolves null once `cancelled()` says so; a tile that fails to load leaves the count partial.
79
+ */
80
+ export declare function countTranscripts(opts: {
81
+ port: SpatialDataPort;
82
+ tiles: readonly TileKey[];
83
+ quality: 'high' | 'all';
84
+ filter: TranscriptFilter;
85
+ band?: readonly [number, number] | null;
86
+ names?: readonly string[] | null;
87
+ cancelled?: () => boolean;
88
+ /** Tiles left out before counting (see {@link tilesAroundCells}). */
89
+ partial?: boolean;
90
+ }): Promise<TranscriptCount | null>;
91
+ /** The cells of `categories` (names) in a categorical column's `codes`, as a selection mask. */
92
+ export declare function cellsOfCategories(codes: ArrayLike<number>, categories: readonly string[], names: readonly string[]): {
93
+ mask: Uint8Array;
94
+ count: number;
95
+ };
@@ -1,14 +1,14 @@
1
- import { EventEmitter, OnChanges, SimpleChanges } from '@angular/core';
1
+ import { OnChanges, SimpleChanges } from '@angular/core';
2
2
  import type { ISpatialControls } from '../../contracts/visualizer.contract';
3
3
  import type { SpatialDataset } from '../../contracts/spatial-dataset.contract';
4
- import { SpatialViewState } from '../../contracts/display-types';
4
+ import { SpatialViewState, Cells3dStatus } from '../../contracts/display-types';
5
5
  import { PanelOption } from '../../spatial/spatial-panel-model';
6
- import type { GenePickerModel } from '../spatial-gene-picker';
7
6
  import * as i0 from "@angular/core";
8
7
  /**
9
- * The Cells section, as Xenium Explorer's: the outlines' on/off switch, which boundary set
10
- * is drawn, how cells are coloured (with the gene, the colour, or the colour bar that
11
- * goes with it), the {@link SpatialGroupsPanelComponent groups}, and how cells are drawn.
8
+ * The Observations section's "Cell segmentations" part (projected into it), shown while the
9
+ * observations are shown as cells: which boundary sets are drawn and how the cells are drawn (fill,
10
+ * outline, opacity), or in 3D, by cell type or each by itself. Their colour is the section's
11
+ * shared "Colour by", the markers' too.
12
12
  *
13
13
  * Writes only through `controls.setViewState`.
14
14
  */
@@ -19,19 +19,18 @@ export declare class SpatialCellsPanelComponent implements OnChanges {
19
19
  dataset: SpatialDataset | null;
20
20
  /** The current spatial view state: what is drawn, and how. */
21
21
  view: SpatialViewState;
22
- /** The gene list the "Gene Expression" colouring picks from, shared with the other
23
- * gene dropdowns. */
24
- genes: GenePickerModel | null;
25
- /** The observations' continuous colour bar, shown for the gene colouring while it has one. */
26
- colorBarCss: string | null;
27
- /** Whether the section is expanded. */
28
- open: boolean;
29
- /** Asks to open or close it; two-way with `open`. */
30
- readonly openChange: EventEmitter<boolean>;
31
- /** Virtual-scrolled only past this many options: the scroller earns its complexity for
32
- * a few thousand names, and for eight it adds only overhead — a virtual viewport that
33
- * short swallows the clicks it is meant to forward. */
34
- protected readonly geneVirtualScrollFrom = 200;
22
+ /**
23
+ * In the 3D view: the cells are a 3D segmentation's, drawn by cell type or each by itself, and
24
+ * the 2D boundaries and draw mode do not apply.
25
+ */
26
+ is3d: boolean;
27
+ /** The 3D view's individual cells as they stand (null: none drawn). */
28
+ cells3dStatus: Cells3dStatus | null;
29
+ /** How the 3D view draws the cells: one surface per cell type, or each cell by itself. */
30
+ protected readonly cells3dOptions: PanelOption<SpatialViewState['cells3d']>[];
31
+ protected onCells3d(mode: SpatialViewState['cells3d']): void;
32
+ /** What the 3D cells' status line says, or null. */
33
+ protected get cells3dHint(): string | null;
35
34
  protected readonly cellDrawOptions: PanelOption<SpatialViewState['cellDraw']>[];
36
35
  /**
37
36
  * Option lists for the cell controls. Built once per dataset rather than in getters: a
@@ -48,11 +47,6 @@ export declare class SpatialCellsPanelComponent implements OnChanges {
48
47
  name: string;
49
48
  label: string;
50
49
  }[];
51
- /** Cell colour modes on offer (Xenium Explorer's "Cell Color"). */
52
- protected cellColorOptions: PanelOption<SpatialViewState['cellColorMode']>[];
53
- /** The density colour bar, rebuilt only when its colormap changes (a 256-entry LUT). */
54
- protected densityColorBarCss: string;
55
- private densityBarFor;
56
50
  ngOnChanges(changes: SimpleChanges): void;
57
51
  /** Whether outlines are on — the explicit choice, or automatically for data that has them. */
58
52
  protected get cellsOn(): boolean;
@@ -73,9 +67,6 @@ export declare class SpatialCellsPanelComponent implements OnChanges {
73
67
  protected onCellDraw(draw: SpatialViewState['cellDraw']): void;
74
68
  protected onCellOpacity(value: number | undefined): void;
75
69
  protected onCellOpacityPercent(v: number | null): void;
76
- protected onCellColorMode(mode: SpatialViewState['cellColorMode']): void;
77
- protected onCellColorGene(gene: string | null): void;
78
- protected onCellSingleColor(hex: string): void;
79
70
  static ɵfac: i0.ɵɵFactoryDeclaration<SpatialCellsPanelComponent, never>;
80
- static ɵcmp: i0.ɵɵComponentDeclaration<SpatialCellsPanelComponent, "spatial-cells-panel", never, { "controls": { "alias": "controls"; "required": false; }; "dataset": { "alias": "dataset"; "required": false; }; "view": { "alias": "view"; "required": false; }; "genes": { "alias": "genes"; "required": false; }; "colorBarCss": { "alias": "colorBarCss"; "required": false; }; "open": { "alias": "open"; "required": false; }; }, { "openChange": "openChange"; }, never, never, true, never>;
71
+ static ɵcmp: i0.ɵɵComponentDeclaration<SpatialCellsPanelComponent, "spatial-cells-panel", never, { "controls": { "alias": "controls"; "required": false; }; "dataset": { "alias": "dataset"; "required": false; }; "view": { "alias": "view"; "required": false; }; "is3d": { "alias": "is3d"; "required": false; }; "cells3dStatus": { "alias": "cells3dStatus"; "required": false; }; }, {}, never, never, true, never>;
81
72
  }
@@ -0,0 +1,64 @@
1
+ import { EventEmitter, OnChanges, SimpleChanges } from '@angular/core';
2
+ import type { ISpatialControls } from '../../contracts/visualizer.contract';
3
+ import type { SpatialDataset } from '../../contracts/spatial-dataset.contract';
4
+ import { ColormapNode, SpatialViewState } from '../../contracts/display-types';
5
+ import type { PanelOption } from '../../spatial/spatial-panel-model';
6
+ import type { GenePickerModel } from '../spatial-gene-picker';
7
+ import type { SpatialLegendEntry } from '../spatial-key/spatial-key.model';
8
+ import * as i0 from "@angular/core";
9
+ /** What colours the observations: a grouping, a gene, a measurement, or one colour. */
10
+ export type ColorByMode = 'group' | 'gene' | 'measure' | 'single';
11
+ /**
12
+ * The Observations section's "Colour by": one colouring for the markers and the cells alike —
13
+ * a grouping (the {@link SpatialGroupsPanelComponent groups} with their colours and switches),
14
+ * one gene's expression, a measurement (a numeric column), or one colour. Each choice writes
15
+ * the markers' colour source (`colorBy`) and the cells' (`cellColorMode` and its own fields)
16
+ * together, so the two cannot disagree.
17
+ *
18
+ * Writes only through `controls.setViewState`.
19
+ */
20
+ export declare class SpatialColorByComponent implements OnChanges {
21
+ /** The spatial controls this panel reads and writes through; null without a `SPATIAL_DATA_PORT`. */
22
+ controls: ISpatialControls | null;
23
+ /** The dataset on offer, or null. */
24
+ dataset: SpatialDataset | null;
25
+ /** The current spatial view state. */
26
+ view: SpatialViewState;
27
+ /** The gene list the gene colouring picks from, shared with the other gene dropdowns. */
28
+ genes: GenePickerModel | null;
29
+ /** The key's categorical legend, or null (continuous). */
30
+ legend: SpatialLegendEntry[] | null;
31
+ /** The key's continuous colour bar (a CSS gradient), or null. */
32
+ colorBarCss: string | null;
33
+ /** The selected category (its code), for highlighting its group. */
34
+ selectedCategory: number | null;
35
+ /** Colormap tree for the continuous colour scale. */
36
+ colormapOptions: ColormapNode[];
37
+ /** A group was clicked: its category's code, to select its observations. */
38
+ readonly categoryClicked: EventEmitter<number>;
39
+ /** Virtual-scrolled only past this many options (see the gene dropdowns elsewhere). */
40
+ protected readonly geneVirtualScrollFrom = 200;
41
+ /** The modes the dataset can be coloured in. */
42
+ protected modeOptions: PanelOption<ColorByMode>[];
43
+ /** The dataset's numeric columns. */
44
+ protected measureOptions: PanelOption<string>[];
45
+ /** A mode picked before its gene or measurement is: shown, nothing written yet. */
46
+ private pending;
47
+ ngOnChanges(changes: SimpleChanges): void;
48
+ /** The mode on show: one picked and waiting for its value, else what the view is coloured by. */
49
+ protected get mode(): ColorByMode | null;
50
+ /** What the view is coloured by, as a mode; null for the flat default. */
51
+ private get viewMode();
52
+ /** The gene the observations are coloured by, or null. */
53
+ protected get selectedGene(): string | null;
54
+ /** The measurement the observations are coloured by, or null. */
55
+ protected get selectedMeasure(): string | null;
56
+ protected onMode(mode: ColorByMode | null): void;
57
+ /** Colour the markers and the cells by gene `name`. */
58
+ protected onGene(name: string | null): void;
59
+ /** Colour the markers and the cells by measurement `name`. */
60
+ protected onMeasure(name: string | null): void;
61
+ protected onSingleColor(hex: string): void;
62
+ static ɵfac: i0.ɵɵFactoryDeclaration<SpatialColorByComponent, never>;
63
+ static ɵcmp: i0.ɵɵComponentDeclaration<SpatialColorByComponent, "spatial-color-by", never, { "controls": { "alias": "controls"; "required": false; }; "dataset": { "alias": "dataset"; "required": false; }; "view": { "alias": "view"; "required": false; }; "genes": { "alias": "genes"; "required": false; }; "legend": { "alias": "legend"; "required": false; }; "colorBarCss": { "alias": "colorBarCss"; "required": false; }; "selectedCategory": { "alias": "selectedCategory"; "required": false; }; "colormapOptions": { "alias": "colormapOptions"; "required": false; }; }, { "categoryClicked": "categoryClicked"; }, never, never, true, never>;
64
+ }
@@ -1,7 +1,7 @@
1
1
  import { EventEmitter, NgZone, OnInit } from '@angular/core';
2
2
  import { IVisualizer, ISpatialControls, RoiSelectionMode } from '../contracts/visualizer.contract';
3
3
  import { SpatialDataset } from '../contracts/spatial-dataset.contract';
4
- import { ColormapNode, SpatialViewState } from '../contracts/display-types';
4
+ import { Cells3dStatus, ColormapNode, SpatialViewState } from '../contracts/display-types';
5
5
  import { PanelOption, parseGeneGroups } from '../spatial/spatial-panel-model';
6
6
  import { SpatialSelectionMask } from '../spatial/spatial-selection';
7
7
  import { GenePickerModel } from './spatial-gene-picker';
@@ -137,14 +137,29 @@ export declare class SpatialControlsComponent implements OnInit {
137
137
  protected get hasSelection(): boolean;
138
138
  /** Boundaries on offer: tiled (level-of-detail) or whole-dataset rings. */
139
139
  protected get hasCells(): boolean;
140
+ /** The 3D view's individual cells as they stand (null: none drawn). */
141
+ protected cells3dStatus: Cells3dStatus | null;
142
+ /**
143
+ * Whether the router has the dataset's region set attached and placed (null: it does not say).
144
+ * See {@link hasCells3d}.
145
+ */
146
+ protected cells3dAvailable: boolean | null;
147
+ /**
148
+ * The dataset's cells can be drawn in 3D: its boundaries name a 3D segmentation's region set, and
149
+ * it is attached with its planes (else the 3D view draws no cells, and the markers stay).
150
+ */
151
+ protected get hasCells3d(): boolean;
140
152
  /** Transcripts on offer: tiles to draw, or a density map. */
141
153
  protected get hasTranscripts(): boolean;
142
154
  /** Whether the 3D cloud can draw the transcripts too: they carry z (a MERFISH volume's do). */
143
155
  protected get hasTranscripts3d(): boolean;
144
156
  protected onShowImage(on: boolean): void;
157
+ /** The reference volume, in 3D (the Volume section's switch). */
158
+ protected onShowVolume(on: boolean): void;
159
+ protected onVolumeOpacity(value: number | undefined): void;
145
160
  protected onShowAnnotations(on: boolean): void;
146
161
  /** Which collapsible sections are open. Per dialog instance, not persisted. */
147
- protected open: Record<'images' | 'cells' | 'transcripts' | 'annotations' | 'observations', boolean>;
162
+ protected open: Record<'images' | 'volume' | 'transcripts' | 'annotations' | 'observations', boolean>;
148
163
  protected toggleSection(name: keyof SpatialControlsComponent['open']): void;
149
164
  /** Expand or collapse a section — what a panel's header asks for. */
150
165
  protected setOpen(name: keyof SpatialControlsComponent['open'], on: boolean): void;
@@ -1,16 +1,18 @@
1
- import { ChangeDetectorRef, NgZone, OnChanges, SimpleChanges } from '@angular/core';
1
+ import { ChangeDetectorRef, EventEmitter, NgZone, OnChanges, SimpleChanges } from '@angular/core';
2
2
  import type { ISpatialControls } from '../../contracts/visualizer.contract';
3
3
  import type { SpatialDataset } from '../../contracts/spatial-dataset.contract';
4
4
  import { SpatialViewState } from '../../contracts/display-types';
5
5
  import { GroupOptionSection, GroupRow, PanelOption } from '../../spatial/spatial-panel-model';
6
6
  import * as i0 from "@angular/core";
7
7
  /**
8
- * The cells' grouping, as Xenium Explorer's Groups section: the group picker (columns under
9
- * their section heading, a k-means family once, with its k beside it), CSV import of a new
8
+ * The observations' grouping, as Xenium Explorer's Groups section: the group picker (columns
9
+ * under their section heading, a k-means family once, with its k beside it), CSV import of a new
10
10
  * grouping, and the grouping's categories with their colours (each one's swatch opens a colour
11
- * picker), cell counts and show/hide switches.
11
+ * picker), cell counts and show/hide switches. A group's name selects its observations.
12
12
  *
13
- * Writes only through `controls.setViewState` (`cellTypeColumn`, `hiddenGroups`, `groupColors`).
13
+ * The Observations section's "Colour by" in Group mode: the grouping colours the markers and the
14
+ * cells alike. Writes only through `controls.setViewState` (`cellTypeColumn` with `colorBy` and
15
+ * `cellColorMode`, `hiddenGroups`, `groupColors`).
14
16
  */
15
17
  export declare class SpatialGroupsPanelComponent implements OnChanges {
16
18
  private readonly zone;
@@ -21,6 +23,10 @@ export declare class SpatialGroupsPanelComponent implements OnChanges {
21
23
  dataset: SpatialDataset | null;
22
24
  /** The current spatial view state: what is drawn, and how. */
23
25
  view: SpatialViewState;
26
+ /** The category selected (its code in the grouping), for highlighting its row. */
27
+ selectedCategory: number | null;
28
+ /** A group's name was clicked: its category's code in the grouping, to select its observations. */
29
+ readonly categoryClicked: EventEmitter<number>;
24
30
  /**
25
31
  * The group picker: categorical columns under their section heading, a family of
26
32
  * variants (k-means at k = 2…10) listed once. Values are a column name, or
@@ -53,6 +59,10 @@ export declare class SpatialGroupsPanelComponent implements OnChanges {
53
59
  protected onGroupEntry(value: string): void;
54
60
  protected onGroupVariant(name: string): void;
55
61
  onCellTypeColumn(name: string | null): void;
62
+ /** Group `label`'s category code in the active grouping, or -1. */
63
+ protected codeOf(label: string): number;
64
+ /** Select (or, selected already, clear) group `label`'s observations. */
65
+ protected onGroupClicked(label: string): void;
56
66
  /** {@link SpatialViewState.hiddenGroups} as a set, for the per-row checks. */
57
67
  private hiddenGroups;
58
68
  protected isGroupShown(label: string): boolean;
@@ -79,5 +89,5 @@ export declare class SpatialGroupsPanelComponent implements OnChanges {
79
89
  /** Apply an async result inside the zone and re-render this OnPush panel. */
80
90
  private apply;
81
91
  static ɵfac: i0.ɵɵFactoryDeclaration<SpatialGroupsPanelComponent, never>;
82
- static ɵcmp: i0.ɵɵComponentDeclaration<SpatialGroupsPanelComponent, "spatial-groups-panel", never, { "controls": { "alias": "controls"; "required": false; }; "dataset": { "alias": "dataset"; "required": false; }; "view": { "alias": "view"; "required": false; }; }, {}, never, never, true, never>;
92
+ static ɵcmp: i0.ɵɵComponentDeclaration<SpatialGroupsPanelComponent, "spatial-groups-panel", never, { "controls": { "alias": "controls"; "required": false; }; "dataset": { "alias": "dataset"; "required": false; }; "view": { "alias": "view"; "required": false; }; "selectedCategory": { "alias": "selectedCategory"; "required": false; }; }, { "categoryClicked": "categoryClicked"; }, never, never, true, never>;
83
93
  }