@jax-data-science/sci-image-visualizer 0.2.0 → 0.2.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.
- package/esm2022/lib/contracts/plot-type.mjs +2 -2
- package/esm2022/lib/implementations/napari-js/napari-visualizer.service.mjs +15 -4
- package/esm2022/lib/visualizer.component.mjs +7 -2
- package/fesm2022/jax-data-science-sci-image-visualizer.mjs +21 -5
- package/fesm2022/jax-data-science-sci-image-visualizer.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -166,7 +166,7 @@ const PLOT_TYPE_DESCRIPTORS = {
|
|
|
166
166
|
// ── napari-js WebGPU (jit-ui#102). The 3D types take a runtime decimate factor. ──
|
|
167
167
|
[PlotType.NAPARI_IMAGE]: { type: PlotType.NAPARI_IMAGE, label: 'Image (napari · WebGPU)', icon: 'pi pi-image', dimensions: '2d', source: 'image' },
|
|
168
168
|
[PlotType.NAPARI_SCATTER]: { type: PlotType.NAPARI_SCATTER, label: 'Scatter 2D (napari · WebGPU)', icon: 'pi pi-chart-scatter', dimensions: '2d', source: 'regions' },
|
|
169
|
-
[PlotType.NAPARI_SURFACE]: { type: PlotType.NAPARI_SURFACE, label: 'Surface (napari · WebGPU)', productionLabel: 'Surface', icon: 'assets/plotting/surface.svg', dimensions: '3d', source: 'image',
|
|
169
|
+
[PlotType.NAPARI_SURFACE]: { type: PlotType.NAPARI_SURFACE, label: 'Surface (napari · WebGPU)', productionLabel: 'Surface', icon: 'assets/plotting/surface.svg', dimensions: '3d', source: 'image' }, // a height-field is z=intensity of one plane — works for any grayscale/RGB image (RGB→luminance), no stack needed
|
|
170
170
|
[PlotType.NAPARI_SCATTER3D]: { type: PlotType.NAPARI_SCATTER3D, label: 'Scatter 3D (napari · WebGPU)', icon: 'assets/plotting/3d-coordinates.svg', dimensions: '3d', source: 'image', requiresStack: true, requiresGrayscale: true },
|
|
171
171
|
[PlotType.NAPARI_VOLUME]: { type: PlotType.NAPARI_VOLUME, label: 'Volume (napari · WebGPU)', productionLabel: 'Volume', icon: 'assets/plotting/cube-3d.svg', dimensions: '3d', source: 'image', requiresStack: true, requiresGrayscale: true },
|
|
172
172
|
[PlotType.NAPARI_ISOSURFACE]: { type: PlotType.NAPARI_ISOSURFACE, label: 'Isosurface (napari · WebGPU)', productionLabel: 'Isosurface', icon: 'assets/plotting/isosurface.svg', dimensions: '3d', source: 'image', requiresStack: true, requiresGrayscale: true },
|
|
@@ -6720,6 +6720,11 @@ class VisualizerComponent {
|
|
|
6720
6720
|
const caps = this.plotService.capabilities;
|
|
6721
6721
|
const isStack = !!this.imageInfo?.isStack;
|
|
6722
6722
|
const isGrayscale = !!this.imageInfo?.isGrayscale;
|
|
6723
|
+
// A multichannel image's bands are each single-band (scalar), so the scalar
|
|
6724
|
+
// plot modes (Heatmap / Surface / Volume / Isosurface) apply per channel even
|
|
6725
|
+
// though the RGB composite isn't grayscale — don't gate them out.
|
|
6726
|
+
const m0 = this.imageInfo?.imageMeta?.[0];
|
|
6727
|
+
const isMultichannel = (m0?.channelCount ?? 1) > 1 && (m0?.rgbChannels ?? 1) < 3;
|
|
6723
6728
|
this.plotTypeOptions = this.plotService.getPlotTypeDescriptors()
|
|
6724
6729
|
.filter((d) => {
|
|
6725
6730
|
// Outside test mode, only the curated set (those with a productionLabel)
|
|
@@ -6730,7 +6735,7 @@ class VisualizerComponent {
|
|
|
6730
6735
|
return false;
|
|
6731
6736
|
if (d.requiresStack && !isStack)
|
|
6732
6737
|
return false;
|
|
6733
|
-
if (d.requiresGrayscale && !isGrayscale)
|
|
6738
|
+
if (d.requiresGrayscale && !isGrayscale && !isMultichannel)
|
|
6734
6739
|
return false;
|
|
6735
6740
|
return true;
|
|
6736
6741
|
})
|
|
@@ -18877,7 +18882,13 @@ class NapariVisualizerService extends BaseStoreVisualizer {
|
|
|
18877
18882
|
// beyond that one file's own extent).
|
|
18878
18883
|
const info = this.loaded?.imageInfo;
|
|
18879
18884
|
if (this.simpleStack.isSimple(info)) {
|
|
18880
|
-
|
|
18885
|
+
// Serverless multichannel volume: fetch the requested channel's OWN plane
|
|
18886
|
+
// (channelUrls[z][channel]) so each band stays distinct — the client-side
|
|
18887
|
+
// analog of the server's per-channel /tile?channel=c. Else the z-anchor URL.
|
|
18888
|
+
const chUrls = info.channelUrls;
|
|
18889
|
+
const url = channel != null && chUrls?.[z]?.[channel] != null
|
|
18890
|
+
? chUrls[z][channel]
|
|
18891
|
+
: this.simpleStack.urlFor(info, z);
|
|
18881
18892
|
if (!url)
|
|
18882
18893
|
throw new Error(`[napari-js] no URL for slice ${z}`);
|
|
18883
18894
|
return this.simpleStack.fetchAsBitmap(url);
|
|
@@ -19487,8 +19498,13 @@ class NapariVisualizerService extends BaseStoreVisualizer {
|
|
|
19487
19498
|
async mountVolume(viewer, info, plotType) {
|
|
19488
19499
|
const token = this.loadToken; // bail before rendering if a Cancel / new plot bumps this
|
|
19489
19500
|
const desc = await this.ensureDescriptor();
|
|
19490
|
-
|
|
19491
|
-
|
|
19501
|
+
// Serverless multichannel (tiled:false + channelUrls): no tile descriptor, so
|
|
19502
|
+
// derive the channel count from imageMeta and assemble each band from its own
|
|
19503
|
+
// channelUrls[z][c] plane (fetchSlice does the per-channel routing).
|
|
19504
|
+
const simpleMc = this.simpleStack.isSimple(info) && !!info?.channelUrls?.length
|
|
19505
|
+
&& (info?.imageMeta?.[0]?.channelCount ?? 1) > 1;
|
|
19506
|
+
const channelCount = simpleMc ? info.imageMeta[0].channelCount : (desc?.channels ?? 1);
|
|
19507
|
+
const multichannel = simpleMc || (!!desc?.multichannel && channelCount > 1);
|
|
19492
19508
|
const res = volumeResolutionFor(this.resolutionScale);
|
|
19493
19509
|
const rendering = isNapariIsosurface(plotType) ? 'iso' : 'mip';
|
|
19494
19510
|
const states = this.store.currentChannelStates();
|