@vitessce/launcher 4.0.0-test.3 → 4.0.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 (34) hide show
  1. package/dist/{GeometryAndMeshXR-arbhswbx.js → GeometryAndMeshXR-BTEzmbOK.js} +2 -2
  2. package/dist/{ReactNeuroglancer-BsqPWpQJ.js → ReactNeuroglancer-Bw5gQWL3.js} +1 -1
  3. package/dist/{XREnterButton-vmEhdF4L.js → XREnterButton-Cy5hojS1.js} +1 -1
  4. package/dist/{XRSceneComponents-DnZLSAJz.js → XRSceneComponents-BTW4vULD.js} +3 -1
  5. package/dist/{XRWrapper-C94X82Mb.js → XRWrapper-BFmCjZo_.js} +3 -2
  6. package/dist/{deflate-0ecBfpbE.js → deflate-Bbx7Vqb7.js} +1 -1
  7. package/dist/{higlass-DjFeS4wB.js → higlass-C6IxqTVD.js} +1 -1
  8. package/dist/{index-BsUxdbVL.js → index-BSOXpbtb.js} +7 -6
  9. package/dist/{index-6Oxzw9ho.js → index-BlOIc49f.js} +18 -6
  10. package/dist/{index-DAhtQMo7.js → index-DYR0bplz.js} +447 -220
  11. package/dist/index.js +1 -1
  12. package/dist/{jpeg-BegTw2ZG.js → jpeg-Co4ZcifY.js} +1 -1
  13. package/dist/{lerc-BKy3Cqfz.js → lerc-_s2Wotdl.js} +1 -1
  14. package/dist/{lzw-CyLNGLTP.js → lzw-CKCb2yMZ.js} +1 -1
  15. package/dist/{packbits-CMdMha0h.js → packbits-BNHyrTcI.js} +1 -1
  16. package/dist/{raw-DbDdV1tN.js → raw-CCLdztVu.js} +1 -1
  17. package/dist/{webimage-DYe9qPKJ.js → webimage-BozDrenu.js} +1 -1
  18. package/dist/xrStore-D3LG-myx.js +8 -0
  19. package/dist-tsc/ControlledLauncher.js +1 -0
  20. package/dist-tsc/ControlledLauncher.js.map +1 -0
  21. package/dist-tsc/LauncherStart.js +1 -0
  22. package/dist-tsc/LauncherStart.js.map +1 -0
  23. package/dist-tsc/UncontrolledLauncher.js +1 -0
  24. package/dist-tsc/UncontrolledLauncher.js.map +1 -0
  25. package/dist-tsc/index.js +1 -0
  26. package/dist-tsc/index.js.map +1 -0
  27. package/dist-tsc/launcher-styles.js +1 -0
  28. package/dist-tsc/launcher-styles.js.map +1 -0
  29. package/dist-tsc/use-hash-param.js +1 -0
  30. package/dist-tsc/use-hash-param.js.map +1 -0
  31. package/dist-tsc/use-query-or-hash-param.js +1 -0
  32. package/dist-tsc/use-query-or-hash-param.js.map +1 -0
  33. package/package.json +9 -9
  34. package/dist/xrStore-BymedRtx.js +0 -8
@@ -4,9 +4,6 @@ import { jsx as jsx$1, jsxs, Fragment } from "react/jsx-runtime";
4
4
  import { useLoaders, useCoordinationScopes, useCoordination, useDescription, useImageData, useReady, TitleInfo, useVitessceContainer, useSetWarning, useObsSetsData, useUrls, usePlotOptionsStyles, OptionsContainer, CellColorEncodingOption, OptionSelect, useComponentHover, useComponentViewInfo, useSetComponentHover, useSetComponentViewInfo, useInitialCoordination, useDeckCanvasSize, useMultiObsLabels, useObsEmbeddingData, useFeatureSelection, useObsFeatureMatrixIndices, useFeatureLabelsData, useExpandedFeatureLabelsMap, useSampleSetsData, useSampleEdgesData, useGetObsInfo, useUint8FeatureSelection, useExpressionValueGetter, useAuxiliaryCoordination, useHasLoader, useObsLocationsData, useObsLabelsData, useObsSegmentationsData, useNeighborhoodsData, useMergeCoordination, useCoordinationScopesBy, useMultiCoordinationScopesSecondaryNonNull, useMultiCoordinationScopesNonNull, useComplexCoordination, useComplexCoordinationSecondary, useGridItemSize, useMultiObsPoints, usePointMultiObsLabels, usePointMultiObsFeatureMatrixIndices, useMultiObsSpots, useSpotMultiObsSets, useSpotMultiFeatureLabels, useSpotMultiFeatureSelection, useSpotMultiObsFeatureMatrixIndices, useSegmentationMultiObsLocations, useMultiObsSegmentations, useSegmentationMultiObsSets, useSegmentationMultiFeatureSelection, useSegmentationMultiObsFeatureMatrixIndices, useMultiImages, useObsFeatureMatrixData, useUint8ObsFeatureMatrix, useGetObsMembership, PopperMenu, useComponentLayout, useClosestVitessceContainerSize, useWindowDimensions, useRemoveImageChannelInMetaCoordinationScopes, useAddImageChannelInMetaCoordinationScopes, useViewConfigStoreApi, useViewConfig, useSetViewConfig, createLoaders, useWarning, useGenomicProfilesData, useMatchingLoader, useColumnNameMapping, useFeatureStatsData, useObsSetStatsData, useAsyncFunction, useFeatureSetStatsData, useComparisonMetadata, logConfig, VitSContainer, createOnDrop } from "@vitessce/vit-s";
5
5
  import * as ReactDOM from "react-dom";
6
6
  import ReactDOM__default, { createPortal } from "react-dom";
7
- import { Quaternion as Quaternion$1, Euler as Euler$1 } from "three";
8
- import { GLTFLoader as GLTFLoader$1 } from "three/addons/loaders/GLTFLoader.js";
9
- import { DRACOLoader } from "three/addons/loaders/DRACOLoader.js";
10
7
  function _mergeNamespaces(n3, m2) {
11
8
  for (var i2 = 0; i2 < m2.length; i2++) {
12
9
  const e3 = m2[i2];
@@ -5881,7 +5878,7 @@ function baseClamp(number2, lower2, upper) {
5881
5878
  }
5882
5879
  return number2;
5883
5880
  }
5884
- function clamp$7(number2, lower2, upper) {
5881
+ function clamp$8(number2, lower2, upper) {
5885
5882
  if (upper === void 0) {
5886
5883
  upper = lower2;
5887
5884
  lower2 = void 0;
@@ -10213,6 +10210,7 @@ const FileType$1 = {
10213
10210
  OBS_LABELS_MUDATA_ZARR: "obsLabels.mudata.zarr",
10214
10211
  FEATURE_LABELS_MUDATA_ZARR: "featureLabels.mudata.zarr",
10215
10212
  GENOMIC_PROFILES_ZARR: "genomic-profiles.zarr",
10213
+ GENOMIC_PROFILES_ZARR_ZIP: "genomic-profiles.zarr.zip",
10216
10214
  NEIGHBORHOODS_JSON: "neighborhoods.json",
10217
10215
  // OME-TIFF
10218
10216
  IMAGE_OME_TIFF: "image.ome-tiff",
@@ -10384,6 +10382,7 @@ const CoordinationType$1 = {
10384
10382
  SPATIAL_CHANNEL_LABELS_VISIBLE: "spatialChannelLabelsVisible",
10385
10383
  SPATIAL_CHANNEL_LABELS_ORIENTATION: "spatialChannelLabelsOrientation",
10386
10384
  SPATIAL_CHANNEL_LABEL_SIZE: "spatialChannelLabelSize",
10385
+ SPATIAL_CHANNELS_SORT_ORDER: "spatialChannelsSortOrder",
10387
10386
  // Multi-sample / comparative
10388
10387
  SAMPLE_TYPE: "sampleType",
10389
10388
  SAMPLE_SELECTION: "sampleSelection",
@@ -10436,7 +10435,9 @@ const ViewHelpMapping = {
10436
10435
  OBS_SET_COMPOSITION_BAR_PLOT: "The set composition bar plot displays the results of a compositional analysis conducted using the scCODA method (Büttner et al. 2021 Nature Communications).",
10437
10436
  FEATURE_SET_ENRICHMENT_BAR_PLOT: "The feature set enrichment bar plot displays the results of a hypergeometric test applied to the differential expression test results to identify enriched pathway gene sets.",
10438
10437
  SAMPLE_SET_PAIR_MANAGER: "Select pairs of sample groups.",
10439
- FEATURE_STATS_TABLE: "This table displays per-feature statistics, for example, from a differential expression test."
10438
+ FEATURE_STATS_TABLE: "This table displays per-feature statistics, for example, from a differential expression test.",
10439
+ LAYER_CONTROLLER_BETA: "The spatial layer controller provides an interface for manipulating the visualization layers displayed in the spatial view.",
10440
+ SPATIAL_BETA: "The spatial view displays (potentially layered) spatially-resolved data including RGB or multiplexed images, segmentations of observations (bitmask- or polygon-based), and/or points (e.g., representing FISH transcripts)."
10440
10441
  };
10441
10442
  ({
10442
10443
  // For new file types
@@ -10507,6 +10508,7 @@ const ViewHelpMapping = {
10507
10508
  [FileType$1.OBS_LABELS_MOLECULES_JSON]: DataType$3.OBS_LABELS,
10508
10509
  // For old file types
10509
10510
  [FileType$1.GENOMIC_PROFILES_ZARR]: DataType$3.GENOMIC_PROFILES,
10511
+ [FileType$1.GENOMIC_PROFILES_ZARR_ZIP]: DataType$3.GENOMIC_PROFILES,
10510
10512
  [FileType$1.NEIGHBORHOODS_JSON]: DataType$3.NEIGHBORHOODS
10511
10513
  });
10512
10514
  ({
@@ -10671,6 +10673,10 @@ const ALT_ZARR_STORE_TYPES = {
10671
10673
  },
10672
10674
  [FileType$1.OBS_EMBEDDING_SPATIALDATA_ZARR]: {
10673
10675
  zip: FileType$1.OBS_EMBEDDING_SPATIALDATA_ZARR_ZIP
10676
+ },
10677
+ // For genomic profiles:
10678
+ [FileType$1.GENOMIC_PROFILES_ZARR]: {
10679
+ zip: FileType$1.GENOMIC_PROFILES_ZARR_ZIP
10674
10680
  }
10675
10681
  };
10676
10682
  [
@@ -10982,6 +10988,7 @@ const COMPONENT_COORDINATION_TYPES = {
10982
10988
  CoordinationType$1.SPATIAL_CHANNEL_LABELS_VISIBLE,
10983
10989
  CoordinationType$1.SPATIAL_CHANNEL_LABELS_ORIENTATION,
10984
10990
  CoordinationType$1.SPATIAL_CHANNEL_LABEL_SIZE,
10991
+ CoordinationType$1.SPATIAL_CHANNELS_SORT_ORDER,
10985
10992
  CoordinationType$1.PHOTOMETRIC_INTERPRETATION
10986
10993
  ],
10987
10994
  [ViewType$1.HEATMAP]: [
@@ -11163,7 +11170,8 @@ const COMPONENT_COORDINATION_TYPES = {
11163
11170
  CoordinationType$1.LEGEND_VISIBLE,
11164
11171
  CoordinationType$1.SPATIAL_CHANNEL_LABELS_VISIBLE,
11165
11172
  CoordinationType$1.SPATIAL_CHANNEL_LABELS_ORIENTATION,
11166
- CoordinationType$1.SPATIAL_CHANNEL_LABEL_SIZE
11173
+ CoordinationType$1.SPATIAL_CHANNEL_LABEL_SIZE,
11174
+ CoordinationType$1.SPATIAL_CHANNELS_SORT_ORDER
11167
11175
  ],
11168
11176
  [ViewType$1.GENOMIC_PROFILES]: [
11169
11177
  CoordinationType$1.DATASET,
@@ -17047,7 +17055,7 @@ function useThemeProps$1({
17047
17055
  });
17048
17056
  }
17049
17057
  const useEnhancedEffect$1 = typeof window !== "undefined" ? React.useLayoutEffect : React.useEffect;
17050
- function clamp$6(val, min2 = Number.MIN_SAFE_INTEGER, max2 = Number.MAX_SAFE_INTEGER) {
17058
+ function clamp$7(val, min2 = Number.MIN_SAFE_INTEGER, max2 = Number.MAX_SAFE_INTEGER) {
17051
17059
  return Math.max(min2, Math.min(val, max2));
17052
17060
  }
17053
17061
  function clampWrapper(value2, min2 = 0, max2 = 1) {
@@ -17056,7 +17064,7 @@ function clampWrapper(value2, min2 = 0, max2 = 1) {
17056
17064
  console.error(`MUI: The value provided ${value2} is out of range [${min2}, ${max2}].`);
17057
17065
  }
17058
17066
  }
17059
- return clamp$6(value2, min2, max2);
17067
+ return clamp$7(value2, min2, max2);
17060
17068
  }
17061
17069
  function hexToRgb$1(color2) {
17062
17070
  color2 = color2.slice(1);
@@ -40923,7 +40931,7 @@ function useSlider(parameters2) {
40923
40931
  });
40924
40932
  const range2 = Array.isArray(valueDerived);
40925
40933
  let values3 = range2 ? valueDerived.slice().sort(asc) : [valueDerived];
40926
- values3 = values3.map((value2) => value2 == null ? min2 : clamp$6(value2, min2, max2));
40934
+ values3 = values3.map((value2) => value2 == null ? min2 : clamp$7(value2, min2, max2));
40927
40935
  const marks = marksProp === true && step !== null ? [...Array(Math.floor((max2 - min2) / step) + 1)].map((_, index2) => ({
40928
40936
  value: min2 + step * index2
40929
40937
  })) : marksProp || [];
@@ -40961,10 +40969,10 @@ function useSlider(parameters2) {
40961
40969
  newValue = newValue < value2 ? marksValues[marksIndex - 1] : marksValues[marksIndex + 1];
40962
40970
  }
40963
40971
  }
40964
- newValue = clamp$6(newValue, min2, max2);
40972
+ newValue = clamp$7(newValue, min2, max2);
40965
40973
  if (range2) {
40966
40974
  if (disableSwap) {
40967
- newValue = clamp$6(newValue, values3[index2 - 1] || -Infinity, values3[index2 + 1] || Infinity);
40975
+ newValue = clamp$7(newValue, values3[index2 - 1] || -Infinity, values3[index2 + 1] || Infinity);
40968
40976
  }
40969
40977
  const previousValue = newValue;
40970
40978
  newValue = setValueIndex({
@@ -41099,7 +41107,7 @@ function useSlider(parameters2) {
41099
41107
  const closestIndex = findClosest(marksValues, newValue);
41100
41108
  newValue = marksValues[closestIndex];
41101
41109
  }
41102
- newValue = clamp$6(newValue, min2, max2);
41110
+ newValue = clamp$7(newValue, min2, max2);
41103
41111
  let activeIndex = 0;
41104
41112
  if (range2) {
41105
41113
  if (!move2) {
@@ -41108,7 +41116,7 @@ function useSlider(parameters2) {
41108
41116
  activeIndex = previousIndex.current;
41109
41117
  }
41110
41118
  if (disableSwap) {
41111
- newValue = clamp$6(newValue, values3[activeIndex - 1] || -Infinity, values3[activeIndex + 1] || Infinity);
41119
+ newValue = clamp$7(newValue, values3[activeIndex - 1] || -Infinity, values3[activeIndex + 1] || Infinity);
41112
41120
  }
41113
41121
  const previousValue = newValue;
41114
41122
  newValue = setValueIndex({
@@ -49015,7 +49023,7 @@ function localStorageAvailable() {
49015
49023
  function escapeRegExp(value2) {
49016
49024
  return value2.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
49017
49025
  }
49018
- const clamp$5 = (value2, min2, max2) => Math.max(min2, Math.min(max2, value2));
49026
+ const clamp$6 = (value2, min2, max2) => Math.max(min2, Math.min(max2, value2));
49019
49027
  function range$c(from2, to) {
49020
49028
  return Array.from({
49021
49029
  length: to - from2
@@ -52721,7 +52729,7 @@ const hydrateColumnsWidth = (rawState, dimensions) => {
52721
52729
  totalFlexUnits += column2.flex;
52722
52730
  isFlex = true;
52723
52731
  } else {
52724
- computedWidth = clamp$5(column2.width || GRID_STRING_COL_DEF.width, column2.minWidth || GRID_STRING_COL_DEF.minWidth, column2.maxWidth || GRID_STRING_COL_DEF.maxWidth);
52732
+ computedWidth = clamp$6(column2.width || GRID_STRING_COL_DEF.width, column2.minWidth || GRID_STRING_COL_DEF.minWidth, column2.maxWidth || GRID_STRING_COL_DEF.maxWidth);
52725
52733
  }
52726
52734
  widthAllocatedBeforeFlex += computedWidth;
52727
52735
  }
@@ -53321,8 +53329,8 @@ const useGridVirtualScroller = () => {
53321
53329
  const maxScrollTop = Math.ceil(dimensions.minimumSize.height - dimensions.viewportOuterSize.height);
53322
53330
  const maxScrollLeft = Math.ceil(dimensions.minimumSize.width - dimensions.viewportInnerSize.width);
53323
53331
  const newScroll = {
53324
- top: clamp$5(scroller.scrollTop, 0, maxScrollTop),
53325
- left: isRtl ? clamp$5(scroller.scrollLeft, -maxScrollLeft, 0) : clamp$5(scroller.scrollLeft, 0, maxScrollLeft)
53332
+ top: clamp$6(scroller.scrollTop, 0, maxScrollTop),
53333
+ left: isRtl ? clamp$6(scroller.scrollLeft, -maxScrollLeft, 0) : clamp$6(scroller.scrollLeft, 0, maxScrollLeft)
53326
53334
  };
53327
53335
  const dx = newScroll.left - scrollPosition.current.left;
53328
53336
  const dy = newScroll.top - scrollPosition.current.top;
@@ -53760,7 +53768,7 @@ function getNearestIndexToRender(inputs, offset2, options) {
53760
53768
  if (inputs.range?.lastRowIndex && !allRowsMeasured) {
53761
53769
  allRowsMeasured = lastMeasuredIndexRelativeToAllRows >= inputs.range.lastRowIndex;
53762
53770
  }
53763
- const lastMeasuredIndexRelativeToCurrentPage = clamp$5(lastMeasuredIndexRelativeToAllRows - (inputs.range?.firstRowIndex || 0), 0, inputs.rowsMeta.positions.length);
53771
+ const lastMeasuredIndexRelativeToCurrentPage = clamp$6(lastMeasuredIndexRelativeToAllRows - (inputs.range?.firstRowIndex || 0), 0, inputs.rowsMeta.positions.length);
53764
53772
  if (allRowsMeasured || inputs.rowsMeta.positions[lastMeasuredIndexRelativeToCurrentPage] >= offset2) {
53765
53773
  return binarySearch$2(offset2, inputs.rowsMeta.positions, options);
53766
53774
  }
@@ -53844,7 +53852,7 @@ function getIndexesToRender({
53844
53852
  lastPosition: positions[positions.length - 1] + lastSize
53845
53853
  });
53846
53854
  const lastIndexPadded = binarySearch$2(lastPosition, positions);
53847
- return [clamp$5(firstIndexPadded, minFirstIndex, maxLastIndex), clamp$5(lastIndexPadded, minFirstIndex, maxLastIndex)];
53855
+ return [clamp$6(firstIndexPadded, minFirstIndex, maxLastIndex), clamp$6(lastIndexPadded, minFirstIndex, maxLastIndex)];
53848
53856
  }
53849
53857
  function areRenderContextsEqual(context1, context2) {
53850
53858
  if (context1 === context2) {
@@ -63423,7 +63431,7 @@ const useGridFocus = (apiRef, props) => {
63423
63431
  columnIndexToFocus = visibleColumns.length - 1;
63424
63432
  }
63425
63433
  }
63426
- rowIndexToFocus = clamp$5(rowIndexToFocus, 0, currentPageRows.length - 1);
63434
+ rowIndexToFocus = clamp$6(rowIndexToFocus, 0, currentPageRows.length - 1);
63427
63435
  const rowToFocus = currentPageRows[rowIndexToFocus];
63428
63436
  if (!rowToFocus) {
63429
63437
  return;
@@ -63436,7 +63444,7 @@ const useGridFocus = (apiRef, props) => {
63436
63444
  columnIndexToFocus = colSpanInfo.rightVisibleCellIndex;
63437
63445
  }
63438
63446
  }
63439
- columnIndexToFocus = clamp$5(columnIndexToFocus, 0, visibleColumns.length - 1);
63447
+ columnIndexToFocus = clamp$6(columnIndexToFocus, 0, visibleColumns.length - 1);
63440
63448
  const columnToFocus = visibleColumns[columnIndexToFocus];
63441
63449
  apiRef.current.setCellFocus(rowToFocus.id, columnToFocus.field);
63442
63450
  }, [apiRef, props.pagination, props.paginationMode]);
@@ -63549,7 +63557,7 @@ const useGridFocus = (apiRef, props) => {
63549
63557
  pagination: props.pagination,
63550
63558
  paginationMode: props.paginationMode
63551
63559
  });
63552
- const nextRow = currentPage.rows[clamp$5(lastFocusedRowIndex, 0, currentPage.rows.length - 1)];
63560
+ const nextRow = currentPage.rows[clamp$6(lastFocusedRowIndex, 0, currentPage.rows.length - 1)];
63553
63561
  nextRowId = nextRow?.id ?? null;
63554
63562
  }
63555
63563
  apiRef.current.setState((state) => _extends$c({}, state, {
@@ -67902,7 +67910,7 @@ function extractColumnWidths(apiRef, options, columns2) {
67902
67910
  const min2 = hasColumnMin ? column2.minWidth : 0;
67903
67911
  const max2 = hasColumnMax ? column2.maxWidth : Infinity;
67904
67912
  const maxContent = filteredWidths.length === 0 ? 0 : Math.max(...filteredWidths);
67905
- widthByField[column2.field] = clamp$5(maxContent, min2, max2);
67913
+ widthByField[column2.field] = clamp$6(maxContent, min2, max2);
67906
67914
  });
67907
67915
  root2.classList.remove(gridClasses.autosizing);
67908
67916
  return widthByField;
@@ -68058,7 +68066,7 @@ const useGridColumnResize = (apiRef, props) => {
68058
68066
  return;
68059
68067
  }
68060
68068
  let newWidth = computeNewWidth(initialOffsetToSeparator.current, nativeEvent.clientX, refs.columnHeaderElement.getBoundingClientRect(), resizeDirection.current);
68061
- newWidth = clamp$5(newWidth, refs.colDef.minWidth, refs.colDef.maxWidth);
68069
+ newWidth = clamp$6(newWidth, refs.colDef.minWidth, refs.colDef.maxWidth);
68062
68070
  updateWidth(newWidth);
68063
68071
  const params2 = {
68064
68072
  element: refs.columnHeaderElement,
@@ -68084,7 +68092,7 @@ const useGridColumnResize = (apiRef, props) => {
68084
68092
  return;
68085
68093
  }
68086
68094
  let newWidth = computeNewWidth(initialOffsetToSeparator.current, finger.x, refs.columnHeaderElement.getBoundingClientRect(), resizeDirection.current);
68087
- newWidth = clamp$5(newWidth, refs.colDef.minWidth, refs.colDef.maxWidth);
68095
+ newWidth = clamp$6(newWidth, refs.colDef.minWidth, refs.colDef.maxWidth);
68088
68096
  updateWidth(newWidth);
68089
68097
  const params2 = {
68090
68098
  element: refs.columnHeaderElement,
@@ -116653,7 +116661,7 @@ function acos$4(radians2, result) {
116653
116661
  function atan$3(radians2, result) {
116654
116662
  return map$3(radians2, (angle2) => Math.atan(angle2), result);
116655
116663
  }
116656
- function clamp$4(value2, min2, max2) {
116664
+ function clamp$5(value2, min2, max2) {
116657
116665
  return map$3(value2, (value3) => Math.max(min2, Math.min(max2, value3)));
116658
116666
  }
116659
116667
  function lerp$8(a2, b2, t4) {
@@ -119623,7 +119631,7 @@ class SphericalCoordinates {
119623
119631
  this.radius = length$5(v);
119624
119632
  if (this.radius > 0) {
119625
119633
  this.theta = Math.atan2(v[0], v[1]);
119626
- this.phi = Math.acos(clamp$4(v[2] / this.radius, -1, 1));
119634
+ this.phi = Math.acos(clamp$5(v[2] / this.radius, -1, 1));
119627
119635
  }
119628
119636
  return this.check();
119629
119637
  }
@@ -119878,7 +119886,7 @@ class Euler extends MathArray {
119878
119886
  order2 = order2 || this[3];
119879
119887
  switch (order2) {
119880
119888
  case Euler.XYZ:
119881
- this[1] = Math.asin(clamp$4(m13, -1, 1));
119889
+ this[1] = Math.asin(clamp$5(m13, -1, 1));
119882
119890
  if (Math.abs(m13) < ALMOST_ONE) {
119883
119891
  this[0] = Math.atan2(-m23, m33);
119884
119892
  this[2] = Math.atan2(-m12, m11);
@@ -119888,7 +119896,7 @@ class Euler extends MathArray {
119888
119896
  }
119889
119897
  break;
119890
119898
  case Euler.YXZ:
119891
- this[0] = Math.asin(-clamp$4(m23, -1, 1));
119899
+ this[0] = Math.asin(-clamp$5(m23, -1, 1));
119892
119900
  if (Math.abs(m23) < ALMOST_ONE) {
119893
119901
  this[1] = Math.atan2(m13, m33);
119894
119902
  this[2] = Math.atan2(m21, m22);
@@ -119898,7 +119906,7 @@ class Euler extends MathArray {
119898
119906
  }
119899
119907
  break;
119900
119908
  case Euler.ZXY:
119901
- this[0] = Math.asin(clamp$4(m32, -1, 1));
119909
+ this[0] = Math.asin(clamp$5(m32, -1, 1));
119902
119910
  if (Math.abs(m32) < ALMOST_ONE) {
119903
119911
  this[1] = Math.atan2(-m31, m33);
119904
119912
  this[2] = Math.atan2(-m12, m22);
@@ -119908,7 +119916,7 @@ class Euler extends MathArray {
119908
119916
  }
119909
119917
  break;
119910
119918
  case Euler.ZYX:
119911
- this[1] = Math.asin(-clamp$4(m31, -1, 1));
119919
+ this[1] = Math.asin(-clamp$5(m31, -1, 1));
119912
119920
  if (Math.abs(m31) < ALMOST_ONE) {
119913
119921
  this[0] = Math.atan2(m32, m33);
119914
119922
  this[2] = Math.atan2(m21, m11);
@@ -119918,7 +119926,7 @@ class Euler extends MathArray {
119918
119926
  }
119919
119927
  break;
119920
119928
  case Euler.YZX:
119921
- this[2] = Math.asin(clamp$4(m21, -1, 1));
119929
+ this[2] = Math.asin(clamp$5(m21, -1, 1));
119922
119930
  if (Math.abs(m21) < ALMOST_ONE) {
119923
119931
  this[0] = Math.atan2(-m23, m22);
119924
119932
  this[1] = Math.atan2(-m31, m11);
@@ -119928,7 +119936,7 @@ class Euler extends MathArray {
119928
119936
  }
119929
119937
  break;
119930
119938
  case Euler.XZY:
119931
- this[2] = Math.asin(-clamp$4(m12, -1, 1));
119939
+ this[2] = Math.asin(-clamp$5(m12, -1, 1));
119932
119940
  if (Math.abs(m12) < ALMOST_ONE) {
119933
119941
  this[0] = Math.atan2(m32, m22);
119934
119942
  this[1] = Math.atan2(m13, m11);
@@ -123072,7 +123080,7 @@ function mod$2(value2, divisor) {
123072
123080
  function lerp$3(start2, end2, step) {
123073
123081
  return step * end2 + (1 - step) * start2;
123074
123082
  }
123075
- function clamp$3(x2, min2, max2) {
123083
+ function clamp$4(x2, min2, max2) {
123076
123084
  return x2 < min2 ? min2 : x2 > max2 ? max2 : x2;
123077
123085
  }
123078
123086
  function ieLog2(x2) {
@@ -123218,7 +123226,7 @@ function getProjectionParameters(options) {
123218
123226
  cameraToSeaLevelDistance += center2[2] * scale2 / Math.cos(pitchRadians) / height2;
123219
123227
  }
123220
123228
  const fovAboveCenter = fovRadians * (0.5 + (offset2 ? offset2[1] : 0) / height2);
123221
- const topHalfSurfaceDistance = Math.sin(fovAboveCenter) * cameraToSeaLevelDistance / Math.sin(clamp$3(Math.PI / 2 - pitchRadians - fovAboveCenter, 0.01, Math.PI - 0.01));
123229
+ const topHalfSurfaceDistance = Math.sin(fovAboveCenter) * cameraToSeaLevelDistance / Math.sin(clamp$4(Math.PI / 2 - pitchRadians - fovAboveCenter, 0.01, Math.PI - 0.01));
123222
123230
  const furthestDistance = Math.sin(pitchRadians) * topHalfSurfaceDistance + cameraToSeaLevelDistance;
123223
123231
  const horizonDistance = cameraToSeaLevelDistance * 10;
123224
123232
  const farZ = Math.min(furthestDistance * farZMultiplier, horizonDistance);
@@ -123276,8 +123284,8 @@ function fitBounds(options) {
123276
123284
  } = options;
123277
123285
  const [[west, south], [east, north]] = bounds2;
123278
123286
  const padding2 = getPaddingObject(options.padding);
123279
- const nw = lngLatToWorld([west, clamp$3(north, -MAX_LATITUDE, MAX_LATITUDE)]);
123280
- const se = lngLatToWorld([east, clamp$3(south, -MAX_LATITUDE, MAX_LATITUDE)]);
123287
+ const nw = lngLatToWorld([west, clamp$4(north, -MAX_LATITUDE, MAX_LATITUDE)]);
123288
+ const se = lngLatToWorld([east, clamp$4(south, -MAX_LATITUDE, MAX_LATITUDE)]);
123281
123289
  const size2 = [Math.max(Math.abs(se[0] - nw[0]), minExtent), Math.max(Math.abs(se[1] - nw[1]), minExtent)];
123282
123290
  const targetSize = [width2 - padding2.left - padding2.right - Math.abs(offset2[0]) * 2, height2 - padding2.top - padding2.bottom - Math.abs(offset2[1]) * 2];
123283
123291
  assert$b(targetSize[0] > 0 && targetSize[1] > 0);
@@ -124567,8 +124575,8 @@ function createProjectionMatrix({
124567
124575
  top: top2 = 0,
124568
124576
  bottom: bottom2 = 0
124569
124577
  } = padding2;
124570
- const offsetX = clamp$4((left2 + width2 - right2) / 2, 0, width2) - width2 / 2;
124571
- const offsetY = clamp$4((top2 + height2 - bottom2) / 2, 0, height2) - height2 / 2;
124578
+ const offsetX = clamp$5((left2 + width2 - right2) / 2, 0, width2) - width2 / 2;
124579
+ const offsetY = clamp$5((top2 + height2 - bottom2) / 2, 0, height2) - height2 / 2;
124572
124580
  matrix2[8] -= offsetX * 2 / width2;
124573
124581
  matrix2[9] += offsetY * 2 / height2;
124574
124582
  }
@@ -124683,7 +124691,7 @@ class Viewport {
124683
124691
  projectFlat(xyz) {
124684
124692
  if (this.isGeospatial) {
124685
124693
  const result = lngLatToWorld(xyz);
124686
- result[1] = clamp$4(result[1], -318, 830);
124694
+ result[1] = clamp$5(result[1], -318, 830);
124687
124695
  return result;
124688
124696
  }
124689
124697
  return xyz;
@@ -127400,7 +127408,7 @@ class MapState extends ViewState {
127400
127408
  minZoom
127401
127409
  } = this.getViewportProps();
127402
127410
  let zoom2 = startZoom + Math.log2(scale2);
127403
- zoom2 = clamp$4(zoom2, minZoom, maxZoom);
127411
+ zoom2 = clamp$5(zoom2, minZoom, maxZoom);
127404
127412
  const zoomedViewport = this.makeViewport({
127405
127413
  ...this.getViewportProps(),
127406
127414
  zoom: zoom2
@@ -127477,13 +127485,13 @@ class MapState extends ViewState {
127477
127485
  minZoom,
127478
127486
  zoom: zoom2
127479
127487
  } = props;
127480
- props.zoom = clamp$4(zoom2, minZoom, maxZoom);
127488
+ props.zoom = clamp$5(zoom2, minZoom, maxZoom);
127481
127489
  const {
127482
127490
  maxPitch,
127483
127491
  minPitch,
127484
127492
  pitch
127485
127493
  } = props;
127486
- props.pitch = clamp$4(pitch, minPitch, maxPitch);
127494
+ props.pitch = clamp$5(pitch, minPitch, maxPitch);
127487
127495
  const {
127488
127496
  normalize: normalize2 = true
127489
127497
  } = props;
@@ -127544,7 +127552,7 @@ class MapState extends ViewState {
127544
127552
  deltaScaleY = 1 - centerY / startY;
127545
127553
  }
127546
127554
  }
127547
- deltaScaleY = clamp$4(deltaScaleY, -1, 1);
127555
+ deltaScaleY = clamp$5(deltaScaleY, -1, 1);
127548
127556
  const {
127549
127557
  minPitch,
127550
127558
  maxPitch
@@ -127673,8 +127681,8 @@ function getProjectionMatrix({
127673
127681
  top: t4 = 0,
127674
127682
  bottom: b2 = 0
127675
127683
  } = padding2;
127676
- const offsetX = clamp$4((l2 + width2 - r3) / 2, 0, width2) - width2 / 2;
127677
- const offsetY = clamp$4((t4 + height2 - b2) / 2, 0, height2) - height2 / 2;
127684
+ const offsetX = clamp$5((l2 + width2 - r3) / 2, 0, width2) - width2 / 2;
127685
+ const offsetY = clamp$5((t4 + height2 - b2) / 2, 0, height2) - height2 / 2;
127678
127686
  left2 -= offsetX;
127679
127687
  right2 -= offsetX;
127680
127688
  bottom2 += offsetY;
@@ -127987,7 +127995,7 @@ class OrbitState extends ViewState {
127987
127995
  startZoom = this.getViewportProps().zoom;
127988
127996
  }
127989
127997
  const zoom2 = startZoom + Math.log2(scale2);
127990
- return clamp$4(zoom2, minZoom, maxZoom);
127998
+ return clamp$5(zoom2, minZoom, maxZoom);
127991
127999
  }
127992
128000
  _panFromCenter(offset2) {
127993
128001
  const {
@@ -128017,8 +128025,8 @@ class OrbitState extends ViewState {
128017
128025
  minRotationX,
128018
128026
  rotationOrbit
128019
128027
  } = props;
128020
- props.zoom = Array.isArray(zoom2) ? [clamp$4(zoom2[0], minZoom, maxZoom), clamp$4(zoom2[1], minZoom, maxZoom)] : clamp$4(zoom2, minZoom, maxZoom);
128021
- props.rotationX = clamp$4(props.rotationX, minRotationX, maxRotationX);
128028
+ props.zoom = Array.isArray(zoom2) ? [clamp$5(zoom2[0], minZoom, maxZoom), clamp$5(zoom2[1], minZoom, maxZoom)] : clamp$5(zoom2, minZoom, maxZoom);
128029
+ props.rotationX = clamp$5(props.rotationX, minRotationX, maxRotationX);
128022
128030
  if (rotationOrbit < -180 || rotationOrbit > 180) {
128023
128031
  props.rotationOrbit = mod$1(rotationOrbit + 180, 360) - 180;
128024
128032
  }
@@ -128062,10 +128070,10 @@ class OrthographicState extends OrbitState {
128062
128070
  let [newZoomX, newZoomY] = startZoom;
128063
128071
  switch (this.zoomAxis) {
128064
128072
  case "X":
128065
- newZoomX = clamp$4(newZoomX + deltaZoom, minZoom, maxZoom);
128073
+ newZoomX = clamp$5(newZoomX + deltaZoom, minZoom, maxZoom);
128066
128074
  break;
128067
128075
  case "Y":
128068
- newZoomY = clamp$4(newZoomY + deltaZoom, minZoom, maxZoom);
128076
+ newZoomY = clamp$5(newZoomY + deltaZoom, minZoom, maxZoom);
128069
128077
  break;
128070
128078
  default:
128071
128079
  let z2 = Math.min(newZoomX + deltaZoom, newZoomY + deltaZoom);
@@ -128081,7 +128089,7 @@ class OrthographicState extends OrbitState {
128081
128089
  }
128082
128090
  return [newZoomX, newZoomY];
128083
128091
  }
128084
- return clamp$4(startZoom + deltaZoom, minZoom, maxZoom);
128092
+ return clamp$5(startZoom + deltaZoom, minZoom, maxZoom);
128085
128093
  }
128086
128094
  }
128087
128095
  class OrthographicController extends Controller {
@@ -136820,7 +136828,7 @@ class FirstPersonState extends ViewState {
136820
136828
  longitude: longitude2,
136821
136829
  bearing
136822
136830
  } = props;
136823
- props.pitch = clamp$4(pitch, minPitch, maxPitch);
136831
+ props.pitch = clamp$5(pitch, minPitch, maxPitch);
136824
136832
  if (longitude2 !== null && (longitude2 < -180 || longitude2 > 180)) {
136825
136833
  props.longitude = mod$1(longitude2 + 180, 360) - 180;
136826
136834
  }
@@ -136869,7 +136877,7 @@ class GlobeState extends MapState {
136869
136877
  minZoom,
136870
136878
  zoom: zoom2
136871
136879
  } = props;
136872
- props.zoom = clamp$4(zoom2, minZoom, maxZoom);
136880
+ props.zoom = clamp$5(zoom2, minZoom, maxZoom);
136873
136881
  const {
136874
136882
  longitude: longitude2,
136875
136883
  latitude
@@ -136877,7 +136885,7 @@ class GlobeState extends MapState {
136877
136885
  if (longitude2 < -180 || longitude2 > 180) {
136878
136886
  props.longitude = mod$1(longitude2 + 180, 360) - 180;
136879
136887
  }
136880
- props.latitude = clamp$4(latitude, -89, 89);
136888
+ props.latitude = clamp$5(latitude, -89, 89);
136881
136889
  return props;
136882
136890
  }
136883
136891
  }
@@ -144524,7 +144532,7 @@ function getQuantileDomain(data2, valueAccessor) {
144524
144532
  function getOrdinalDomain(data2, valueAccessor) {
144525
144533
  return unique$1(getTruthyValues(data2, valueAccessor));
144526
144534
  }
144527
- function clamp$2(value2, min2, max2) {
144535
+ function clamp$3(value2, min2, max2) {
144528
144536
  return Math.max(min2, Math.min(max2, value2));
144529
144537
  }
144530
144538
  const defaultGetValue = (points2) => points2.length;
@@ -144585,7 +144593,7 @@ class BinSorter {
144585
144593
  if (len2 < 2) {
144586
144594
  return [0, 0];
144587
144595
  }
144588
- const [lower2, upper] = percentileRange.map((n3) => clamp$2(n3, 0, 100));
144596
+ const [lower2, upper] = percentileRange.map((n3) => clamp$3(n3, 0, 100));
144589
144597
  const lowerIdx = Math.ceil(lower2 / 100 * (len2 - 1));
144590
144598
  const upperIdx = Math.floor(upper / 100 * (len2 - 1));
144591
144599
  return [lowerIdx, upperIdx];
@@ -167379,7 +167387,7 @@ new Vector3();
167379
167387
  new Vector2();
167380
167388
  new Vector2();
167381
167389
  function fromSNorm(value2, rangeMaximum = 255) {
167382
- return clamp$4(value2, 0, rangeMaximum) / rangeMaximum * 2 - 1;
167390
+ return clamp$5(value2, 0, rangeMaximum) / rangeMaximum * 2 - 1;
167383
167391
  }
167384
167392
  function signNotZero(value2) {
167385
167393
  return value2 < 0 ? -1 : 1;
@@ -206496,7 +206504,7 @@ const esm = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty(
206496
206504
  asin: asin$5,
206497
206505
  assert: assert$c,
206498
206506
  atan: atan$3,
206499
- clamp: clamp$4,
206507
+ clamp: clamp$5,
206500
206508
  clone: clone$5,
206501
206509
  config: config$3,
206502
206510
  configure,
@@ -210925,22 +210933,22 @@ async function getDecoder(fileDirectory) {
210925
210933
  const Decoder = await importFn();
210926
210934
  return new Decoder(fileDirectory);
210927
210935
  }
210928
- addDecoder([void 0, 1], () => import("./raw-DbDdV1tN.js").then((m2) => m2.default));
210929
- addDecoder(5, () => import("./lzw-CyLNGLTP.js").then((m2) => m2.default));
210936
+ addDecoder([void 0, 1], () => import("./raw-CCLdztVu.js").then((m2) => m2.default));
210937
+ addDecoder(5, () => import("./lzw-CKCb2yMZ.js").then((m2) => m2.default));
210930
210938
  addDecoder(6, () => {
210931
210939
  throw new Error("old style JPEG compression is not supported.");
210932
210940
  });
210933
- addDecoder(7, () => import("./jpeg-BegTw2ZG.js").then((m2) => m2.default));
210934
- addDecoder([8, 32946], () => import("./deflate-0ecBfpbE.js").then((m2) => m2.default));
210935
- addDecoder(32773, () => import("./packbits-CMdMha0h.js").then((m2) => m2.default));
210941
+ addDecoder(7, () => import("./jpeg-Co4ZcifY.js").then((m2) => m2.default));
210942
+ addDecoder([8, 32946], () => import("./deflate-Bbx7Vqb7.js").then((m2) => m2.default));
210943
+ addDecoder(32773, () => import("./packbits-BNHyrTcI.js").then((m2) => m2.default));
210936
210944
  addDecoder(
210937
210945
  34887,
210938
- () => import("./lerc-BKy3Cqfz.js").then(async (m2) => {
210946
+ () => import("./lerc-_s2Wotdl.js").then(async (m2) => {
210939
210947
  await m2.zstd.init();
210940
210948
  return m2;
210941
210949
  }).then((m2) => m2.default)
210942
210950
  );
210943
- addDecoder(50001, () => import("./webimage-DYe9qPKJ.js").then((m2) => m2.default));
210951
+ addDecoder(50001, () => import("./webimage-BozDrenu.js").then((m2) => m2.default));
210944
210952
  function copyNewSize(array2, width2, height2, samplesPerPixel = 1) {
210945
210953
  return new (Object.getPrototypeOf(array2)).constructor(width2 * height2 * samplesPerPixel);
210946
210954
  }
@@ -227796,7 +227804,7 @@ function ToolMenu(props) {
227796
227804
  return jsxs("div", { className: classes2.tool, children: [visibleTools.pan && jsx$1(IconTool, { alt: pointerIconAltText, onClick: () => setActiveTool(null), isActive: activeTool === null, children: jsx$1(SvgNearMe, {}) }), visibleTools.selectLasso ? jsx$1(IconTool, { alt: lassoIconAltText, onClick: () => setActiveTool(distEs6Exports$2.SELECTION_TYPE.POLYGON), isActive: activeTool === distEs6Exports$2.SELECTION_TYPE.POLYGON, children: jsx$1(SvgSelectionLasso, {}) }) : null, visibleTools.recenter ? jsx$1(IconButton, { alt: "click to recenter", onClick: () => onRecenterButtonCLick(), "aria-label": "Recenter scatterplot view", children: jsx$1(CenterFocusStrong, {}) }) : null] });
227797
227805
  }
227798
227806
  const getCursorWithTool = () => "crosshair";
227799
- const getCursor = (interactionState) => interactionState.isDragging ? "grabbing" : "default";
227807
+ const getCursor = (interactionState) => interactionState.isDragging ? "grabbing" : "grab";
227800
227808
  function getOnHoverCallback(obsIndex, setObsHighlight, setComponentHover) {
227801
227809
  return (info2) => {
227802
227810
  if (setComponentHover) {
@@ -228161,7 +228169,7 @@ const BASE_POINT_SIZE = 5;
228161
228169
  const LARGE_DATASET_CELL_COUNT = 1e4;
228162
228170
  const SMALL_DATASET_CELL_COUNT = 100;
228163
228171
  function getInitialPointSize(numCells = LARGE_DATASET_CELL_COUNT) {
228164
- return BASE_POINT_SIZE / clamp$7(numCells, SMALL_DATASET_CELL_COUNT, LARGE_DATASET_CELL_COUNT);
228172
+ return BASE_POINT_SIZE / clamp$8(numCells, SMALL_DATASET_CELL_COUNT, LARGE_DATASET_CELL_COUNT);
228165
228173
  }
228166
228174
  function getPointSizeDevicePixels(devicePixelRatio2, zoom2, xRange, yRange, width2, height2, numCells) {
228167
228175
  const pointSize = getInitialPointSize(numCells);
@@ -228174,7 +228182,7 @@ function getPointSizeDevicePixels(devicePixelRatio2, zoom2, xRange, yRange, widt
228174
228182
  const diagonalAxisRange = Math.sqrt(xAxisRange ** 2 + yAxisRange ** 2);
228175
228183
  const diagonalFraction = pointSize / diagonalAxisRange;
228176
228184
  const deviceSize = diagonalFraction * diagonalScreenSize;
228177
- const pointSizeDevicePixels = clamp$7(deviceSize, pointScreenSizeMin, pointScreenSizeMax);
228185
+ const pointSizeDevicePixels = clamp$8(deviceSize, pointScreenSizeMin, pointScreenSizeMax);
228178
228186
  return pointSizeDevicePixels;
228179
228187
  }
228180
228188
  function getPointOpacity(zoom2, xRange, yRange, width2, height2, numCells, avgFillDensity) {
@@ -228203,7 +228211,7 @@ function getPointOpacity(zoom2, xRange, yRange, width2, height2, numCells, avgFi
228203
228211
  rho = Math.min(1, 1 / 10 ** (Math.log10(N2) - 3));
228204
228212
  }
228205
228213
  const alpha2 = rho * W * H / N2 * (Y02 / Y3) * (X02 / X3);
228206
- const pointOpacity = clamp$7(alpha2, 1.01 / 255, 1);
228214
+ const pointOpacity = clamp$8(alpha2, 1.01 / 255, 1);
228207
228215
  return pointOpacity;
228208
228216
  }
228209
228217
  const CELLS_LAYER_ID$1 = "scatterplot";
@@ -228819,7 +228827,7 @@ typeof SuppressedError === "function" ? SuppressedError : function(error2, suppr
228819
228827
  var e3 = new Error(message);
228820
228828
  return e3.name = "SuppressedError", e3.error = error2, e3.suppressed = suppressed, e3;
228821
228829
  };
228822
- const FEATURE_AGGREGATION_STRATEGIES$1 = ["first", "last", "sum", "mean"];
228830
+ const FEATURE_AGGREGATION_STRATEGIES$2 = ["first", "last", "sum", "mean"];
228823
228831
  function ScatterplotOptions(props) {
228824
228832
  const { children: children3, observationsLabel, cellRadius, setCellRadius, cellRadiusMode, setCellRadiusMode, cellOpacity, setCellOpacity, cellOpacityMode, setCellOpacityMode, cellSetLabelsVisible, setCellSetLabelsVisible, tooltipsVisible, setTooltipsVisible, cellSetLabelSize, setCellSetLabelSize, cellSetPolygonsVisible, setCellSetPolygonsVisible, cellColorEncoding, setCellColorEncoding, geneExpressionColormap, setGeneExpressionColormap, geneExpressionColormapRange, setGeneExpressionColormapRange, embeddingPointsVisible, setEmbeddingPointsVisible, embeddingContoursVisible, setEmbeddingContoursVisible, embeddingContoursFilled, setEmbeddingContoursFilled, contourPercentiles, setContourPercentiles, defaultContourPercentiles, contourColorEncoding, setContourColorEncoding, featureAggregationStrategy, setFeatureAggregationStrategy } = props;
228825
228833
  const scatterplotOptionsId = $bdb11010cef70236$export$f680877a34711e37();
@@ -228944,7 +228952,7 @@ function ScatterplotOptions(props) {
228944
228952
  return "Scatterplot sliders for contour percentile thresholds";
228945
228953
  }, id: `scatterplot-contour-percentiles-${scatterplotOptionsId}`, valueLabelDisplay: "auto", step: 5e-3, min: 9e-3, max: 0.999 }) })] }), setFeatureAggregationStrategy ? jsxs(TableRow, { children: [jsx$1(TableCell, { className: classes2.labelCell, variant: "head", scope: "row", children: jsx$1("label", { htmlFor: `feature-aggregation-strategy-${scatterplotOptionsId}`, children: "Feature Aggregation Strategy" }) }), jsx$1(TableCell, { className: classes2.inputCell, variant: "body", children: jsx$1(OptionSelect, { className: classes2.select, value: featureAggregationStrategy ?? "first", onChange: handleFeatureAggregationStrategyChange, inputProps: {
228946
228954
  id: `feature-aggregation-strategy-${scatterplotOptionsId}`
228947
- }, children: FEATURE_AGGREGATION_STRATEGIES$1.map((opt) => jsx$1("option", { value: opt, children: capitalize$3(opt) }, opt)) }) })] }) : null] });
228955
+ }, children: FEATURE_AGGREGATION_STRATEGIES$2.map((opt) => jsx$1("option", { value: opt, children: capitalize$3(opt) }, opt)) }) })] }) : null] });
228948
228956
  }
228949
228957
  const useStyles$t = makeStyles()((theme) => ({
228950
228958
  tooltipAnchor: {
@@ -233616,7 +233624,7 @@ function ChannelNamesLegend(props) {
233616
233624
  }) : null });
233617
233625
  }
233618
233626
  const DEFAULT_CONTOUR_PERCENTILES = [0.09, 0.9, 0.99];
233619
- const DEFAULT_FEATURE_AGGREGATION_STRATEGY$2 = "first";
233627
+ const DEFAULT_FEATURE_AGGREGATION_STRATEGY$3 = "first";
233620
233628
  function EmbeddingScatterplotSubscriber(props) {
233621
233629
  const {
233622
233630
  uuid: uuid2,
@@ -233643,7 +233651,7 @@ function EmbeddingScatterplotSubscriber(props) {
233643
233651
  const { embeddingZoom: initialZoom, embeddingTargetX: initialTargetX, embeddingTargetY: initialTargetY } = useInitialCoordination(COMPONENT_COORDINATION_TYPES[ViewType$1.SCATTERPLOT], coordinationScopes);
233644
233652
  const observationsLabel = observationsLabelOverride || obsType;
233645
233653
  const sampleSetSelection = sampleSetSelectionFromProps || sampleSetSelectionFromCoordination;
233646
- const featureAggregationStrategyToUse = featureAggregationStrategy ?? DEFAULT_FEATURE_AGGREGATION_STRATEGY$2;
233654
+ const featureAggregationStrategyToUse = featureAggregationStrategy ?? DEFAULT_FEATURE_AGGREGATION_STRATEGY$3;
233647
233655
  const [width2, height2, deckRef] = useDeckCanvasSize();
233648
233656
  const title2 = titleOverride || `Scatterplot (${mapping})`;
233649
233657
  const [
@@ -238315,7 +238323,7 @@ function cbrt(x2) {
238315
238323
  function ceil$2(x2) {
238316
238324
  return finalise(x2 = new this(x2), x2.e + 1, 2);
238317
238325
  }
238318
- function clamp$1(x2, min2, max2) {
238326
+ function clamp$2(x2, min2, max2) {
238319
238327
  return new this(x2).clamp(min2, max2);
238320
238328
  }
238321
238329
  function config$1(obj) {
@@ -238486,7 +238494,7 @@ function clone$1(obj) {
238486
238494
  Decimal3.atan2 = atan2$2;
238487
238495
  Decimal3.cbrt = cbrt;
238488
238496
  Decimal3.ceil = ceil$2;
238489
- Decimal3.clamp = clamp$1;
238497
+ Decimal3.clamp = clamp$2;
238490
238498
  Decimal3.cos = cos$3;
238491
238499
  Decimal3.cosh = cosh;
238492
238500
  Decimal3.div = div;
@@ -252470,6 +252478,16 @@ class RelaxedFetchStore extends FetchStore {
252470
252478
  throw e3;
252471
252479
  }
252472
252480
  }
252481
+ async getRange(key2, range2, options = {}) {
252482
+ try {
252483
+ return await super.getRange(key2, range2, options);
252484
+ } catch (e3) {
252485
+ if (e3?.message?.startsWith("Unexpected response status 403") && true) {
252486
+ return void 0;
252487
+ }
252488
+ throw e3;
252489
+ }
252490
+ }
252473
252491
  }
252474
252492
  function transformEntriesForZipFileStore(entries2) {
252475
252493
  const topLevelZarrDirectories = new Set(Object.keys(entries2).map((k) => k.split("/")[0]).filter((firstPathItem) => firstPathItem?.endsWith(".zarr")));
@@ -253379,7 +253397,8 @@ let Spatial$1 = class Spatial extends AbstractSpatialOrScatterplot {
253379
253397
  "expressionData",
253380
253398
  "cellColorEncoding",
253381
253399
  "geneExpressionColormap",
253382
- "segmentationLayerCallbacks"
253400
+ "segmentationLayerCallbacks",
253401
+ "getExpressionValue"
253383
253402
  ].some(shallowDiff2)) {
253384
253403
  this.onUpdateCellsLayer();
253385
253404
  forceUpdate = true;
@@ -253439,6 +253458,7 @@ const useToggleStyles = makeStyles()(() => ({
253439
253458
  padding: "0px"
253440
253459
  }
253441
253460
  }));
253461
+ const FEATURE_AGGREGATION_STRATEGIES$1 = ["first", "last", "sum", "mean"];
253442
253462
  const ToggleFixedAxisButton = ({ setSpatialAxisFixed, spatialAxisFixed, use3d }) => {
253443
253463
  const toggleAxisId = $bdb11010cef70236$export$f680877a34711e37();
253444
253464
  const { classes: classes2 } = useToggleStyles();
@@ -253448,7 +253468,7 @@ const ToggleFixedAxisButton = ({ setSpatialAxisFixed, spatialAxisFixed, use3d })
253448
253468
  } } }) })] });
253449
253469
  };
253450
253470
  function SpatialOptions(props) {
253451
- const { observationsLabel, cellColorEncoding, setCellColorEncoding, setSpatialAxisFixed, spatialAxisFixed, use3d, tooltipsVisible, setTooltipsVisible, geneExpressionColormap, setGeneExpressionColormap, geneExpressionColormapRange, setGeneExpressionColormapRange, canShowExpressionOptions, canShowColorEncodingOption, canShow3DOptions } = props;
253471
+ const { observationsLabel, cellColorEncoding, setCellColorEncoding, setSpatialAxisFixed, spatialAxisFixed, use3d, tooltipsVisible, setTooltipsVisible, geneExpressionColormap, setGeneExpressionColormap, geneExpressionColormapRange, setGeneExpressionColormapRange, canShowExpressionOptions, canShowColorEncodingOption, canShow3DOptions, featureAggregationStrategy, setFeatureAggregationStrategy } = props;
253452
253472
  const spatialOptionsId = $bdb11010cef70236$export$f680877a34711e37();
253453
253473
  function handleGeneExpressionColormapChange(event2) {
253454
253474
  setGeneExpressionColormap(event2.target.value);
@@ -253484,7 +253504,7 @@ function SpatialOptions(props) {
253484
253504
  }, value: geneExpressionColormapRange, onChange: handleColormapRangeChangeDebounced, getAriaLabel: (index2) => {
253485
253505
  const labelPrefix = index2 === 0 ? "Low value slider" : "High value slider";
253486
253506
  return `${labelPrefix} for spatial gene expression colormap range`;
253487
- }, id: `gene-expression-colormap-range-${spatialOptionsId}`, valueLabelDisplay: "auto", step: 5e-3, min: 0, max: 1 }) })] })] }) : null] });
253507
+ }, id: `gene-expression-colormap-range-${spatialOptionsId}`, valueLabelDisplay: "auto", step: 5e-3, min: 0, max: 1 }) })] }), setFeatureAggregationStrategy ? jsxs(TableRow, { children: [jsx$1(TableCell, { className: classes2.labelCell, variant: "head", scope: "row", children: jsx$1("label", { htmlFor: `feature-aggregation-strategy-${spatialOptionsId}`, children: "Feature Aggregation Strategy" }) }), jsx$1(TableCell, { className: classes2.inputCell, variant: "body", children: jsx$1(OptionSelect, { className: classes2.select, value: featureAggregationStrategy ?? "first", onChange: (e3) => setFeatureAggregationStrategy(e3.target.value), inputProps: { id: `feature-aggregation-strategy-${spatialOptionsId}` }, children: FEATURE_AGGREGATION_STRATEGIES$1.map((opt) => jsx$1("option", { value: opt, children: capitalize$3(opt) }, opt)) }) })] }) : null] }) : null] });
253488
253508
  }
253489
253509
  function SpatialTooltipSubscriber$1(props) {
253490
253510
  const { parentUuid, obsHighlight, width: width2, height: height2, getObsInfo: getObsInfo2, hoverData, hoverCoord, hoverMode, useHoverInfoForTooltip, getObsIdFromHoverData, featureType, featureLabelsMap } = props;
@@ -253516,12 +253536,13 @@ function SpatialTooltipSubscriber$1(props) {
253516
253536
  }
253517
253537
  return cellInfo ? jsx$1(Tooltip2D, { x: x2, y: y2, parentUuid, sourceUuid, parentWidth: width2, parentHeight: height2, children: jsx$1(TooltipContent, { info: cellInfo, featureType, featureLabelsMap }) }) : null;
253518
253538
  }
253539
+ const DEFAULT_FEATURE_AGGREGATION_STRATEGY$2 = "first";
253519
253540
  function SpatialSubscriber$1(props) {
253520
253541
  const { uuid: uuid2, coordinationScopes, closeButtonVisible, downloadButtonVisible, removeGridComponent, observationsLabelOverride, subobservationsLabelOverride: subobservationsLabel = "molecule", theme, title: title2 = "Spatial", disable3d, globalDisable3d, useFullResolutionImage = {}, channelNamesVisible = false, helpText = ViewHelpMapping.SPATIAL } = props;
253521
253542
  const loaders = useLoaders();
253522
253543
  const setComponentHover = useSetComponentHover();
253523
253544
  const setComponentViewInfo = useSetComponentViewInfo(uuid2);
253524
- const [{ dataset, obsType, featureType, featureValueType, spatialZoom: zoom2, spatialTargetX: targetX2, spatialTargetY: targetY2, spatialTargetZ: targetZ, spatialRotationX: rotationX, spatialRotationY: rotationY, spatialRotationZ: rotationZ, spatialRotationOrbit: rotationOrbit, spatialOrbitAxis: orbitAxis, spatialImageLayer: imageLayers, spatialSegmentationLayer: cellsLayer, spatialPointLayer: moleculesLayer, spatialNeighborhoodLayer: neighborhoodsLayer, obsFilter: cellFilter, obsHighlight: cellHighlight, moleculeHighlight, featureSelection: geneSelection, obsSetSelection: cellSetSelection, obsSetColor: cellSetColor, obsColorEncoding: cellColorEncoding, additionalObsSets: additionalCellSets, spatialAxisFixed, featureValueColormap: geneExpressionColormap, featureValueColormapRange: geneExpressionColormapRange, tooltipsVisible, photometricInterpretation: photometricInterpretationFromCoordination }, { setSpatialZoom: setZoom, setSpatialTargetX: setTargetX, setSpatialTargetY: setTargetY, setSpatialTargetZ: setTargetZ, setSpatialRotationX: setRotationX, setSpatialRotationOrbit: setRotationOrbit, setSpatialOrbitAxis: setOrbitAxis, setSpatialImageLayer: setRasterLayers, setSpatialSegmentationLayer: setCellsLayer, setSpatialPointLayer: setMoleculesLayer, setSpatialNeighborhoodLayer: setNeighborhoodsLayer, setObsFilter: setCellFilter, setObsSetSelection: setCellSetSelection, setObsHighlight: setCellHighlight, setObsSetColor: setCellSetColor, setObsColorEncoding: setCellColorEncoding, setAdditionalObsSets: setAdditionalCellSets, setMoleculeHighlight, setSpatialAxisFixed, setFeatureValueColormap: setGeneExpressionColormap, setFeatureValueColormapRange: setGeneExpressionColormapRange, setTooltipsVisible }] = useCoordination(COMPONENT_COORDINATION_TYPES[ViewType$1.SPATIAL], coordinationScopes);
253545
+ const [{ dataset, obsType, featureType, featureValueType, spatialZoom: zoom2, spatialTargetX: targetX2, spatialTargetY: targetY2, spatialTargetZ: targetZ, spatialRotationX: rotationX, spatialRotationY: rotationY, spatialRotationZ: rotationZ, spatialRotationOrbit: rotationOrbit, spatialOrbitAxis: orbitAxis, spatialImageLayer: imageLayers, spatialSegmentationLayer: cellsLayer, spatialPointLayer: moleculesLayer, spatialNeighborhoodLayer: neighborhoodsLayer, obsFilter: cellFilter, obsHighlight: cellHighlight, moleculeHighlight, featureSelection: geneSelection, obsSetSelection: cellSetSelection, obsSetColor: cellSetColor, obsColorEncoding: cellColorEncoding, additionalObsSets: additionalCellSets, spatialAxisFixed, featureValueColormap: geneExpressionColormap, featureValueColormapRange: geneExpressionColormapRange, tooltipsVisible, photometricInterpretation: photometricInterpretationFromCoordination, featureAggregationStrategy }, { setSpatialZoom: setZoom, setSpatialTargetX: setTargetX, setSpatialTargetY: setTargetY, setSpatialTargetZ: setTargetZ, setSpatialRotationX: setRotationX, setSpatialRotationOrbit: setRotationOrbit, setSpatialOrbitAxis: setOrbitAxis, setSpatialImageLayer: setRasterLayers, setSpatialSegmentationLayer: setCellsLayer, setSpatialPointLayer: setMoleculesLayer, setSpatialNeighborhoodLayer: setNeighborhoodsLayer, setObsFilter: setCellFilter, setObsSetSelection: setCellSetSelection, setObsHighlight: setCellHighlight, setObsSetColor: setCellSetColor, setObsColorEncoding: setCellColorEncoding, setAdditionalObsSets: setAdditionalCellSets, setMoleculeHighlight, setSpatialAxisFixed, setFeatureValueColormap: setGeneExpressionColormap, setFeatureValueColormapRange: setGeneExpressionColormapRange, setTooltipsVisible, setFeatureAggregationStrategy }] = useCoordination(COMPONENT_COORDINATION_TYPES[ViewType$1.SPATIAL], coordinationScopes);
253525
253546
  const { spatialZoom: initialZoom, spatialTargetX: initialTargetX, spatialTargetY: initialTargetY, spatialTargetZ: initialTargetZ } = useInitialCoordination(COMPONENT_COORDINATION_TYPES[ViewType$1.SPATIAL], coordinationScopes);
253526
253547
  const observationsLabel = observationsLabelOverride || obsType;
253527
253548
  const [{ imageLayerCallbacks, segmentationLayerCallbacks }] = useAuxiliaryCoordination(COMPONENT_COORDINATION_TYPES.layerController, coordinationScopes);
@@ -253727,7 +253748,15 @@ function SpatialSubscriber$1(props) {
253727
253748
  subobservationsLabel,
253728
253749
  locationsCount
253729
253750
  });
253730
- const { normData: uint8ExpressionData, extents: expressionExtents } = useUint8FeatureSelection(expressionData);
253751
+ const featureAggregationStrategyToUse = featureAggregationStrategy ?? DEFAULT_FEATURE_AGGREGATION_STRATEGY$2;
253752
+ const aggregatedExpressionData = useMemo$1(() => {
253753
+ if (featureAggregationStrategyToUse != null && expressionData && expressionData.length > 1) {
253754
+ const aggregated = aggregateFeatureArrays(expressionData, featureAggregationStrategyToUse);
253755
+ return [aggregated];
253756
+ }
253757
+ return expressionData;
253758
+ }, [expressionData, featureAggregationStrategyToUse]);
253759
+ const { normData: uint8ExpressionData, extents: expressionExtents } = useUint8FeatureSelection(aggregatedExpressionData);
253731
253760
  const shiftedExpressionDataForBitmask = useMemo$1(() => {
253732
253761
  if (matrixObsIndex && uint8ExpressionData && obsSegmentationsType === "bitmask") {
253733
253762
  const maxId = matrixObsIndex.reduce((max2, curr) => Math.max(max2, Number(curr)));
@@ -253752,7 +253781,7 @@ function SpatialSubscriber$1(props) {
253752
253781
  const canShow3DOptions = canLoad3DLayers && !(disable3d?.length === imageLayerLoaders.length) && !globalDisable3d;
253753
253782
  const options = useMemo$1(() => {
253754
253783
  if (canShow3DOptions || hasExpressionData) {
253755
- return jsx$1(SpatialOptions, { observationsLabel, cellColorEncoding, setCellColorEncoding, setSpatialAxisFixed, spatialAxisFixed, use3d, tooltipsVisible, setTooltipsVisible, geneExpressionColormap, setGeneExpressionColormap, geneExpressionColormapRange, setGeneExpressionColormapRange, canShowExpressionOptions: hasExpressionData, canShowColorEncodingOption: (hasLocationsData || hasSegmentationsData) && hasExpressionData, canShow3DOptions });
253784
+ return jsx$1(SpatialOptions, { observationsLabel, cellColorEncoding, setCellColorEncoding, setSpatialAxisFixed, spatialAxisFixed, use3d, tooltipsVisible, setTooltipsVisible, geneExpressionColormap, setGeneExpressionColormap, geneExpressionColormapRange, setGeneExpressionColormapRange, canShowExpressionOptions: hasExpressionData, canShowColorEncodingOption: (hasLocationsData || hasSegmentationsData) && hasExpressionData, canShow3DOptions, featureSelection: geneSelection, featureAggregationStrategy, setFeatureAggregationStrategy });
253756
253785
  }
253757
253786
  return null;
253758
253787
  }, [
@@ -253771,7 +253800,10 @@ function SpatialSubscriber$1(props) {
253771
253800
  spatialAxisFixed,
253772
253801
  use3d,
253773
253802
  tooltipsVisible,
253774
- setTooltipsVisible
253803
+ setTooltipsVisible,
253804
+ geneSelection,
253805
+ featureAggregationStrategy,
253806
+ setFeatureAggregationStrategy
253775
253807
  ]);
253776
253808
  useEffect(() => {
253777
253809
  if (!hasSegmentationsData && cellsLayer && !obsSegmentations && !obsSegmentationsIndex && obsCentroids && obsCentroidsIndex) {
@@ -253834,7 +253866,8 @@ function SpatialSubscriber$1(props) {
253834
253866
  featureValueColormap: geneExpressionColormap,
253835
253867
  featureValueColormapRange: geneExpressionColormapRange,
253836
253868
  setFeatureValueColormapRange: setGeneExpressionColormapRange,
253837
- extent: expressionExtents?.[0]
253869
+ extent: expressionExtents?.[0],
253870
+ featureAggregationStrategy: featureAggregationStrategyToUse
253838
253871
  })] });
253839
253872
  }
253840
253873
  function getInitialSpatialTargets({ width: width2, height: height2, obsPoints, obsSpots, obsSegmentations, obsSegmentationsLocations, segmentationChannelScopesByLayer, images, is3dMode: use3d, isReady }) {
@@ -255486,12 +255519,12 @@ class ErrorBoundary extends React__default.Component {
255486
255519
  }
255487
255520
  }
255488
255521
  const LazySpatialThree = React__default.lazy(async () => {
255489
- const { SpatialWrapper: SpatialWrapper2 } = await import("./index-6Oxzw9ho.js").then((n3) => n3.a);
255522
+ const { SpatialWrapper: SpatialWrapper2 } = await import("./index-BlOIc49f.js").then((n3) => n3.a);
255490
255523
  return { default: SpatialWrapper2 };
255491
255524
  });
255492
255525
  const SpatialThreeAdapter = React__default.forwardRef((props, ref2) => jsx$1("div", { ref: ref2, style: { width: "100%", height: "100%" }, children: jsx$1(ErrorBoundary, { fallback: jsx$1("div", { children: "3D spatial view is not available in this environment." }), children: jsx$1(Suspense, { fallback: jsx$1("div", { children: "Loading..." }), children: jsx$1(LazySpatialThree, { ...props }) }) }) }));
255493
255526
  const LazySpatialAccelerated = React__default.lazy(async () => {
255494
- const { SpatialWrapper: SpatialWrapper2 } = await import("./index-BsUxdbVL.js");
255527
+ const { SpatialWrapper: SpatialWrapper2 } = await import("./index-BSOXpbtb.js");
255495
255528
  return { default: SpatialWrapper2 };
255496
255529
  });
255497
255530
  const SpatialAcceleratedAdapter = React__default.forwardRef((props, ref2) => jsx$1("div", { ref: ref2, style: { width: "100%", height: "100%" }, children: jsx$1(ErrorBoundary, { fallback: jsx$1("div", { children: "3D spatial view is not available in this environment." }), children: jsx$1(Suspense, { fallback: jsx$1("div", { children: "Loading..." }), children: jsx$1(LazySpatialAccelerated, { ...props }) }) }) }));
@@ -255668,7 +255701,8 @@ function SpatialSubscriber(props) {
255668
255701
  bitmaskValueIsIndex = false,
255669
255702
  // TODO: move to coordination type
255670
255703
  three: threeFor3d = false,
255671
- accelerated: acceleratedFor3d = false
255704
+ accelerated: acceleratedFor3d = false,
255705
+ helpText = ViewHelpMapping.SPATIAL_BETA
255672
255706
  } = props;
255673
255707
  const loaders = useLoaders();
255674
255708
  const setComponentHover = useSetComponentHover();
@@ -256112,7 +256146,7 @@ function SpatialSubscriber(props) {
256112
256146
  }
256113
256147
  }
256114
256148
  };
256115
- return jsxs(TitleInfo, { title: title2, info: subtitle, isSpatial: true, urls: urls2, theme, closeButtonVisible, downloadButtonVisible, removeGridComponent, isReady, errors, children: [shouldUseThree ? acceleratedFor3d ? jsx$1(SpatialAcceleratedAdapter, { ref: threeRef, uuid: uuid2, width: width2, height: height2, theme, hideTools: !isSelectable, rotation: [rotationX, rotationY, rotationZ], setRotationX, setRotationY, setRotationZ, targetT, targetZ, viewState: isValidViewState ? {
256149
+ return jsxs(TitleInfo, { title: title2, info: subtitle, isSpatial: true, urls: urls2, theme, closeButtonVisible, downloadButtonVisible, removeGridComponent, isReady, errors, helpText, children: [shouldUseThree ? acceleratedFor3d ? jsx$1(SpatialAcceleratedAdapter, { ref: threeRef, uuid: uuid2, width: width2, height: height2, theme, hideTools: !isSelectable, rotation: [rotationX, rotationY, rotationZ], setRotationX, setRotationY, setRotationZ, targetT, targetZ, viewState: isValidViewState ? {
256116
256150
  zoom: zoom2,
256117
256151
  target: [targetX2, targetY2, targetZ],
256118
256152
  rotationX,
@@ -256219,8 +256253,8 @@ function getAxisSizes(transpose2, longestGeneLabel, longestCellLabel, hideObserv
256219
256253
  const font2 = `${AXIS_LABEL_TEXT_SIZE}pt ${AXIS_FONT_FAMILY}`;
256220
256254
  const geneLabelMaxWidth = hideVariableLabels ? 0 : getTextWidth(longestGeneLabel, font2) + AXIS_PADDING;
256221
256255
  const cellLabelMaxWidth = hideObservationLabels ? 0 : getTextWidth(longestCellLabel, font2) + AXIS_PADDING;
256222
- const axisOffsetLeft = clamp$7(transpose2 ? geneLabelMaxWidth : cellLabelMaxWidth, AXIS_MIN_SIZE, AXIS_MAX_SIZE);
256223
- const axisOffsetTop = clamp$7(transpose2 ? cellLabelMaxWidth : geneLabelMaxWidth, AXIS_MIN_SIZE, AXIS_MAX_SIZE);
256256
+ const axisOffsetLeft = clamp$8(transpose2 ? geneLabelMaxWidth : cellLabelMaxWidth, AXIS_MIN_SIZE, AXIS_MAX_SIZE);
256257
+ const axisOffsetTop = clamp$8(transpose2 ? cellLabelMaxWidth : geneLabelMaxWidth, AXIS_MIN_SIZE, AXIS_MAX_SIZE);
256224
256258
  return [axisOffsetLeft, axisOffsetTop];
256225
256259
  }
256226
256260
  function mouseToHeatmapPosition(mouseX, mouseY, { offsetLeft, offsetTop, targetX: targetX2, targetY: targetY2, scaleFactor, matrixWidth, matrixHeight, numRows, numCols }) {
@@ -256450,8 +256484,8 @@ const Heatmap$1 = forwardRef$1((props, deckRef) => {
256450
256484
  const scaleFactor = 2 ** viewState.zoom;
256451
256485
  const cellHeight = matrixHeight * scaleFactor / height2;
256452
256486
  const cellWidth = matrixWidth * scaleFactor / width2;
256453
- const aggSizeX = clamp$7(2 ** Math.ceil(Math.log2(1 / cellWidth)), MIN_ROW_AGG, MAX_ROW_AGG);
256454
- const aggSizeY = clamp$7(2 ** Math.ceil(Math.log2(1 / cellHeight)), MIN_ROW_AGG, MAX_ROW_AGG);
256487
+ const aggSizeX = clamp$8(2 ** Math.ceil(Math.log2(1 / cellWidth)), MIN_ROW_AGG, MAX_ROW_AGG);
256488
+ const aggSizeY = clamp$8(2 ** Math.ceil(Math.log2(1 / cellHeight)), MIN_ROW_AGG, MAX_ROW_AGG);
256455
256489
  const [targetX2, targetY2] = viewState.target;
256456
256490
  useEffect(() => {
256457
256491
  updateViewInfo({
@@ -256495,8 +256529,8 @@ const Heatmap$1 = forwardRef$1((props, deckRef) => {
256495
256529
  const minTargetY = nextZoom === 0 ? 0 : -(matrixBottom - matrixBottom / nextScaleFactor);
256496
256530
  const maxTargetY = -1 * minTargetY;
256497
256531
  const nextTarget = [
256498
- clamp$7(nextViewState.target[0], minTargetX, maxTargetX),
256499
- clamp$7(nextViewState.target[1], minTargetY, maxTargetY)
256532
+ clamp$8(nextViewState.target[0], minTargetX, maxTargetX),
256533
+ clamp$8(nextViewState.target[1], minTargetY, maxTargetY)
256500
256534
  ];
256501
256535
  setViewState({
256502
256536
  zoom: nextZoom,
@@ -263641,7 +263675,7 @@ const useStyles$o = makeStyles()((theme) => ({
263641
263675
  }));
263642
263676
  const SHIFT_KEYCODE = 16;
263643
263677
  function SelectableTable(props) {
263644
- const { hasColorEncoding, columns: columns2, columnLabels, data: data2, onChange, idKey = "id", valueKey = "value", allowMultiple = false, allowUncheck = false, showTableHead = true, showTableInputs = false, testHeight = void 0, testWidth = void 0, width: width2, height: height2 } = props;
263678
+ const { hasColorEncoding, columns: columns2, columnLabels, data: data2, onChange, idKey = "id", selectedIds, allowMultiple = false, allowUncheck = false, showTableHead = true, showTableInputs = false, testHeight = void 0, testWidth = void 0, width: width2, height: height2 } = props;
263645
263679
  const [selectedRows, setSelectedRows] = useState(null);
263646
263680
  const [isCheckingMultiple, setIsCheckingMultiple] = useState(false);
263647
263681
  useEffect(() => {
@@ -263685,20 +263719,20 @@ function SelectableTable(props) {
263685
263719
  })), [data2, idKey]);
263686
263720
  const isSelected = useCallback((id2) => Array.isArray(selectedRows) && selectedRows.includes(id2), [selectedRows]);
263687
263721
  useEffect(() => {
263688
- const initialSelectedRows = data2.map((d) => {
263689
- if (d[valueKey]) {
263690
- return d[idKey];
263691
- }
263692
- return null;
263693
- }).filter(Boolean);
263694
- if (!isEqual$3(initialSelectedRows, selectedRows)) {
263695
- if (initialSelectedRows.length > 0) {
263696
- setSelectedRows(initialSelectedRows);
263697
- } else {
263698
- setSelectedRows(null);
263722
+ if (selectedIds === void 0)
263723
+ return;
263724
+ setSelectedRows((prev2) => {
263725
+ const prevList = prev2 || [];
263726
+ const nextList = selectedIds || [];
263727
+ const sharedList = prevList.filter((id2) => nextList.includes(id2));
263728
+ const nextUnique = nextList.filter((id2) => !prevList.includes(id2));
263729
+ const merged = [...sharedList, ...nextUnique];
263730
+ if (isEqual$3(merged, prevList)) {
263731
+ return prev2;
263699
263732
  }
263700
- }
263701
- }, [data2, idKey, valueKey]);
263733
+ return merged.length > 0 ? merged : null;
263734
+ });
263735
+ }, [selectedIds]);
263702
263736
  useEffect(() => {
263703
263737
  if (!onChange || !selectedRows) {
263704
263738
  return;
@@ -263770,8 +263804,7 @@ function FeatureList(props) {
263770
263804
  const data2 = useMemo$1(() => {
263771
263805
  const preSortedData = searchResults.filter((gene) => geneFilter ? geneFilter.includes(gene) : true).map((gene) => ({
263772
263806
  key: gene,
263773
- name: featureLabelsMap?.get(gene) || featureLabelsMap?.get(cleanFeatureId(gene)) || gene,
263774
- value: geneSelection ? geneSelection.includes(gene) : false
263807
+ name: featureLabelsMap?.get(gene) || featureLabelsMap?.get(cleanFeatureId(gene)) || gene
263775
263808
  }));
263776
263809
  if (preSortedData && featureListSort === "alphabetical" && preSortedData.length > 0) {
263777
263810
  return preSortedData.sort((a2, b2) => a2[selectableTableSortKey].localeCompare(b2[selectableTableSortKey]));
@@ -263782,8 +263815,7 @@ function FeatureList(props) {
263782
263815
  selectableTableSortKey,
263783
263816
  searchResults,
263784
263817
  geneFilter,
263785
- featureLabelsMap,
263786
- geneSelection
263818
+ featureLabelsMap
263787
263819
  ]);
263788
263820
  const handleChange = (event2) => {
263789
263821
  setSearchTerm(event2.target.value);
@@ -263800,7 +263832,7 @@ function FeatureList(props) {
263800
263832
  [primaryColumnName]
263801
263833
  ];
263802
263834
  }, [showFeatureTable, primaryColumnName, hasFeatureLabels]);
263803
- return width2 > 0 && height2 > 0 ? jsxs(Fragment, { children: [jsx$1("input", { className: classes2.searchBar, type: "text", placeholder: "Search", value: searchTerm, onChange: handleChange }), jsx$1(SelectableTable, { columns: columns2, columnLabels, data: data2, hasColorEncoding, idKey: "key", valueKey: "value", onChange, allowMultiple: enableMultiSelect, allowUncheck: enableMultiSelect, showTableHead: columnLabels.length > 1, width: width2, height: height2 - 34 })] }) : null;
263835
+ return width2 > 0 && height2 > 0 ? jsxs(Fragment, { children: [jsx$1("input", { className: classes2.searchBar, type: "text", placeholder: "Search", value: searchTerm, onChange: handleChange }), jsx$1(SelectableTable, { columns: columns2, columnLabels, data: data2, hasColorEncoding, idKey: "key", selectedIds: geneSelection, onChange, allowMultiple: enableMultiSelect, allowUncheck: enableMultiSelect, showTableHead: columnLabels.length > 1, width: width2, height: height2 - 34 })] }) : null;
263804
263836
  }
263805
263837
  function FeatureListOptions(props) {
263806
263838
  const { children: children3, featureListSort, setFeatureListSort, featureListSortKey, setFeatureListSortKey, showFeatureTable, setShowFeatureTable, hasFeatureLabels, primaryColumnName } = props;
@@ -263817,7 +263849,7 @@ function FeatureListOptions(props) {
263817
263849
  const { classes: classes2 } = usePlotOptionsStyles();
263818
263850
  return jsxs(OptionsContainer, { children: [children3, jsxs(TableRow, { children: [jsx$1(TableCell, { className: classes2.labelCell, variant: "head", scope: "row", children: jsx$1("label", { htmlFor: `feature-list-sort-option-${featureListId}`, children: "Sort Ordering" }) }), jsx$1(TableCell, { variant: "body", children: jsx$1(OptionSelect, { className: classes2.select, value: featureListSort, onChange: handleFeatureListSortChange, inputProps: {
263819
263851
  id: `feature-list-sort-option-${featureListId}`
263820
- }, children: FEATURELIST_SORT_OPTIONS.map((option) => jsx$1("option", { value: option, children: option }, option)) }) })] }), hasFeatureLabels ? jsxs(Fragment, { children: [jsxs(TableRow, { children: [jsx$1(TableCell, { className: classes2.labelCell, variant: "head", scope: "row", children: jsx$1("label", { htmlFor: `feature-list-sort-key-${featureListId}`, children: "Sort Key" }) }), jsx$1(TableCell, { variant: "body", children: jsx$1(OptionSelect, { className: classes2.select, disabled: featureListSort === "original", value: featureListSortKey, onChange: handleFeatureListSortKeyChange, inputProps: {
263852
+ }, children: FEATURELIST_SORT_OPTIONS.map((option) => jsx$1("option", { value: option, children: capitalize$3(option) }, option)) }) })] }), hasFeatureLabels ? jsxs(Fragment, { children: [jsxs(TableRow, { children: [jsx$1(TableCell, { className: classes2.labelCell, variant: "head", scope: "row", children: jsx$1("label", { htmlFor: `feature-list-sort-key-${featureListId}`, children: "Sort Key" }) }), jsx$1(TableCell, { variant: "body", children: jsx$1(OptionSelect, { className: classes2.select, disabled: featureListSort === "original", value: featureListSortKey, onChange: handleFeatureListSortKeyChange, inputProps: {
263821
263853
  "aria-label": "Select the feature list sort key",
263822
263854
  id: `feature-list-sort-key-${featureListId}`
263823
263855
  }, children: hasFeatureLabels ? jsxs(Fragment, { children: [jsx$1("option", { value: "featureLabels", children: primaryColumnName }), jsx$1("option", { value: "featureIndex", children: ALT_COLNAME })] }) : jsx$1("option", { value: "featureIndex", children: primaryColumnName }) }) })] }), jsxs(TableRow, { children: [jsx$1(TableCell, { className: classes2.labelCell, variant: "head", scope: "row", children: jsx$1("label", { htmlFor: `feature-list-show-alternative-ids-${featureListId}`, children: "Show Alternate IDs" }) }), jsx$1(TableCell, { className: classes2.inputCell, variant: "body", children: jsx$1(Checkbox$1, { className: classes2.tableCheckbox, checked: showFeatureTable, onChange: handleShowTableChange, name: "feature-list-show-table", color: "default", slotProps: { input: {
@@ -265316,7 +265348,7 @@ function PointLayerController(props) {
265316
265348
  const [coloringTabIndex, setColoringTabIndex] = useState(0);
265317
265349
  const { featureIndex } = pointMatrixIndicesData || {};
265318
265350
  const hasSelectedFeatures = Array.isArray(featureSelection) && featureSelection.length > 0;
265319
- return jsxs(Grid$1, { className: lcClasses.layerControllerGrid, children: [jsxs(Paper, { elevation: 4, className: lcClasses.layerControllerRoot, children: [jsxs(Grid$1, { container: true, direction: "row", justifyContent: "space-between", children: [jsx$1(Grid$1, { size: 1, children: jsx$1(Button, { onClick: handleVisibleChange, className: menuClasses.imageLayerVisibleButton, "aria-label": "Toggle layer visibility", children: jsx$1(Visibility, {}) }) }), jsx$1(Grid$1, { size: 1, children: jsx$1(ChannelColorPickerMenu, { theme, color: color2, setColor: setColor2, palette, isStaticColor, isColormap, featureValueColormap, visible }) }), jsx$1(Grid$1, { size: 6, children: jsx$1(Typography, { className: menuClasses.imageLayerName, children: label2 }) }), jsx$1(Grid$1, { size: 2, children: jsx$1(Slider, { value: opacity2, min: 0, max: 1, step: 1e-3, onChange: handleOpacityChange, className: menuClasses.imageLayerOpacitySlider, orientation: "horizontal", "aria-label": `Adjust opacity for layer ${label2}` }) }), jsx$1(Grid$1, { size: 1, children: jsx$1(PointLayerEllipsisMenu, { featureSelection, obsColorEncoding, setObsColorEncoding, featureValueColormapRange, setFeatureValueColormapRange, tooltipsVisible, setTooltipsVisible, tooltipCrosshairsVisible, setTooltipCrosshairsVisible, legendVisible, setLegendVisible, featureFilterMode, setFeatureFilterMode }) }), jsxs(Grid$1, { size: 1, container: true, direction: "row", children: [jsx$1(SvgPoints, { className: classes2.layerTypePointIcon }), null] })] }), loadingDoneFraction < 1 ? jsx$1(Grid$1, { size: 12, container: true, direction: "column", justifyContent: "space-between", className: classes2.pointFeatureControllerGrid, children: jsx$1(LinearProgress, { variant: loadingDoneFraction === 0 ? "indeterminate" : "determinate", value: loadingDoneFraction * 100 }) }) : null, null] }), hasSelectedFeatures ? jsxs(Fragment, { children: [featureSelection.map((featureName) => jsx$1(LayerPerFeatureController, { theme, featureName, featureColor, setFeatureColor, spatialLayerColor, featureIndex, featureValueColormap, featureSelection, setFeatureSelection, obsColorEncoding, loadingDoneFraction, opacity: opacity2, handleOpacityChange }, featureName)), jsx$1(Grid$1, { className: lcClasses.layerControllerGrid, children: jsx$1(Paper, { elevation: 2, className: lcClasses.layerControllerSubRow, children: jsxs(Grid$1, { container: true, direction: "row", justifyContent: "space-between", children: [jsx$1(Grid$1, { size: 1, children: jsx$1(Button, { onClick: () => setFeatureFilterMode(featureFilterMode === "featureSelection" ? null : "featureSelection"), className: menuClasses.imageLayerVisibleButton, "aria-label": "Toggle visibility of unselected points", children: featureFilterMode === "featureSelection" ? jsx$1(VisibilityOffIcon, {}) : jsx$1(VisibilityIcon, {}) }) }), jsx$1(Grid$1, { size: 1, children: jsx$1(ChannelColorPickerMenu, { theme, color: getDefaultColor("dark"), setColor: null, isStaticColor: true, isColormap: false, visible: true }) }), jsx$1(Grid$1, { size: 6, children: jsx$1(Typography, { className: menuClasses.imageLayerName, children: "Unselected" }) }), jsx$1(Grid$1, { size: 2, sx: { paddingRight: "12px", overflow: "visible" }, children: jsx$1(Slider, { value: opacity2, min: 0, max: 1, step: 1e-3, onChange: handleOpacityChange, className: menuClasses.imageLayerOpacitySlider, orientation: "horizontal", "aria-label": "Adjust opacity for unselected layer" }) }), jsx$1(Grid$1, { size: 1, children: jsx$1(SvgPoints, { className: classes2.layerTypePointIcon }) })] }) }) })] }) : null] });
265351
+ return jsxs(Grid$1, { className: lcClasses.layerControllerGrid, children: [jsxs(Paper, { elevation: 4, className: lcClasses.layerControllerRoot, children: [jsxs(Grid$1, { container: true, direction: "row", justifyContent: "space-between", children: [jsx$1(Grid$1, { size: 1, children: jsx$1(Button, { onClick: handleVisibleChange, className: menuClasses.imageLayerVisibleButton, "aria-label": "Toggle layer visibility", children: jsx$1(Visibility, {}) }) }), jsx$1(Grid$1, { size: 1, children: jsx$1(ChannelColorPickerMenu, { theme, color: color2, setColor: setColor2, palette, isStaticColor, isColormap, featureValueColormap, visible }) }), jsx$1(Grid$1, { size: 6, children: jsx$1(Typography, { className: menuClasses.imageLayerName, children: label2 }) }), jsx$1(Grid$1, { size: 2, children: jsx$1(Slider, { value: opacity2, min: 0, max: 1, step: 1e-3, onChange: handleOpacityChange, className: menuClasses.imageLayerOpacitySlider, orientation: "horizontal", "aria-label": `Adjust opacity for layer ${label2}` }) }), jsx$1(Grid$1, { size: 1, children: jsx$1(PointLayerEllipsisMenu, { featureSelection, obsColorEncoding, setObsColorEncoding, featureValueColormapRange, setFeatureValueColormapRange, tooltipsVisible, setTooltipsVisible, tooltipCrosshairsVisible, setTooltipCrosshairsVisible, legendVisible, setLegendVisible, featureFilterMode, setFeatureFilterMode }) }), jsxs(Grid$1, { size: 1, container: true, direction: "row", children: [jsx$1(SvgPoints, { className: classes2.layerTypePointIcon }), null] })] }), loadingDoneFraction < 1 ? jsx$1(Grid$1, { size: 12, container: true, direction: "column", justifyContent: "space-between", className: classes2.pointFeatureControllerGrid, children: jsx$1(LinearProgress, { variant: loadingDoneFraction === 0 ? "indeterminate" : "determinate", value: loadingDoneFraction * 100 }) }) : null, null] }), layerPerFeatureForPoints && hasSelectedFeatures ? jsxs(Fragment, { children: [featureSelection.map((featureName) => jsx$1(LayerPerFeatureController, { theme, featureName, featureColor, setFeatureColor, spatialLayerColor, featureIndex, featureValueColormap, featureSelection, setFeatureSelection, obsColorEncoding, loadingDoneFraction, opacity: opacity2, handleOpacityChange }, featureName)), jsx$1(Grid$1, { className: lcClasses.layerControllerGrid, children: jsx$1(Paper, { elevation: 2, className: lcClasses.layerControllerSubRow, children: jsxs(Grid$1, { container: true, direction: "row", justifyContent: "space-between", children: [jsx$1(Grid$1, { size: 1, children: jsx$1(Button, { onClick: () => setFeatureFilterMode(featureFilterMode === "featureSelection" ? null : "featureSelection"), className: menuClasses.imageLayerVisibleButton, "aria-label": "Toggle visibility of unselected points", children: featureFilterMode === "featureSelection" ? jsx$1(VisibilityOffIcon, {}) : jsx$1(VisibilityIcon, {}) }) }), jsx$1(Grid$1, { size: 1, children: jsx$1(ChannelColorPickerMenu, { theme, color: getDefaultColor("dark"), setColor: null, isStaticColor: true, isColormap: false, visible: true }) }), jsx$1(Grid$1, { size: 6, children: jsx$1(Typography, { className: menuClasses.imageLayerName, children: "Unselected" }) }), jsx$1(Grid$1, { size: 2, sx: { paddingRight: "12px", overflow: "visible" }, children: jsx$1(Slider, { value: opacity2, min: 0, max: 1, step: 1e-3, onChange: handleOpacityChange, className: menuClasses.imageLayerOpacitySlider, orientation: "horizontal", "aria-label": "Adjust opacity for unselected layer" }) }), jsx$1(Grid$1, { size: 1, children: jsx$1(SvgPoints, { className: classes2.layerTypePointIcon }) })] }) }) })] }) : null] });
265320
265352
  }
265321
265353
  const useStyles$e = makeStyles()(() => ({
265322
265354
  layerTypeSegmentationIcon: {
@@ -268145,17 +268177,23 @@ const useStyles$a = makeStyles()(() => ({
268145
268177
  }
268146
268178
  }));
268147
268179
  function ChannelSelectionDropdown(props) {
268148
- const { featureIndex, targetC, setTargetC, setWindow: setWindow2, disabled } = props;
268180
+ const { featureIndex, channelsSortOrder, targetC, setTargetC, setWindow: setWindow2, disabled } = props;
268149
268181
  const { classes: classes2 } = useStyles$a();
268150
268182
  const { classes: selectClasses2 } = useSelectStyles();
268151
268183
  function handleChange(event2) {
268152
268184
  setTargetC(event2.target.value === "" ? null : Number(event2.target.value));
268153
268185
  setWindow2(null);
268154
268186
  }
268155
- return Array.isArray(featureIndex) ? jsx$1(NativeSelect, { classes: { root: selectClasses2.selectRoot }, className: classes2.oneLineChannelSelect, value: targetC === null ? "" : targetC, onChange: handleChange, inputProps: { "aria-label": "Channel selector" }, children: featureIndex.map((channelName, channelIndex) => (
268156
- // eslint-disable-next-line react/no-array-index-key
268157
- jsx$1("option", { disabled, value: channelIndex, children: channelName }, `${channelName}-${channelIndex}`)
268158
- )) }) : null;
268187
+ const sortedOptions = useMemo$1(() => {
268188
+ if (!Array.isArray(featureIndex))
268189
+ return [];
268190
+ const options = featureIndex.map((channelName, channelIndex) => ({ channelName, channelIndex }));
268191
+ if (channelsSortOrder === "alphabetical") {
268192
+ return options.sort((a2, b2) => a2.channelName.localeCompare(b2.channelName, void 0, { numeric: true, sensitivity: "base" }));
268193
+ }
268194
+ return options;
268195
+ }, [featureIndex, channelsSortOrder]);
268196
+ return Array.isArray(featureIndex) ? jsx$1(NativeSelect, { classes: { root: selectClasses2.selectRoot }, className: classes2.oneLineChannelSelect, value: targetC === null ? "" : targetC, onChange: handleChange, inputProps: { "aria-label": "Channel selector" }, children: sortedOptions.map(({ channelName, channelIndex }) => jsx$1("option", { disabled, value: channelIndex, children: channelName }, `${channelName}-${channelIndex}`)) }) : null;
268159
268197
  }
268160
268198
  function ImageChannelController(props) {
268161
268199
  const {
@@ -268183,7 +268221,8 @@ function ImageChannelController(props) {
268183
268221
  spatialRenderingMode,
268184
268222
  numResolutions,
268185
268223
  spatialMaxResolution,
268186
- setSpatialMaxResolution
268224
+ setSpatialMaxResolution,
268225
+ channelsSortOrder
268187
268226
  } = props;
268188
268227
  const removeChannel = useRemoveImageChannelInMetaCoordinationScopes();
268189
268228
  const [showValueExtent, setShowValueExtent] = useState(true);
@@ -268220,7 +268259,7 @@ function ImageChannelController(props) {
268220
268259
  setWindow2(minMaxDomain);
268221
268260
  }
268222
268261
  }
268223
- return jsxs(Grid$1, { container: true, direction: "row", justifyContent: "space-between", children: [jsx$1(Grid$1, { size: 1, children: jsx$1(ChannelVisibilityCheckbox, { color: color2, setColor: setColor2, visible, setVisible, disabled: isLoading, theme, colormapOn }) }), jsx$1(Grid$1, { size: 1, children: jsx$1(ChannelColorPickerMenu, { color: color2, setColor: setColor2, visible, setVisible, disabled: isLoading, theme, isStaticColor: !colormapOn, palette: VIEWER_PALETTE }) }), jsx$1(Grid$1, { size: 6, children: jsx$1(ChannelSelectionDropdown, { featureIndex, targetC, setTargetC, setWindow: setWindow2, disabled: isLoading }) }), jsx$1(Grid$1, { size: 3, children: jsx$1(ChannelSlider, { image: image2, targetT, targetZ, targetC, window: window2, setWindow: setWindow2, disabled, color: color2, theme, colormapOn, showValueExtent, minMaxDomain }) }), jsx$1(Grid$1, { size: 1, children: jsx$1(ChannelOptions, { onRemove: onRemove2, showValueExtent, setShowValueExtent, onResetWindowUsingIQR: handleResetWindowUsingIQR, numResolutions, spatialMaxResolution, setSpatialMaxResolution }) })] });
268262
+ return jsxs(Grid$1, { container: true, direction: "row", justifyContent: "space-between", children: [jsx$1(Grid$1, { size: 1, children: jsx$1(ChannelVisibilityCheckbox, { color: color2, setColor: setColor2, visible, setVisible, disabled: isLoading, theme, colormapOn }) }), jsx$1(Grid$1, { size: 1, children: jsx$1(ChannelColorPickerMenu, { color: color2, setColor: setColor2, visible, setVisible, disabled: isLoading, theme, isStaticColor: !colormapOn, palette: VIEWER_PALETTE }) }), jsx$1(Grid$1, { size: 6, children: jsx$1(ChannelSelectionDropdown, { featureIndex, targetC, setTargetC, setWindow: setWindow2, disabled: isLoading, channelsSortOrder }) }), jsx$1(Grid$1, { size: 3, children: jsx$1(ChannelSlider, { image: image2, targetT, targetZ, targetC, window: window2, setWindow: setWindow2, disabled, color: color2, theme, colormapOn, showValueExtent, minMaxDomain }) }), jsx$1(Grid$1, { size: 1, children: jsx$1(ChannelOptions, { onRemove: onRemove2, showValueExtent, setShowValueExtent, onResetWindowUsingIQR: handleResetWindowUsingIQR, numResolutions, spatialMaxResolution, setSpatialMaxResolution }) })] });
268224
268263
  }
268225
268264
  function DimensionSlider(props) {
268226
268265
  const { boundingSlice, sliceValue, setSliceValue, label: label2 } = props;
@@ -268319,7 +268358,7 @@ const lodSliderRangeConfig = {
268319
268358
  step: 1
268320
268359
  };
268321
268360
  function ImageLayerEllipsisMenu(props) {
268322
- const { colormap, setColormap, photometricInterpretation, setPhotometricInterpretation, spatialTargetResolution, setSpatialTargetResolution, spatialLodFactor, setSpatialLodFactor, volumetricRenderingAlgorithm, setVolumetricRenderingAlgorithm, spatialLayerTransparentColor, setSpatialLayerTransparentColor, spatialRenderingMode, image: image2, channelScopes, tooltipsVisible, setTooltipsVisible, channelLabelsVisible, setChannelLabelsVisible, channelLabelsOrientation, setChannelLabelsOrientation, channelLabelSize, setChannelLabelSize } = props;
268361
+ const { colormap, setColormap, photometricInterpretation, setPhotometricInterpretation, spatialTargetResolution, setSpatialTargetResolution, spatialLodFactor, setSpatialLodFactor, volumetricRenderingAlgorithm, setVolumetricRenderingAlgorithm, spatialLayerTransparentColor, setSpatialLayerTransparentColor, spatialRenderingMode, image: image2, channelScopes, tooltipsVisible, setTooltipsVisible, channelLabelsVisible, setChannelLabelsVisible, channelLabelsOrientation, setChannelLabelsOrientation, channelLabelSize, setChannelLabelSize, channelsSortOrder, setChannelsSortOrder } = props;
268323
268362
  const [open2, setOpen] = useState(false);
268324
268363
  const { classes: selectClasses2 } = useSelectStyles();
268325
268364
  const { classes: menuClasses } = useEllipsisMenuStyles();
@@ -268345,6 +268384,9 @@ function ImageLayerEllipsisMenu(props) {
268345
268384
  function handleChannelLabelsOrientationChange(event2) {
268346
268385
  setChannelLabelsOrientation(event2.target.value);
268347
268386
  }
268387
+ function handleChannelsSortOrderChange(event2) {
268388
+ setChannelsSortOrder(event2.target.value);
268389
+ }
268348
268390
  function handleLodFactorChange(event2, value2) {
268349
268391
  setLocalLodSliderValue(value2);
268350
268392
  }
@@ -268366,11 +268408,12 @@ function ImageLayerEllipsisMenu(props) {
268366
268408
  const channelLabelsOrientationId = $bdb11010cef70236$export$f680877a34711e37();
268367
268409
  const channelLabelSizeId = $bdb11010cef70236$export$f680877a34711e37();
268368
268410
  const lodFactorId = $bdb11010cef70236$export$f680877a34711e37();
268411
+ const channelsSortOrderId = $bdb11010cef70236$export$f680877a34711e37();
268369
268412
  return jsxs(PopperMenu, { open: open2, setOpen, buttonIcon: jsx$1(MoreVertIcon, {}), buttonClassName: menuClasses.imageLayerMenuButton, containerClassName: menuClasses.imageLayerPopperContainer, withPaper: true, "aria-label": "Open image layer options menu", children: [is3dMode && jsxs(MenuItem, { dense: true, disableGutters: true, className: menuClasses.menuItem, children: [jsx$1("label", { id: `${lodFactorId}-label`, className: menuClasses.imageLayerMenuLabel, htmlFor: lodFactorId, children: "LOD Factor: " }), jsx$1(Slider, { disabled: !is3dMode, value: localLodSliderValue, onChange: handleLodFactorChange, onChangeCommitted: handleLodFactorChangeCommitted, className: menuClasses.menuItemSlider, orientation: "horizontal", id: lodFactorId, "aria-label": "Level of detail factor slider", valueLabelDisplay: "off", ...lodSliderRangeConfig }), jsx$1(Box, { px: 1 }), jsx$1(Input$1, { value: localLodSliderValue, onChange: handleLodFactorInputChange, onBlur: handleLodFactorInputChange, "aria-labelledby": `${lodFactorId}-label`, size: "small", sx: { width: "6ch", flexShrink: 0, fontVariantNumeric: "tabular-nums" }, endAdornment: jsx$1(InputAdornment$1, { position: "end", variant: "standard", sx: { "& > p": { marginBottom: 0 } }, children: "%" }), inputProps: {
268370
268413
  ...lodSliderRangeConfig,
268371
268414
  inputMode: "numeric",
268372
268415
  pattern: "[0-9]*"
268373
- } })] }), jsxs(MenuItem, { dense: true, disableGutters: true, classes: menuClasses.menuItem, children: [jsx$1("label", { className: menuClasses.imageLayerMenuLabel, htmlFor: colormapId, children: "Colormap: " }), jsxs(NativeSelect, { disabled: photometricInterpretation === "RGB", onChange: handleColormapChange, value: colormap === null ? "" : colormap, inputProps: { id: colormapId, "aria-label": "Colormap selector" }, classes: { root: selectClasses2.selectRoot }, children: [jsx$1("option", { "aria-label": "None", value: "", children: "None" }), COLORMAP_OPTIONS.map((name2) => jsx$1("option", { value: name2, children: name2 }, name2))] })] }), jsxs(MenuItem, { dense: true, disableGutters: true, classes: menuClasses.menuItem, children: [jsx$1("label", { className: menuClasses.imageLayerMenuLabel, htmlFor: interpretationId, children: "Photometric Interpretation: " }), jsxs(NativeSelect, { onChange: handleInterpretationChange, value: photometricInterpretation, inputProps: { id: interpretationId, "aria-label": "Photometric interpretation selector" }, classes: { root: selectClasses2.selectRoot }, children: [jsx$1("option", { "aria-label": "RGB", value: "RGB", children: "RGB" }), channelScopes.length > 0 ? jsx$1("option", { "aria-label": "BlackIsZero", value: "BlackIsZero", children: "BlackIsZero" }) : null] })] }), jsxs(MenuItem, { dense: true, disableGutters: true, classes: menuClasses.menuItem, children: [jsx$1("label", { className: menuClasses.imageLayerMenuLabel, htmlFor: transparentId, children: "Zero Transparent: " }), jsx$1(Checkbox$1, { color: "primary", checked: spatialLayerTransparentColor !== null, onChange: (e3, v) => setSpatialLayerTransparentColor(v ? [0, 0, 0] : null), slotProps: { input: { id: transparentId, "aria-label": "Render zero-value pixels as transparent" } } })] }), jsxs(MenuItem, { dense: true, disableGutters: true, classes: menuClasses.menuItem, children: [jsx$1("label", { className: menuClasses.imageLayerMenuLabel, htmlFor: volumetricId, children: "Volumetric Rendering: " }), jsxs(NativeSelect, { onChange: handleVolumetricChange, value: volumetricRenderingAlgorithm, inputProps: { id: volumetricId, "aria-label": "Volumetric rendering algorithm selector" }, classes: { root: selectClasses2.selectRoot }, disabled: !is3dMode, children: [jsx$1("option", { "aria-label": "Additive", value: "additive", children: "Additive" }), jsx$1("option", { "aria-label": "Maximum Intensity Projection", value: "maximumIntensityProjection", children: "Maximum Intensity Projection" })] })] }), jsxs(MenuItem, { dense: true, disableGutters: true, children: [jsx$1("label", { className: menuClasses.imageLayerMenuLabel, htmlFor: resolutionId, children: "Volume Resolution: " }), jsxs(NativeSelect, { disabled: !is3dMode || !isMultiResolution, onChange: handleResolutionChange, value: spatialTargetResolution === null ? "auto" : spatialTargetResolution, inputProps: { id: resolutionId, "aria-label": "Volumetric resolution selector" }, classes: { root: selectClasses2.selectRoot }, children: [jsx$1("option", { value: "auto", children: "Auto" }), Array.isArray(multiResolutionStats) ? multiResolutionStats.map((stats, resolution) => stats.canLoad ? jsx$1("option", { value: resolution, children: `3D: ${resolution}x Downsampled, ~${formatBytes(stats.totalBytes)} per channel, (${stats.height}, ${stats.width}, ${stats.depthDownsampled})` }, `(${stats.height}, ${stats.width}, ${stats.depthDownsampled})`) : null) : null] })] }), jsxs(MenuItem, { dense: true, disableGutters: true, classes: menuClasses.menuItem, children: [jsx$1("label", { className: menuClasses.imageLayerMenuLabel, htmlFor: tooltipsVisibleId, children: "Tooltips Visible: " }), jsx$1(Checkbox$1, { color: "primary", checked: tooltipsVisible, onChange: (e3, v) => setTooltipsVisible(v), slotProps: { input: { id: tooltipsVisibleId, "aria-label": "Render pixel value tooltips" } } })] }), jsxs(MenuItem, { dense: true, disableGutters: true, classes: menuClasses.menuItem, children: [jsx$1("label", { className: menuClasses.imageLayerMenuLabel, htmlFor: channelLabelsVisibleId, children: "Channel Labels Visible: " }), jsx$1(Checkbox$1, { disabled: photometricInterpretation === "RGB", color: "primary", checked: channelLabelsVisible, onChange: (e3, v) => setChannelLabelsVisible(v), slotProps: { input: { id: channelLabelsVisibleId, "aria-label": "Render channel labels" } } })] }), jsxs(MenuItem, { dense: true, disableGutters: true, classes: menuClasses.menuItem, children: [jsx$1("label", { className: menuClasses.imageLayerMenuLabel, htmlFor: channelLabelsOrientationId, children: "Channel Labels Orientation: " }), jsxs(NativeSelect, { disabled: photometricInterpretation === "RGB", onChange: handleChannelLabelsOrientationChange, value: channelLabelsOrientation, inputProps: { id: channelLabelsOrientationId, "aria-label": "Channel labels orientation selector" }, classes: { root: selectClasses2.selectRoot }, children: [jsx$1("option", { "aria-label": "Vertical", value: "vertical", children: "Vertical" }), jsx$1("option", { "aria-label": "Horizontal", value: "horizontal", children: "Horizontal" })] })] }), jsxs(MenuItem, { dense: true, disableGutters: true, classes: menuClasses.menuItem, children: [jsx$1("label", { className: menuClasses.imageLayerMenuLabel, htmlFor: channelLabelSizeId, children: "Channel Labels Size: " }), jsx$1(Slider, { disabled: photometricInterpretation === "RGB", value: channelLabelSize, min: 8, max: 36, step: 1, onChange: (e3, v) => setChannelLabelSize(v), className: menuClasses.menuItemSlider, orientation: "horizontal", id: channelLabelSizeId, "aria-label": "Channel labels text size slider" })] })] });
268416
+ } })] }), jsxs(MenuItem, { dense: true, disableGutters: true, classes: menuClasses.menuItem, children: [jsx$1("label", { className: menuClasses.imageLayerMenuLabel, htmlFor: colormapId, children: "Colormap: " }), jsxs(NativeSelect, { disabled: photometricInterpretation === "RGB", onChange: handleColormapChange, value: colormap === null ? "" : colormap, inputProps: { id: colormapId, "aria-label": "Colormap selector" }, classes: { root: selectClasses2.selectRoot }, children: [jsx$1("option", { "aria-label": "None", value: "", children: "None" }), COLORMAP_OPTIONS.map((name2) => jsx$1("option", { value: name2, children: name2 }, name2))] })] }), jsxs(MenuItem, { dense: true, disableGutters: true, classes: menuClasses.menuItem, children: [jsx$1("label", { className: menuClasses.imageLayerMenuLabel, htmlFor: interpretationId, children: "Photometric Interpretation: " }), jsxs(NativeSelect, { onChange: handleInterpretationChange, value: photometricInterpretation, inputProps: { id: interpretationId, "aria-label": "Photometric interpretation selector" }, classes: { root: selectClasses2.selectRoot }, children: [jsx$1("option", { "aria-label": "RGB", value: "RGB", children: "RGB" }), channelScopes.length > 0 ? jsx$1("option", { "aria-label": "BlackIsZero", value: "BlackIsZero", children: "BlackIsZero" }) : null] })] }), jsxs(MenuItem, { dense: true, disableGutters: true, classes: menuClasses.menuItem, children: [jsx$1("label", { className: menuClasses.imageLayerMenuLabel, htmlFor: transparentId, children: "Zero Transparent: " }), jsx$1(Checkbox$1, { color: "primary", checked: spatialLayerTransparentColor !== null, onChange: (e3, v) => setSpatialLayerTransparentColor(v ? [0, 0, 0] : null), slotProps: { input: { id: transparentId, "aria-label": "Render zero-value pixels as transparent" } } })] }), jsxs(MenuItem, { dense: true, disableGutters: true, classes: menuClasses.menuItem, children: [jsx$1("label", { className: menuClasses.imageLayerMenuLabel, htmlFor: volumetricId, children: "Volumetric Rendering: " }), jsxs(NativeSelect, { onChange: handleVolumetricChange, value: volumetricRenderingAlgorithm, inputProps: { id: volumetricId, "aria-label": "Volumetric rendering algorithm selector" }, classes: { root: selectClasses2.selectRoot }, disabled: !is3dMode, children: [jsx$1("option", { "aria-label": "Additive", value: "additive", children: "Additive" }), jsx$1("option", { "aria-label": "Maximum Intensity Projection", value: "maximumIntensityProjection", children: "Maximum Intensity Projection" })] })] }), jsxs(MenuItem, { dense: true, disableGutters: true, children: [jsx$1("label", { className: menuClasses.imageLayerMenuLabel, htmlFor: resolutionId, children: "Volume Resolution: " }), jsxs(NativeSelect, { disabled: !is3dMode || !isMultiResolution, onChange: handleResolutionChange, value: spatialTargetResolution === null ? "auto" : spatialTargetResolution, inputProps: { id: resolutionId, "aria-label": "Volumetric resolution selector" }, classes: { root: selectClasses2.selectRoot }, children: [jsx$1("option", { value: "auto", children: "Auto" }), Array.isArray(multiResolutionStats) ? multiResolutionStats.map((stats, resolution) => stats.canLoad ? jsx$1("option", { value: resolution, children: `3D: ${resolution}x Downsampled, ~${formatBytes(stats.totalBytes)} per channel, (${stats.height}, ${stats.width}, ${stats.depthDownsampled})` }, `(${stats.height}, ${stats.width}, ${stats.depthDownsampled})`) : null) : null] })] }), jsxs(MenuItem, { dense: true, disableGutters: true, classes: menuClasses.menuItem, children: [jsx$1("label", { className: menuClasses.imageLayerMenuLabel, htmlFor: tooltipsVisibleId, children: "Tooltips Visible: " }), jsx$1(Checkbox$1, { color: "primary", checked: tooltipsVisible, onChange: (e3, v) => setTooltipsVisible(v), slotProps: { input: { id: tooltipsVisibleId, "aria-label": "Render pixel value tooltips" } } })] }), jsxs(MenuItem, { dense: true, disableGutters: true, classes: menuClasses.menuItem, children: [jsx$1("label", { className: menuClasses.imageLayerMenuLabel, htmlFor: channelLabelsVisibleId, children: "Channel Labels Visible: " }), jsx$1(Checkbox$1, { disabled: photometricInterpretation === "RGB", color: "primary", checked: channelLabelsVisible, onChange: (e3, v) => setChannelLabelsVisible(v), slotProps: { input: { id: channelLabelsVisibleId, "aria-label": "Render channel labels" } } })] }), jsxs(MenuItem, { dense: true, disableGutters: true, classes: menuClasses.menuItem, children: [jsx$1("label", { className: menuClasses.imageLayerMenuLabel, htmlFor: channelLabelsOrientationId, children: "Channel Labels Orientation: " }), jsxs(NativeSelect, { disabled: photometricInterpretation === "RGB", onChange: handleChannelLabelsOrientationChange, value: channelLabelsOrientation, inputProps: { id: channelLabelsOrientationId, "aria-label": "Channel labels orientation selector" }, classes: { root: selectClasses2.selectRoot }, children: [jsx$1("option", { "aria-label": "Vertical", value: "vertical", children: "Vertical" }), jsx$1("option", { "aria-label": "Horizontal", value: "horizontal", children: "Horizontal" })] })] }), jsxs(MenuItem, { dense: true, disableGutters: true, classes: menuClasses.menuItem, children: [jsx$1("label", { className: menuClasses.imageLayerMenuLabel, htmlFor: channelLabelSizeId, children: "Channel Labels Size: " }), jsx$1(Slider, { disabled: photometricInterpretation === "RGB", value: channelLabelSize, min: 8, max: 36, step: 1, onChange: (e3, v) => setChannelLabelSize(v), className: menuClasses.menuItemSlider, orientation: "horizontal", id: channelLabelSizeId, "aria-label": "Channel labels text size slider" })] }), jsxs(MenuItem, { dense: true, disableGutters: true, classes: menuClasses.menuItem, children: [jsx$1("label", { className: menuClasses.imageLayerMenuLabel, htmlFor: channelsSortOrderId, children: "Channel Ordering: " }), jsxs(NativeSelect, { onChange: handleChannelsSortOrderChange, value: channelsSortOrder, inputProps: { id: channelsSortOrderId, "aria-label": "Channel sort order selector" }, classes: { root: selectClasses2.selectRoot }, children: [jsx$1("option", { "aria-label": "Original", value: "original", children: "Original" }), jsx$1("option", { "aria-label": "Alphabetical", value: "alphabetical", children: "Alphabetical" })] })] })] });
268374
268417
  }
268375
268418
  function ImageLayerController(props) {
268376
268419
  const {
@@ -268396,8 +268439,8 @@ function ImageLayerController(props) {
268396
268439
  volumeStillRef = null
268397
268440
  } = props;
268398
268441
  const [open2, setOpen] = useState(true);
268399
- const { spatialLayerVisible: visible, spatialLayerOpacity: opacity2, spatialLayerColormap: colormap, photometricInterpretation, spatialTargetResolution, spatialLodFactor, volumetricRenderingAlgorithm, spatialLayerTransparentColor, spatialSliceX, spatialSliceY, spatialSliceZ, tooltipsVisible, spatialChannelLabelsVisible: channelLabelsVisible, spatialChannelLabelsOrientation: channelLabelsOrientation, spatialChannelLabelSize: channelLabelSize } = layerCoordination;
268400
- const { setSpatialLayerVisible: setVisible, setSpatialLayerOpacity: setOpacity2, setSpatialLayerColormap: setColormap, setPhotometricInterpretation, setSpatialTargetResolution, setSpatialLodFactor, setVolumetricRenderingAlgorithm, setSpatialLayerTransparentColor, setSpatialSliceX, setSpatialSliceY, setSpatialSliceZ, setTooltipsVisible, setSpatialChannelLabelsVisible: setChannelLabelsVisible, setSpatialChannelLabelsOrientation: setChannelLabelsOrientation, setSpatialChannelLabelSize: setChannelLabelSize } = setLayerCoordination;
268442
+ const { spatialLayerVisible: visible, spatialLayerOpacity: opacity2, spatialLayerColormap: colormap, photometricInterpretation, spatialTargetResolution, spatialLodFactor, volumetricRenderingAlgorithm, spatialLayerTransparentColor, spatialSliceX, spatialSliceY, spatialSliceZ, tooltipsVisible, spatialChannelLabelsVisible: channelLabelsVisible, spatialChannelLabelsOrientation: channelLabelsOrientation, spatialChannelLabelSize: channelLabelSize, spatialChannelsSortOrder: channelsSortOrder } = layerCoordination;
268443
+ const { setSpatialLayerVisible: setVisible, setSpatialLayerOpacity: setOpacity2, setSpatialLayerColormap: setColormap, setPhotometricInterpretation, setSpatialTargetResolution, setSpatialLodFactor, setVolumetricRenderingAlgorithm, setSpatialLayerTransparentColor, setSpatialSliceX, setSpatialSliceY, setSpatialSliceZ, setTooltipsVisible, setSpatialChannelLabelsVisible: setChannelLabelsVisible, setSpatialChannelLabelsOrientation: setChannelLabelsOrientation, setSpatialChannelLabelSize: setChannelLabelSize, setSpatialChannelsSortOrder: setChannelsSortOrder } = setLayerCoordination;
268401
268444
  const addChannel = useAddImageChannelInMetaCoordinationScopes();
268402
268445
  const visibleSetting = typeof visible === "boolean" ? visible : true;
268403
268446
  const Visibility = useMemo$1(() => visibleSetting ? VisibilityIcon : VisibilityOffIcon, [visibleSetting]);
@@ -268417,12 +268460,12 @@ function ImageLayerController(props) {
268417
268460
  const { classes: menuClasses } = useEllipsisMenuStyles();
268418
268461
  const { classes: controllerSectionClasses } = useControllerSectionStyles();
268419
268462
  const isMultiChannel = photometricInterpretation !== "RGB";
268420
- return jsx$1(Grid$1, { className: controllerSectionClasses.layerControllerGrid, children: jsxs(Paper, { elevation: 4, className: controllerSectionClasses.layerControllerRoot, children: [jsxs(Grid$1, { container: true, direction: "row", justifyContent: "space-between", children: [jsx$1(Grid$1, { size: 1, children: jsx$1(Button, { className: menuClasses.imageLayerVisibleButton, onClick: handleVisibleChange, "aria-label": "Toggle layer visibility", children: jsx$1(Visibility, {}) }) }), jsx$1(Grid$1, { size: 1 }), jsx$1(Grid$1, { size: 6, children: jsx$1(Typography, { className: menuClasses.imageLayerName, children: label2 }) }), jsx$1(Grid$1, { size: 2, children: jsx$1(Slider, { value: opacity2, min: 0, max: 1, step: 1e-3, onChange: handleOpacityChange, className: menuClasses.imageLayerOpacitySlider, orientation: "horizontal", "aria-label": `Adjust opacity for layer ${label2}` }) }), jsx$1(Grid$1, { size: 1, children: jsx$1(ImageLayerEllipsisMenu, { colormap, setColormap, photometricInterpretation, setPhotometricInterpretation, spatialTargetResolution, setSpatialTargetResolution, spatialLodFactor, setSpatialLodFactor, volumetricRenderingAlgorithm, setVolumetricRenderingAlgorithm, spatialLayerTransparentColor, setSpatialLayerTransparentColor, spatialRenderingMode, image: image2, channelScopes, tooltipsVisible, setTooltipsVisible, channelLabelsVisible, setChannelLabelsVisible, channelLabelsOrientation, setChannelLabelsOrientation, channelLabelSize, setChannelLabelSize }) }), jsxs(Grid$1, { size: 1, container: true, direction: "row", children: [jsx$1(ImageIcon, { className: classes2.layerTypeImageIcon }), isMultiChannel ? jsx$1(Button, { onClick: handleOpenChange, className: classes2.channelExpansionButton, "aria-label": "Expand or collapse channel controls", children: open2 ? jsx$1(ExpandLess, {}) : jsx$1(ExpandMore, {}) }) : null] })] }), isMultiChannel && open2 ? jsxs(Grid$1, { container: true, direction: "column", justifyContent: "space-between", className: classes2.imageChannelControllerGrid, children: [channelScopes.map((cScope) => {
268463
+ return jsx$1(Grid$1, { className: controllerSectionClasses.layerControllerGrid, children: jsxs(Paper, { elevation: 4, className: controllerSectionClasses.layerControllerRoot, children: [jsxs(Grid$1, { container: true, direction: "row", justifyContent: "space-between", children: [jsx$1(Grid$1, { size: 1, children: jsx$1(Button, { className: menuClasses.imageLayerVisibleButton, onClick: handleVisibleChange, "aria-label": "Toggle layer visibility", children: jsx$1(Visibility, {}) }) }), jsx$1(Grid$1, { size: 1 }), jsx$1(Grid$1, { size: 6, children: jsx$1(Typography, { className: menuClasses.imageLayerName, children: label2 }) }), jsx$1(Grid$1, { size: 2, children: jsx$1(Slider, { value: opacity2, min: 0, max: 1, step: 1e-3, onChange: handleOpacityChange, className: menuClasses.imageLayerOpacitySlider, orientation: "horizontal", "aria-label": `Adjust opacity for layer ${label2}` }) }), jsx$1(Grid$1, { size: 1, children: jsx$1(ImageLayerEllipsisMenu, { colormap, setColormap, photometricInterpretation, setPhotometricInterpretation, spatialTargetResolution, setSpatialTargetResolution, spatialLodFactor, setSpatialLodFactor, volumetricRenderingAlgorithm, setVolumetricRenderingAlgorithm, spatialLayerTransparentColor, setSpatialLayerTransparentColor, spatialRenderingMode, image: image2, channelScopes, tooltipsVisible, setTooltipsVisible, channelLabelsVisible, setChannelLabelsVisible, channelLabelsOrientation, setChannelLabelsOrientation, channelLabelSize, setChannelLabelSize, channelsSortOrder, setChannelsSortOrder }) }), jsxs(Grid$1, { size: 1, container: true, direction: "row", children: [jsx$1(ImageIcon, { className: classes2.layerTypeImageIcon }), isMultiChannel ? jsx$1(Button, { onClick: handleOpenChange, className: classes2.channelExpansionButton, "aria-label": "Expand or collapse channel controls", children: open2 ? jsx$1(ExpandLess, {}) : jsx$1(ExpandMore, {}) }) : null] })] }), isMultiChannel && open2 ? jsxs(Grid$1, { container: true, direction: "column", justifyContent: "space-between", className: classes2.imageChannelControllerGrid, children: [channelScopes.map((cScope) => {
268421
268464
  const { spatialTargetC, spatialChannelVisible, spatialChannelOpacity, spatialChannelColor, spatialChannelWindow, spatialMaxResolution } = channelCoordination[cScope];
268422
268465
  const { setSpatialTargetC, setSpatialChannelVisible, setSpatialChannelOpacity, setSpatialChannelColor, setSpatialChannelWindow, setSpatialMaxResolution } = setChannelCoordination[cScope];
268423
268466
  const channelIndex = image2?.getChannelIndex(spatialTargetC);
268424
268467
  const numResolutions = image2?.getNumResolutions();
268425
- return jsx$1(ImageChannelController, { theme, coordinationScopesRaw, layerScope, channelScope: cScope, targetT, targetZ, targetC: channelIndex, setTargetC: setSpatialTargetC, visible: spatialChannelVisible, setVisible: setSpatialChannelVisible, opacity: spatialChannelOpacity, setOpacity: setSpatialChannelOpacity, color: spatialChannelColor, setColor: setSpatialChannelColor, window: spatialChannelWindow, setWindow: setSpatialChannelWindow, colormapOn: colormap !== null, featureIndex, image: image2, spatialRenderingMode, numResolutions, spatialMaxResolution, setSpatialMaxResolution }, cScope);
268468
+ return jsx$1(ImageChannelController, { theme, coordinationScopesRaw, layerScope, channelScope: cScope, targetT, targetZ, targetC: channelIndex, setTargetC: setSpatialTargetC, visible: spatialChannelVisible, setVisible: setSpatialChannelVisible, opacity: spatialChannelOpacity, setOpacity: setSpatialChannelOpacity, color: spatialChannelColor, setColor: setSpatialChannelColor, window: spatialChannelWindow, setWindow: setSpatialChannelWindow, colormapOn: colormap !== null, featureIndex, image: image2, channelsSortOrder, spatialRenderingMode, numResolutions, spatialMaxResolution, setSpatialMaxResolution }, cScope);
268426
268469
  }), jsx$1(Button, { disabled: channelScopes.length === MAX_CHANNELS$1 || channelScopes.length === imageNumChannels, onClick: handleChannelAdd, fullWidth: true, variant: "outlined", className: classes2.imageLayerButton, startIcon: jsx$1(AddIcon, {}), size: "small", "aria-label": "Add a channel to this layer", children: "Add Channel" })] }) : null, is3dMode && image2 ? jsxs(Grid$1, { container: true, direction: "column", justifyContent: "space-between", className: classes2.imageChannelControllerGrid, children: [jsx$1(Typography, { className: classes2.clippingPanesLabel, children: "Clipping planes:" }), jsx$1(Grid$1, { size: 12, className: classes2.clippingSliders, children: jsx$1(ClippingSliders, { image: image2, spatialSliceX, spatialSliceY, spatialSliceZ, setSpatialSliceX, setSpatialSliceY, setSpatialSliceZ }) }), jsx$1(LoadingStatusIndicator, { loadingProgress: volumeLoadingProgress, onStopLoading: onStopVolumeLoading, onRestartLoading: onRestartVolumeLoading, stillRef: volumeStillRef, spatialRenderingMode })] }) : null] }) });
268427
268470
  }
268428
268471
  const useStyles$8 = makeStyles()((theme) => ({
@@ -268473,7 +268516,7 @@ function LayerController(props) {
268473
268516
  return jsxs("div", { children: [anyLayerHasZ ? jsx$1(GlobalDimensionSlider, { label: "Z", targetValue: targetZ, setTargetValue: setTargetZ, max: maxZ, spatialRenderingMode, setSpatialRenderingMode }) : null, anyLayerHasT ? jsx$1(GlobalDimensionSlider, { label: "T", targetValue: targetT, setTargetValue: setTargetT, max: maxT }) : null, pointLayerScopes && reversedPointLayerScopes.map((layerScope) => jsx$1(PointLayerController, { theme, layerScope, layerCoordination: pointLayerCoordination[0][layerScope], setLayerCoordination: pointLayerCoordination[1][layerScope], pointMatrixIndicesData: pointMultiIndicesData?.[layerScope], tiledPointsLoadingProgress, layerPerFeatureForPoints }, layerScope)), spotLayerScopes && reversedSpotLayerScopes.map((layerScope) => jsx$1(SpotLayerController, { theme, layerScope, layerCoordination: spotLayerCoordination[0][layerScope], setLayerCoordination: spotLayerCoordination[1][layerScope] }, layerScope)), segmentationLayerScopes && reversedSegmentationLayerScopes.map((layerScope) => jsx$1(SegmentationLayerController, { theme, layerScope, layerCoordination: segmentationLayerCoordination[0][layerScope], setLayerCoordination: segmentationLayerCoordination[1][layerScope], channelScopes: segmentationChannelScopesByLayer[layerScope], channelCoordination: segmentationChannelCoordination[0][layerScope], setChannelCoordination: segmentationChannelCoordination[1][layerScope] }, layerScope)), imageLayerScopes && reversedImageLayerScopes.map((layerScope) => jsx$1(ImageLayerController, { theme, coordinationScopesRaw, layerScope, layerCoordination: imageLayerCoordination[0][layerScope], setLayerCoordination: imageLayerCoordination[1][layerScope], channelScopes: imageChannelScopesByLayer[layerScope], channelCoordination: imageChannelCoordination[0][layerScope], setChannelCoordination: imageChannelCoordination[1][layerScope], image: images[layerScope]?.image?.instance, featureIndex: images[layerScope]?.featureIndex, targetT, targetZ, spatialRenderingMode, volumeLoadingProgress: volumeLoadingStatus?.loadingProgress, onStopVolumeLoading: volumeLoadingStatus?.onStopLoading, onRestartVolumeLoading: volumeLoadingStatus?.onRestartLoading, volumeStillRef: volumeLoadingStatus?.stillRef }, layerScope))] });
268474
268517
  }
268475
268518
  function LayerControllerSubscriber(props) {
268476
- const { coordinationScopes: coordinationScopesRaw, coordinationScopesBy: coordinationScopesByRaw, closeButtonVisible, downloadButtonVisible, removeGridComponent, theme, title: title2 = "Spatial Layers", uuid: uuid2, layerPerFeatureForPoints = false, cameraPresets } = props;
268519
+ const { coordinationScopes: coordinationScopesRaw, coordinationScopesBy: coordinationScopesByRaw, closeButtonVisible, downloadButtonVisible, removeGridComponent, theme, title: title2 = "Spatial Layers", uuid: uuid2, layerPerFeatureForPoints = false, cameraPresets, helpText = ViewHelpMapping.LAYER_CONTROLLER_BETA } = props;
268477
268520
  const loaders = useLoaders();
268478
268521
  const mergeCoordination = useMergeCoordination();
268479
268522
  const coordinationScopes = useCoordinationScopes(coordinationScopesRaw);
@@ -268561,7 +268604,8 @@ function LayerControllerSubscriber(props) {
268561
268604
  CoordinationType$1.TOOLTIPS_VISIBLE,
268562
268605
  CoordinationType$1.SPATIAL_CHANNEL_LABELS_VISIBLE,
268563
268606
  CoordinationType$1.SPATIAL_CHANNEL_LABELS_ORIENTATION,
268564
- CoordinationType$1.SPATIAL_CHANNEL_LABEL_SIZE
268607
+ CoordinationType$1.SPATIAL_CHANNEL_LABEL_SIZE,
268608
+ CoordinationType$1.SPATIAL_CHANNELS_SORT_ORDER
268565
268609
  ], coordinationScopes, coordinationScopesBy, CoordinationType$1.IMAGE_LAYER);
268566
268610
  const imageChannelCoordination = useComplexCoordinationSecondary([
268567
268611
  CoordinationType$1.SPATIAL_TARGET_C,
@@ -268629,7 +268673,7 @@ function LayerControllerSubscriber(props) {
268629
268673
  imageDataStatus,
268630
268674
  pointMultiIndicesDataStatus
268631
268675
  ]);
268632
- return jsx$1(TitleInfo, { title: title2, isScroll: true, closeButtonVisible, downloadButtonVisible, removeGridComponent, theme, isReady, errors, children: jsx$1(LayerController, { theme, coordinationScopesRaw, segmentationLayerScopes, segmentationLayerCoordination, segmentationChannelScopesByLayer, segmentationChannelCoordination, images: imageData, imageLayerScopes, imageLayerCoordination, targetT, targetZ, setTargetT, setTargetZ, spatialRenderingMode, setSpatialRenderingMode, imageChannelScopesByLayer, imageChannelCoordination, spotLayerScopes, spotLayerCoordination, pointLayerScopes, pointLayerCoordination, pointMultiIndicesData, layerPerFeatureForPoints, volumeLoadingStatus, tiledPointsLoadingProgress }) });
268676
+ return jsx$1(TitleInfo, { title: title2, isScroll: true, closeButtonVisible, downloadButtonVisible, removeGridComponent, theme, isReady, errors, helpText, children: jsx$1(LayerController, { theme, coordinationScopesRaw, segmentationLayerScopes, segmentationLayerCoordination, segmentationChannelScopesByLayer, segmentationChannelCoordination, images: imageData, imageLayerScopes, imageLayerCoordination, targetT, targetZ, setTargetT, setTargetZ, spatialRenderingMode, setSpatialRenderingMode, imageChannelScopesByLayer, imageChannelCoordination, spotLayerScopes, spotLayerCoordination, pointLayerScopes, pointLayerCoordination, pointMultiIndicesData, layerPerFeatureForPoints, volumeLoadingStatus, tiledPointsLoadingProgress }) });
268633
268677
  }
268634
268678
  const isIterable$2 = (obj) => Symbol.iterator in obj;
268635
268679
  const hasIterableEntries = (value2) => (
@@ -270544,7 +270588,7 @@ function HiglassGlobalStyles(props) {
270544
270588
  }
270545
270589
  register({ dataFetcher: ZarrMultivecDataFetcher_default, config: ZarrMultivecDataFetcher_default.config }, { pluginType: "dataFetcher" });
270546
270590
  const LazyHiGlassComponent = React__default.lazy(async () => {
270547
- const { HiGlassComponent } = await import("./higlass-DjFeS4wB.js");
270591
+ const { HiGlassComponent } = await import("./higlass-C6IxqTVD.js");
270548
270592
  return { default: HiGlassComponent };
270549
270593
  });
270550
270594
  const HG_SIZE = 800;
@@ -272133,13 +272177,16 @@ const globalNeuroglancerStyles = {
272133
272177
  },
272134
272178
  "input.perspective-panel-show-slice-views": { pointerEvents: "all" },
272135
272179
  ".neuroglancer-rendered-data-panel": {
272136
- cursor: "crosshair",
272180
+ cursor: "grab",
272137
272181
  position: "relative",
272138
272182
  outline: "0",
272139
272183
  touchAction: "none",
272140
272184
  color: "#fff",
272141
272185
  textAlign: "left"
272142
272186
  },
272187
+ ".neuroglancer-rendered-data-panel:active": {
272188
+ cursor: "grabbing"
272189
+ },
272143
272190
  ".neuroglancer-display-dimensions-widget": {
272144
272191
  position: "absolute",
272145
272192
  cursor: "default",
@@ -273492,7 +273539,7 @@ function NeuroglancerGlobalStyles(props) {
273492
273539
  const { classes: classes2 } = props;
273493
273540
  return jsxs(Fragment, { children: [jsx$1(GlobalStyles$3, { styles: globalNeuroglancerCss }), jsx$1(ScopedGlobalStyles, { styles: globalNeuroglancerStyles, parentClassName: classes2.neuroglancerWrapper })] });
273494
273541
  }
273495
- const LazyReactNeuroglancer = React__default.lazy(() => import("./ReactNeuroglancer-BsqPWpQJ.js"));
273542
+ const LazyReactNeuroglancer = React__default.lazy(() => import("./ReactNeuroglancer-Bw5gQWL3.js"));
273496
273543
  function createWorker() {
273497
273544
  const worker = new WorkerFactory$1();
273498
273545
  worker.AsyncComputationWorker = WorkerFactory;
@@ -274182,17 +274229,40 @@ function diffCameraState(prev2, next4) {
274182
274229
  const pos = posHard || posSoft;
274183
274230
  return { changed: scale2 || pos || rot2, scale: scale2, pos, rot: rot2 };
274184
274231
  }
274232
+ const clamp$1 = (value2, min2, max2) => Math.max(min2, Math.min(max2, value2));
274185
274233
  function quaternionToEuler([x2, y2, z2, w2]) {
274186
- const quaternion2 = new Quaternion$1(x2, y2, z2, w2);
274187
- const euler = new Euler$1().setFromQuaternion(quaternion2, "YXZ");
274188
- const pitch = euler.x;
274189
- const yaw = euler.y;
274234
+ const x22 = x2 + x2;
274235
+ const y22 = y2 + y2;
274236
+ const z22 = z2 + z2;
274237
+ const xx = x2 * x22;
274238
+ const yy = y2 * y22;
274239
+ const zz = z2 * z22;
274240
+ const xz = x2 * z22;
274241
+ const yz = y2 * z22;
274242
+ const wx = w2 * x22;
274243
+ const wy = w2 * y22;
274244
+ const m11 = 1 - (yy + zz);
274245
+ const m13 = xz + wy;
274246
+ const m23 = yz - wx;
274247
+ const m31 = xz - wy;
274248
+ const m33 = 1 - (xx + yy);
274249
+ const pitch = Math.asin(-clamp$1(m23, -1, 1));
274250
+ const yaw = Math.abs(m23) < 0.9999999 ? Math.atan2(m13, m33) : Math.atan2(-m31, m11);
274190
274251
  return [pitch, yaw];
274191
274252
  }
274192
274253
  function eulerToQuaternion(pitch, yaw, roll = 0) {
274193
- const euler = new Euler$1(pitch, yaw, roll, "YXZ");
274194
- const quaternion2 = new Quaternion$1().setFromEuler(euler);
274195
- return [quaternion2.x, quaternion2.y, quaternion2.z, quaternion2.w];
274254
+ const c1 = Math.cos(pitch / 2);
274255
+ const c2 = Math.cos(yaw / 2);
274256
+ const c3 = Math.cos(roll / 2);
274257
+ const s1 = Math.sin(pitch / 2);
274258
+ const s2 = Math.sin(yaw / 2);
274259
+ const s3 = Math.sin(roll / 2);
274260
+ return [
274261
+ s1 * c2 * c3 + c1 * s2 * s3,
274262
+ c1 * s2 * c3 - s1 * c2 * s3,
274263
+ c1 * c2 * s3 - s1 * s2 * c3,
274264
+ c1 * c2 * c3 + s1 * s2 * s3
274265
+ ];
274196
274266
  }
274197
274267
  function makeVitNgZoomCalibrator(initialNgProjectionScale, initialDeckZoom = 0) {
274198
274268
  const base2 = initialNgProjectionScale / 2 ** -initialDeckZoom;
@@ -276503,7 +276573,7 @@ function useFilteredVolcanoData(props) {
276503
276573
  const rawSampleSetPathB = coordinationValues.sampleSetFilter[1];
276504
276574
  const sampleSetPathB = [...rawSampleSetPathB];
276505
276575
  sampleSetPathB[0] = sampleSetsColumnNameMappingReversed[rawSampleSetPathB[0]];
276506
- if (isEqual$3(sampleSetPathA, sampleSetSelection[1]) && isEqual$3(sampleSetPathB, sampleSetSelection[0])) {
276576
+ if (isEqual$3(sampleSetPathA, sampleSetSelection[0]) && isEqual$3(sampleSetPathB, sampleSetSelection[1])) {
276507
276577
  shouldSwapFoldChangeDirection = true;
276508
276578
  }
276509
276579
  }
@@ -327333,8 +327403,8 @@ function CellSetSizesPlot(props) {
327333
327403
  value: 0
327334
327404
  }
327335
327405
  },
327336
- width: clamp$7(width2 - marginRight, 10, Infinity),
327337
- height: clamp$7(height2 - marginBottom, 10, Infinity),
327406
+ width: clamp$8(width2 - marginRight, 10, Infinity),
327407
+ height: clamp$8(height2 - marginBottom, 10, Infinity),
327338
327408
  config: VEGA_THEMES[theme]
327339
327409
  };
327340
327410
  const handleSignal = (name2, value2) => {
@@ -327447,8 +327517,8 @@ function ExpressionHistogram(props) {
327447
327517
  select: { type: "interval", encodings: ["x"] }
327448
327518
  }
327449
327519
  ],
327450
- width: clamp$7(width2 - marginRight, 10, Infinity),
327451
- height: clamp$7(height2 - marginBottom, 10, Infinity),
327520
+ width: clamp$8(width2 - marginRight, 10, Infinity),
327521
+ height: clamp$8(height2 - marginBottom, 10, Infinity),
327452
327522
  config: VEGA_THEMES[theme]
327453
327523
  };
327454
327524
  const handleSignal = (name2, value2) => {
@@ -327583,8 +327653,8 @@ function DotPlot(props) {
327583
327653
  const autoMarginForFeature = marginBottom || 30 + Math.sqrt(maxCharactersForFeature / 2) * 30;
327584
327654
  const autoMarginForGroup = marginRight || 30 + Math.sqrt(maxCharactersForGroup / 2) * 30;
327585
327655
  const autoMarginForSampleSet = marginRight || 30 + Math.sqrt(maxCharactersForSampleSet / 2) * 30;
327586
- const plotWidth = transpose2 ? clamp$7(width2 - autoMarginForFeature - 180, 10, Infinity) / (obsSetSelection?.length || 1) : clamp$7(width2 - autoMarginForGroup - autoMarginForSampleSet - 200, 10, Infinity);
327587
- const plotHeight = transpose2 ? clamp$7(height2 - autoMarginForGroup - autoMarginForSampleSet - 50, 10, Infinity) : clamp$7(height2 - autoMarginForFeature - 80, 10, Infinity) / (obsSetSelection?.length || 1);
327656
+ const plotWidth = transpose2 ? clamp$8(width2 - autoMarginForFeature - 180, 10, Infinity) / (obsSetSelection?.length || 1) : clamp$8(width2 - autoMarginForGroup - autoMarginForSampleSet - 200, 10, Infinity);
327657
+ const plotHeight = transpose2 ? clamp$8(height2 - autoMarginForGroup - autoMarginForSampleSet - 50, 10, Infinity) : clamp$8(height2 - autoMarginForFeature - 80, 10, Infinity) / (obsSetSelection?.length || 1);
327588
327658
  const groupKeys = data2.map((d) => d.keyGroup);
327589
327659
  const featureKeys = data2.map((d) => d.keyFeature);
327590
327660
  const groupSecondaryKeys = data2.map((d) => d.keyGroupSecondary);
@@ -328257,6 +328327,10 @@ function TreemapSubscriber(props) {
328257
328327
  }, [setObsSetSelection]);
328258
328328
  return jsxs(TitleInfo, { title: `Treemap of ${capitalize$3(pluralize(obsType, 2))}`, info: `${commaNumber(selectedObsCount)} ${pluralize(obsType, selectedObsCount)} from ${commaNumber(selectedSampleCount)} ${pluralize(sampleType, selectedSampleCount)}`, removeGridComponent, urls: urls2, theme, isReady, helpText, errors, withPadding: false, options: jsx$1(TreemapOptions, { obsType, sampleType, obsColorEncoding, setObsColorEncoding, hierarchyLevels: hierarchyLevels || DEFAULT_HIERARCHY_LEVELS, setHierarchyLevels }), children: [jsx$1("div", { ref: containerRef, className: classes2.vegaContainer, children: jsx$1(Treemap, { obsCounts, sampleCounts, obsColorEncoding, hierarchyLevels: hierarchyLevels || DEFAULT_HIERARCHY_LEVELS, theme, width: width2, height: Math.max(height2 * (selectedObsCount / totalObsCount), 40), obsType, sampleType, obsSetColor, sampleSetColor, obsSetSelection, sampleSetSelection, onNodeClick }) }), jsx$1("div", { style: { position: "absolute", right: "2px", bottom: "2px", fontSize: "10px" }, children: unselectedObsCount > 0 ? jsx$1("span", { children: `${commaNumber(unselectedObsCount)} ${pluralize(obsType, unselectedObsCount)} from ${commaNumber(unselectedSampleCount)} ${pluralize(sampleType, unselectedSampleCount)} currently omitted` }) : null })] });
328259
328329
  }
328330
+ const GOLDEN_RATIO = 0.6180339887498948;
328331
+ function topJitter(index2, rangePixels) {
328332
+ return index2 * GOLDEN_RATIO % 1 * rangePixels;
328333
+ }
328260
328334
  function VolcanoPlot(props) {
328261
328335
  const { theme, width: width2, height: height2, obsType, featureType, obsSetsColumnNameMappingReversed, sampleSetsColumnNameMappingReversed, sampleSetSelection, obsSetSelection, obsSetColor, sampleSetColor, data: data2, marginTop = 5, marginRight = 5, marginLeft = 50, marginBottom = 50, onFeatureClick, featurePointSignificanceThreshold, featurePointFoldChangeThreshold, featureLabelSignificanceThreshold, featureLabelFoldChangeThreshold } = props;
328262
328336
  const svgRef = useRef();
@@ -328318,10 +328392,10 @@ function VolcanoPlot(props) {
328318
328392
  const obsSetPath2 = [...rawObsSetPath];
328319
328393
  obsSetPath2[0] = obsSetsColumnNameMappingReversed[rawObsSetPath[0]];
328320
328394
  const color2 = obsSetColorScale(obsSetPath2);
328321
- obsSetG.append("g").selectAll("circle").data(filteredDf).join("circle").attr("cx", (d) => xScale(d.logFoldChange)).attr("cy", (d) => yScale(d.minusLog10p)).attr("r", 3).attr("opacity", 0.5).attr("fill", color2).on("click", (event2, d) => {
328395
+ obsSetG.append("g").selectAll("circle").data(filteredDf).join("circle").attr("cx", (d) => xScale(d.logFoldChange)).attr("cy", (d, i2) => yScale(d.minusLog10p) + (!Number.isFinite(d.minusLog10p) ? topJitter(i2, 20) : 0)).attr("r", 3).attr("opacity", 0.5).attr("fill", color2).on("click", (event2, d) => {
328322
328396
  onFeatureClick(d.featureId);
328323
328397
  });
328324
- const textElements = obsSetG.append("g").selectAll("text").data(filteredDf).join("text").text((d) => d.featureId).attr("text-anchor", (d) => d.logFoldChange < 0 ? "end" : "start").attr("x", (d) => xScale(d.logFoldChange)).attr("y", (d) => yScale(d.minusLog10p)).style("display", (d) => Math.abs(d.logFoldChange) < (featureLabelFoldChangeThreshold ?? 5) || d.featureSignificance >= (featureLabelSignificanceThreshold ?? 0.01) ? "none" : void 0).attr("fill", color2).on("click", (event2, d) => {
328398
+ const textElements = obsSetG.append("g").selectAll("text").data(filteredDf).join("text").text((d) => d.featureId).attr("text-anchor", (d) => d.logFoldChange < 0 ? "end" : "start").attr("x", (d) => xScale(d.logFoldChange)).attr("y", (d, i2) => yScale(d.minusLog10p) + (!Number.isFinite(d.minusLog10p) ? topJitter(i2, 20) : 0)).style("display", (d) => Math.abs(d.logFoldChange) < (featureLabelFoldChangeThreshold ?? 5) || d.featureSignificance >= (featureLabelSignificanceThreshold ?? 0.01) ? "none" : void 0).attr("fill", color2).on("click", (event2, d) => {
328325
328399
  onFeatureClick(d.featureId);
328326
328400
  });
328327
328401
  textElements.append("title").text((d) => `${featureType}: ${d.featureId}
@@ -328580,8 +328654,8 @@ function CellSetCompositionBarPlot(props) {
328580
328654
  }
328581
328655
  },
328582
328656
  // TODO: for width, also subtract length of longest y-axis set name label.
328583
- width: clamp$7(width2 - marginRight, 10, Infinity),
328584
- height: clamp$7(height2 - marginBottom, 10, Infinity),
328657
+ width: clamp$8(width2 - marginRight, 10, Infinity),
328658
+ height: clamp$8(height2 - marginBottom, 10, Infinity),
328585
328659
  config: VEGA_THEMES[theme]
328586
328660
  };
328587
328661
  const handleSignal = (name2, value2) => {
@@ -328762,8 +328836,8 @@ function FeatureSetEnrichmentBarPlot(props) {
328762
328836
  }
328763
328837
  },
328764
328838
  // TODO: for width, also subtract length of longest y-axis set name label.
328765
- width: clamp$7(width2 - marginRight, 10, Infinity),
328766
- height: clamp$7(height2 - marginBottom, 10, Infinity),
328839
+ width: clamp$8(width2 - marginRight, 10, Infinity),
328840
+ height: clamp$8(height2 - marginBottom, 10, Infinity),
328767
328841
  config: VEGA_THEMES[theme]
328768
328842
  };
328769
328843
  const handleSignal = (name2, value2) => {
@@ -329982,7 +330056,9 @@ const fileTypeToExtensions = {
329982
330056
  // TODO: how to handle h5ad-based AnnData (since needs reference JSON file).
329983
330057
  // Perhaps just assume one H5AD+one JSON (or .ref.json) file correspond to each other?
329984
330058
  [FileType$1.SPATIALDATA_ZARR]: [".sd.zarr", ".sdata.zarr", ".spatialdata.zarr"],
329985
- [FileType$1.SPATIALDATA_ZARR_ZIP]: [".sd.zarr.zip", ".sdata.zarr.zip", ".spatialdata.zarr.zip"]
330059
+ [FileType$1.SPATIALDATA_ZARR_ZIP]: [".sd.zarr.zip", ".sdata.zarr.zip", ".spatialdata.zarr.zip"],
330060
+ [FileType$1.GENOMIC_PROFILES_ZARR]: [".multivec.zarr"],
330061
+ [FileType$1.GENOMIC_PROFILES_ZARR_ZIP]: [".multivec.zarr.zip"]
329986
330062
  };
329987
330063
  const fileTypeToClass = {
329988
330064
  // OME-TIFF
@@ -330008,7 +330084,9 @@ const ZARR_FILETYPES = [
330008
330084
  FileType$1.IMAGE_OME_ZARR,
330009
330085
  FileType$1.IMAGE_OME_ZARR_ZIP,
330010
330086
  FileType$1.OBS_SEGMENTATIONS_OME_ZARR,
330011
- FileType$1.OBS_SEGMENTATIONS_OME_ZARR_ZIP
330087
+ FileType$1.OBS_SEGMENTATIONS_OME_ZARR_ZIP,
330088
+ FileType$1.GENOMIC_PROFILES_ZARR,
330089
+ FileType$1.GENOMIC_PROFILES_ZARR_ZIP
330012
330090
  ];
330013
330091
  function urlToFileType(url) {
330014
330092
  const match2 = Object.entries(fileTypeToExtensions).find(
@@ -330164,6 +330242,102 @@ async function generateConfig(parsedUrls, layoutOption = null) {
330164
330242
  stores
330165
330243
  };
330166
330244
  }
330245
+ var fetchJsonp$1 = { exports: {} };
330246
+ var fetchJsonp = fetchJsonp$1.exports;
330247
+ var hasRequiredFetchJsonp;
330248
+ function requireFetchJsonp() {
330249
+ if (hasRequiredFetchJsonp) return fetchJsonp$1.exports;
330250
+ hasRequiredFetchJsonp = 1;
330251
+ (function(module2, exports2) {
330252
+ (function(global2, factory2) {
330253
+ {
330254
+ factory2(exports2, module2);
330255
+ }
330256
+ })(fetchJsonp, function(exports3, module3) {
330257
+ var defaultOptions = {
330258
+ timeout: 5e3,
330259
+ jsonpCallback: "callback"
330260
+ };
330261
+ function generateCallbackFunction() {
330262
+ return "jsonp_" + Date.now() + "_" + Math.ceil(Math.random() * 1e5);
330263
+ }
330264
+ function clearFunction(functionName) {
330265
+ try {
330266
+ delete window[functionName];
330267
+ } catch (e3) {
330268
+ window[functionName] = void 0;
330269
+ }
330270
+ }
330271
+ function removeScript(scriptId) {
330272
+ var script = document.getElementById(scriptId);
330273
+ if (script) {
330274
+ document.getElementsByTagName("head")[0].removeChild(script);
330275
+ }
330276
+ }
330277
+ function fetchJsonp2(_url) {
330278
+ var options = arguments.length <= 1 || arguments[1] === void 0 ? {} : arguments[1];
330279
+ var url = _url;
330280
+ var timeout3 = options.timeout || defaultOptions.timeout;
330281
+ var jsonpCallback = options.jsonpCallback || defaultOptions.jsonpCallback;
330282
+ var timeoutId = void 0;
330283
+ return new Promise(function(resolve2, reject) {
330284
+ var callbackFunction = options.jsonpCallbackFunction || generateCallbackFunction();
330285
+ var scriptId = jsonpCallback + "_" + callbackFunction;
330286
+ window[callbackFunction] = function(response) {
330287
+ resolve2({
330288
+ ok: true,
330289
+ // keep consistent with fetch API
330290
+ json: function json2() {
330291
+ return Promise.resolve(response);
330292
+ }
330293
+ });
330294
+ if (timeoutId) clearTimeout(timeoutId);
330295
+ removeScript(scriptId);
330296
+ clearFunction(callbackFunction);
330297
+ };
330298
+ url += url.indexOf("?") === -1 ? "?" : "&";
330299
+ var jsonpScript = document.createElement("script");
330300
+ jsonpScript.setAttribute("src", "" + url + jsonpCallback + "=" + callbackFunction);
330301
+ if (options.charset) {
330302
+ jsonpScript.setAttribute("charset", options.charset);
330303
+ }
330304
+ if (options.nonce) {
330305
+ jsonpScript.setAttribute("nonce", options.nonce);
330306
+ }
330307
+ if (options.referrerPolicy) {
330308
+ jsonpScript.setAttribute("referrerPolicy", options.referrerPolicy);
330309
+ }
330310
+ if (options.crossorigin) {
330311
+ jsonpScript.setAttribute("crossorigin", typeof options.crossorigin === "string" ? options.crossorigin : "anonymous");
330312
+ }
330313
+ var fp = options.fetchPriority;
330314
+ if (fp === "high" || fp === "low" || fp === "auto") {
330315
+ jsonpScript.setAttribute("fetchPriority", fp);
330316
+ }
330317
+ jsonpScript.id = scriptId;
330318
+ document.getElementsByTagName("head")[0].appendChild(jsonpScript);
330319
+ timeoutId = setTimeout(function() {
330320
+ reject(new Error("JSONP request to " + _url + " timed out"));
330321
+ clearFunction(callbackFunction);
330322
+ removeScript(scriptId);
330323
+ window[callbackFunction] = function() {
330324
+ clearFunction(callbackFunction);
330325
+ };
330326
+ }, timeout3);
330327
+ jsonpScript.onerror = function() {
330328
+ reject(new Error("JSONP request to " + _url + " failed"));
330329
+ clearFunction(callbackFunction);
330330
+ removeScript(scriptId);
330331
+ if (timeoutId) clearTimeout(timeoutId);
330332
+ };
330333
+ });
330334
+ }
330335
+ module3.exports = fetchJsonp2;
330336
+ });
330337
+ })(fetchJsonp$1, fetchJsonp$1.exports);
330338
+ return fetchJsonp$1.exports;
330339
+ }
330340
+ requireFetchJsonp();
330167
330341
  class ObsSpotsCsvLoader extends CsvLoader {
330168
330342
  loadFromCache(data2) {
330169
330343
  if (this.cachedResult) {
@@ -331078,11 +331252,21 @@ class AnnDataSource extends ZarrDataSource {
331078
331252
  categoriesValues = await this.getFlatArrDecompressed(`${prefix2}/${categories}`);
331079
331253
  }
331080
331254
  } else if (encodingType === "categorical") {
331081
- const { dtype } = await open$1(storeRoot.resolve(`${path2}/categories`), { kind: "array" });
331082
- if (dtype === "v2:object" || dtype === "|O") {
331255
+ const categoriesZattrs = await this.getJson(`${path2}/categories/.zattrs`);
331256
+ const categoriesEncodingType = categoriesZattrs?.["encoding-type"];
331257
+ if (categoriesEncodingType === "nullable-string-array") {
331258
+ categoriesValues = await this.getFlatArrDecompressed(`${path2}/categories/values`);
331259
+ } else if (categoriesEncodingType === "string-array") {
331083
331260
  categoriesValues = await this.getFlatArrDecompressed(`${path2}/categories`);
331261
+ } else {
331262
+ const { dtype } = await open$1(storeRoot.resolve(`${path2}/categories`), { kind: "array" });
331263
+ if (dtype === "v2:object" || dtype === "|O") {
331264
+ categoriesValues = await this.getFlatArrDecompressed(`${path2}/categories`);
331265
+ }
331084
331266
  }
331085
331267
  codesPath = `${path2}/codes`;
331268
+ } else if (encodingType === "nullable-string-array") {
331269
+ return this.getFlatArrDecompressed(`${path2}/values`);
331086
331270
  } else if (encodingType === "string-array") {
331087
331271
  return this.getFlatArrDecompressed(path2);
331088
331272
  } else {
@@ -332246,16 +332430,25 @@ let FeatureStatsAnndataLoader$1 = class FeatureStatsAnndataLoader extends Abstra
332246
332430
  return this.dataSource.loadDataFrameIndex(dfPath);
332247
332431
  }
332248
332432
  async loadDataFrame(dfPath) {
332249
- const [featureId2, featureFoldChange, featureSignificance] = await Promise.all([
332250
- this.loadFeatureNames(dfPath),
332251
- this.loadFoldChanges(dfPath),
332252
- this.loadSignificances(dfPath)
332253
- ]);
332254
- return {
332255
- featureId: featureId2,
332256
- featureFoldChange,
332257
- featureSignificance
332258
- };
332433
+ try {
332434
+ const [featureId2, featureFoldChange, featureSignificance] = await Promise.all([
332435
+ this.loadFeatureNames(dfPath),
332436
+ this.loadFoldChanges(dfPath),
332437
+ this.loadSignificances(dfPath)
332438
+ ]);
332439
+ return {
332440
+ featureId: featureId2,
332441
+ featureFoldChange,
332442
+ featureSignificance
332443
+ };
332444
+ } catch (e3) {
332445
+ log$b.warn("Dataframe not found at", dfPath);
332446
+ return {
332447
+ featureId: [],
332448
+ featureFoldChange: [],
332449
+ featureSignificance: []
332450
+ };
332451
+ }
332259
332452
  }
332260
332453
  /**
332261
332454
  *
@@ -332282,7 +332475,7 @@ let FeatureStatsAnndataLoader$1 = class FeatureStatsAnndataLoader extends Abstra
332282
332475
  * @returns {Promise<LoaderResult<FeatureStatsData>>}
332283
332476
  */
332284
332477
  async loadMulti(volcanoOptions) {
332285
- const { analysisType: targetAnalysisType = "rank_genes_groups" } = this.options;
332478
+ const { analysisType: targetAnalysisType = "pydeseq2" } = this.options;
332286
332479
  const { sampleSetSelection, obsSetSelection } = volcanoOptions || {};
332287
332480
  const rawObsSetSelection = obsSetSelection;
332288
332481
  const rawSampleSetSelection = sampleSetSelection;
@@ -333260,7 +333453,7 @@ class SpatialDataObsSpotsLoader extends AbstractTwoStepLoader {
333260
333453
  const formatVersion = await this.dataSource.getShapesFormatVersion(path2);
333261
333454
  if (formatVersion === "0.1") {
333262
333455
  locations = await this.dataSource.loadNumericForDims(getCoordsPath(path2), [0, 1]);
333263
- } else if (formatVersion === "0.2") {
333456
+ } else if (formatVersion === "0.2" || formatVersion === "0.3") {
333264
333457
  locations = await this.dataSource.loadCircleShapes(getGeometryPath$1(path2));
333265
333458
  }
333266
333459
  this.locations = locations;
@@ -333459,7 +333652,7 @@ class SpatialDataObsPointsLoader extends AbstractTwoStepLoader {
333459
333652
  }
333460
333653
  let locations;
333461
333654
  const formatVersion = await this.dataSource.getPointsFormatVersion(path2);
333462
- if (formatVersion === "0.1") {
333655
+ if (formatVersion === "0.1" || formatVersion === "0.2") {
333463
333656
  locations = await this.dataSource.loadPoints(path2);
333464
333657
  } else {
333465
333658
  throw new UnknownSpatialDataFormatError("Only points format version 0.1 is supported.");
@@ -333478,7 +333671,7 @@ class SpatialDataObsPointsLoader extends AbstractTwoStepLoader {
333478
333671
  }
333479
333672
  let locationsFeatureIndex;
333480
333673
  const formatVersion = await this.dataSource.getPointsFormatVersion(path2);
333481
- if (formatVersion === "0.1") {
333674
+ if (formatVersion === "0.1" || formatVersion === "0.2") {
333482
333675
  locationsFeatureIndex = await this.dataSource.loadPointsFeatureIds(path2);
333483
333676
  } else {
333484
333677
  throw new UnknownSpatialDataFormatError("Only points format version 0.1 is supported.");
@@ -333490,7 +333683,7 @@ class SpatialDataObsPointsLoader extends AbstractTwoStepLoader {
333490
333683
  const { path: path2, featureIndexColumn, mortonCodeColumn } = this.options;
333491
333684
  let locations;
333492
333685
  const formatVersion = await this.dataSource.getPointsFormatVersion(path2);
333493
- if (formatVersion === "0.1") {
333686
+ if (formatVersion === "0.1" || formatVersion === "0.2") {
333494
333687
  locations = await this.dataSource.loadPointsInRect(path2, bounds2, signal, featureIndexColumn, mortonCodeColumn);
333495
333688
  } else {
333496
333689
  throw new UnknownSpatialDataFormatError("Only points format version 0.1 is supported.");
@@ -333522,10 +333715,8 @@ class SpatialDataObsPointsLoader extends AbstractTwoStepLoader {
333522
333715
  // and for the presence of morton_code_2d and feature_index columns.
333523
333716
  this.dataSource.supportsLoadPointsInRect(path2, featureIndexColumnName, mortonCodeColumn)
333524
333717
  ]);
333525
- const isSupportedVersion = formatVersion === "0.1";
333526
- const boundingBox = zattrs?.bounding_box;
333527
- const hasBoundingBox2D = typeof boundingBox?.x_max === "number" && typeof boundingBox?.x_min === "number" && typeof boundingBox?.y_max === "number" && typeof boundingBox?.y_min === "number";
333528
- return isSupportedVersion && hasBoundingBox2D && hasRequiredColumnsAndRowGroupSize;
333718
+ const isSupportedVersion = formatVersion === "0.1" || formatVersion === "0.2";
333719
+ return isSupportedVersion && hasRequiredColumnsAndRowGroupSize;
333529
333720
  }
333530
333721
  async load() {
333531
333722
  const [modelMatrix2, supportsTiling] = await Promise.all([
@@ -333563,7 +333754,7 @@ class SpatialDataObsPointsLoader extends AbstractTwoStepLoader {
333563
333754
  featureIds,
333564
333755
  obsPointsModelMatrix: modelMatrix2,
333565
333756
  // Return 'tiled' if the morton_code_2d column
333566
- // and bounding_box metadata are present,
333757
+ // is present,
333567
333758
  // and the row group size is small enough.
333568
333759
  // Otherwise, return 'full'.
333569
333760
  obsPointsTilingType: supportsTiling ? "tiled" : "full",
@@ -343072,6 +343263,7 @@ function sdataMortonQueryRectAux(boundingBox, origRect) {
343072
343263
  const mortonIntervals = zcoverRectangle(normRect[0][0], normRect[0][1], normRect[1][0], normRect[1][1], 16, null, true);
343073
343264
  return mortonIntervals;
343074
343265
  }
343266
+ const MORTON_CODE_EXTREME_VALUE_INDICATOR = 0;
343075
343267
  async function getParquetModule() {
343076
343268
  const module2 = await import(
343077
343269
  /* webpackIgnore: true */
@@ -343150,7 +343342,7 @@ async function _loadParquetSchemaBytes({ queryClient, store }, parquetPath, part
343150
343342
  if (!tailBytes || tailBytes.length < TAIL_LENGTH) {
343151
343343
  throw new Error(`Failed to load parquet footerLength for ${partZeroPath}`);
343152
343344
  }
343153
- const footerLength = new DataView(tailBytes.buffer).getInt32(0, true);
343345
+ const footerLength = new DataView(tailBytes.buffer, tailBytes.byteOffset, tailBytes.byteLength).getInt32(0, true);
343154
343346
  const magic = new TextDecoder().decode(tailBytes.slice(4, 8));
343155
343347
  if (magic !== "PAR1") {
343156
343348
  throw new Error("Invalid Parquet file: missing PAR1 magic number");
@@ -343197,22 +343389,22 @@ async function _loadParquetMetadataByPart({ queryClient, store }, parquetPath) {
343197
343389
  } catch (error2) {
343198
343390
  if (error2.message.includes("Failed to load parquet footerLength")) {
343199
343391
  numParts = partIndex;
343392
+ log$b.info(`Found ${numParts} parts for parquet path ${parquetPath}; An above "Failed to load parquet footerLength" error is expected for the subsequent part.`);
343200
343393
  }
343201
343394
  }
343202
343395
  } while (numParts === void 0);
343396
+ const numRows = allMetadata.map((part) => part.metadata.fileMetadata().numRows());
343397
+ const numRowGroups = allMetadata.map((part) => part.metadata.numRowGroups());
343398
+ const numRowsPerGroup = allMetadata.map((part) => part.metadata.rowGroup(0).numRows());
343203
343399
  const metadata2 = {
343204
- numRows: 0,
343205
- numRowGroups: 0,
343206
- numRowsPerGroup: 0,
343207
- schema: null
343208
- };
343209
- if (allMetadata.length > 0) {
343210
- const firstPart = allMetadata[0];
343211
- metadata2.numRows = allMetadata.reduce((sum2, part) => sum2 + part.metadata.fileMetadata().numRows(), 0);
343212
- metadata2.numRowGroups = allMetadata.reduce((sum2, part) => sum2 + part.metadata.numRowGroups(), 0);
343213
- metadata2.numRowsPerGroup = firstPart.metadata.rowGroup(0).numRows();
343214
- metadata2.schema = firstPart.schema.schema;
343215
- }
343400
+ totalNumRows: numRows.reduce((a2, b2) => a2 + b2, 0),
343401
+ totalNumRowGroups: numRowGroups.reduce((a2, b2) => a2 + b2, 0),
343402
+ // Array of count per part (length equal to numParts).
343403
+ numRowsByPart: numRows,
343404
+ numRowGroupsByPart: numRowGroups,
343405
+ numRowsPerGroupByPart: numRowsPerGroup,
343406
+ schema: allMetadata?.[0]?.schema?.schema
343407
+ };
343216
343408
  const result = {
343217
343409
  ...metadata2,
343218
343410
  // TODO: extract metadata per part and rowGroup into plain objects that match the hyparquet parquetMetadata() return value?
@@ -343236,8 +343428,8 @@ async function _loadParquetRowGroupByGroupIndex({ queryClient, store }, parquetP
343236
343428
  const store2 = ctx.meta?.store;
343237
343429
  const { readParquetRowGroup } = await _getParquetModule({ queryClient: queryClient2 });
343238
343430
  const allMetadata = await _loadParquetMetadataByPart({ queryClient: queryClient2, store: store2 }, parquetPath);
343239
- if (rowGroupIndex < 0 || rowGroupIndex >= allMetadata.numRowGroups) {
343240
- throw new Error(`Row group index ${rowGroupIndex} is out of bounds for parquet table with ${allMetadata.numRowGroups} row groups.`);
343431
+ if (rowGroupIndex < 0 || rowGroupIndex >= allMetadata.totalNumRowGroups) {
343432
+ throw new Error(`Row group index ${rowGroupIndex} is out of bounds for parquet table with ${allMetadata.totalNumRowGroups} row groups.`);
343241
343433
  }
343242
343434
  let partIndex;
343243
343435
  let cumulativeRowGroups = 0;
@@ -343347,9 +343539,9 @@ async function _bisectRowGroupsRight({ queryClient, store }, parquetPath, column
343347
343539
  );
343348
343540
  const store2 = ctx.meta?.store;
343349
343541
  const allMetadata = await _loadParquetMetadataByPart({ queryClient: queryClient2, store: store2 }, parquetPath);
343350
- const { numRowGroups } = allMetadata;
343542
+ const { totalNumRowGroups } = allMetadata;
343351
343543
  let lo = 0;
343352
- let hi = numRowGroups;
343544
+ let hi = totalNumRowGroups;
343353
343545
  while (lo < hi) {
343354
343546
  const cachedInRange = await getCachedInRange(queryClient2, parquetPath, columnName, lo, hi);
343355
343547
  const betterLo = cachedInRange.slice().reverse().find((c2) => c2.index > lo && targetValue >= c2.max);
@@ -343752,11 +343944,12 @@ class SpatialDataTableSource extends AnnDataSource {
343752
343944
  const { queryClient } = this;
343753
343945
  const { store } = this.storeRoot;
343754
343946
  const allMetadata = await _loadParquetMetadataByPart({ queryClient, store }, parquetPath);
343755
- const { numRowsPerGroup } = allMetadata;
343756
- const numRowsTotal = allMetadata.numRows;
343757
- if (numRowsPerGroup >= 1e5) {
343947
+ const { numRowsPerGroupByPart } = allMetadata;
343948
+ const numRowsTotal = allMetadata.totalNumRows;
343949
+ const maxNumRowsPerGroup = Math.max(...numRowsPerGroupByPart);
343950
+ if (maxNumRowsPerGroup >= 1e5) {
343758
343951
  if (numRowsTotal > 5e6) {
343759
- throw new Error(`The Parquet table at ${parquetPath} has ${numRowsTotal} total rows, which necessitates tiled loading, but it was not possible because the row group size is too large (${numRowsPerGroup}). See the Vitessce documentation at Data Troubleshooting -> Points for more details.`);
343952
+ throw new Error(`The Parquet table at ${parquetPath} has ${numRowsTotal} total rows, which necessitates tiled loading, but it was not possible because the row group size is too large (${maxNumRowsPerGroup}). See the Vitessce documentation at Data Troubleshooting -> Points for more details.`);
343760
343953
  }
343761
343954
  return false;
343762
343955
  }
@@ -343780,7 +343973,7 @@ class SpatialDataTableSource extends AnnDataSource {
343780
343973
  * @param {string[]|undefined} columns An optional list of column names to load.
343781
343974
  * @returns
343782
343975
  */
343783
- async loadParquetTableInRect(parquetPath, tileBbox, allPointsBbox, signal, featureIndexColumnName, mortonCodeColumn) {
343976
+ async loadParquetTableInRect(parquetPath, tileBbox, signal, featureIndexColumnName, mortonCodeColumn) {
343784
343977
  const { queryClient } = this;
343785
343978
  const { store } = this.storeRoot;
343786
343979
  const mortonCodeColumnName = mortonCodeColumn ?? "morton_code_2d";
@@ -343805,15 +343998,46 @@ class SpatialDataTableSource extends AnnDataSource {
343805
343998
  } else {
343806
343999
  tileBboxes = [tileBbox];
343807
344000
  }
344001
+ const firstRowGroupTable = await _loadParquetRowGroupByGroupIndex({ queryClient, store }, parquetPath, 0);
344002
+ const xColumnForBoundingBox = firstRowGroupTable.getChild("x");
344003
+ const yColumnForBoundingBox = firstRowGroupTable.getChild("y");
344004
+ const mortonCodeColumnForBoundingBox = firstRowGroupTable.getChild(mortonCodeColumnName);
344005
+ const boundingBoxMaxNumRows = Math.min(4, firstRowGroupTable.numRows);
344006
+ const firstMortonCodes = range$e(boundingBoxMaxNumRows).map((i2) => mortonCodeColumnForBoundingBox.get(i2));
344007
+ const boundingBoxNumRows = firstMortonCodes.filter((code2) => code2 === MORTON_CODE_EXTREME_VALUE_INDICATOR).length;
344008
+ const boundingBoxXValues = range$e(boundingBoxNumRows).map((i2) => xColumnForBoundingBox.get(i2));
344009
+ const boundingBoxYValues = range$e(boundingBoxNumRows).map((i2) => yColumnForBoundingBox.get(i2));
344010
+ const xMin = Math.min(...boundingBoxXValues);
344011
+ const xMax = Math.max(...boundingBoxXValues);
344012
+ const yMin = Math.min(...boundingBoxYValues);
344013
+ const yMax = Math.max(...boundingBoxYValues);
344014
+ const allPointsBbox = {
344015
+ x_min: xMin,
344016
+ x_max: xMax,
344017
+ y_min: yMin,
344018
+ y_max: yMax
344019
+ };
343808
344020
  const rowGroupIndicesPerTile = await Promise.all(tileBboxes.map(async (subTileBbox) => _rectToRowGroupIndices({ queryClient, store }, parquetPath, subTileBbox, allPointsBbox, mortonCodeColumnName)));
343809
344021
  const uniqueCoveredRowGroupIndices = Array.from(new Set(rowGroupIndicesPerTile.flat())).toSorted((a2, b2) => a2 - b2);
343810
344022
  const allMetadata = await _loadParquetMetadataByPart({ queryClient, store }, parquetPath);
343811
- const { numRowsPerGroup } = allMetadata;
343812
- const numRowGroups = uniqueCoveredRowGroupIndices.length;
343813
- const totalNumRows = numRowsPerGroup * numRowGroups;
343814
- const xArr = new Float32Array(totalNumRows);
343815
- const yArr = new Float32Array(totalNumRows);
343816
- const featureIndexArr = new Uint32Array(totalNumRows);
344023
+ const { numRowsPerGroupByPart, numRowGroupsByPart } = allMetadata;
344024
+ const rowGroupIToNumRows = (rowGroupI) => {
344025
+ let currPartIndex = 0;
344026
+ let prevTotalRowGroupCount = 0;
344027
+ for (let partIndex = 0; partIndex < numRowGroupsByPart.length; partIndex++) {
344028
+ const numRowGroupsInPart = numRowGroupsByPart[partIndex];
344029
+ if (prevTotalRowGroupCount <= rowGroupI && rowGroupI < prevTotalRowGroupCount + numRowGroupsInPart) {
344030
+ currPartIndex = partIndex;
344031
+ break;
344032
+ }
344033
+ prevTotalRowGroupCount += numRowGroupsInPart;
344034
+ }
344035
+ return numRowsPerGroupByPart[currPartIndex];
344036
+ };
344037
+ const totalNumRowsToLoad = uniqueCoveredRowGroupIndices.reduce((acc, rowGroupI) => acc + rowGroupIToNumRows(rowGroupI), 0);
344038
+ const xArr = new Float32Array(totalNumRowsToLoad);
344039
+ const yArr = new Float32Array(totalNumRowsToLoad);
344040
+ const featureIndexArr = new Uint32Array(totalNumRowsToLoad);
343817
344041
  const rowGroupTables = await Promise.all(uniqueCoveredRowGroupIndices.map(async (rowGroupIndex) => _loadParquetRowGroupByGroupIndex({ queryClient, store }, parquetPath, rowGroupIndex)));
343818
344042
  let rowOffset = 0;
343819
344043
  rowGroupTables.forEach((table2) => {
@@ -343826,7 +344050,7 @@ class SpatialDataTableSource extends AnnDataSource {
343826
344050
  xArr.set(xColumn.toArray(), rowOffset);
343827
344051
  yArr.set(yColumn.toArray(), rowOffset);
343828
344052
  featureIndexArr.set(featureIndexColumn.toArray(), rowOffset);
343829
- rowOffset += numRowsPerGroup;
344053
+ rowOffset += table2.numRows;
343830
344054
  });
343831
344055
  return {
343832
344056
  data: {
@@ -343834,7 +344058,7 @@ class SpatialDataTableSource extends AnnDataSource {
343834
344058
  y: yArr,
343835
344059
  featureIndices: featureIndexArr
343836
344060
  },
343837
- shape: [3, totalNumRows]
344061
+ shape: [3, totalNumRowsToLoad]
343838
344062
  };
343839
344063
  }
343840
344064
  }
@@ -349710,14 +349934,14 @@ class SpatialDataShapesSource extends SpatialDataTableSource {
349710
349934
  /**
349711
349935
  *
349712
349936
  * @param {string} path A path to within shapes.
349713
- * @returns {Promise<"0.1"|"0.2">} The format version.
349937
+ * @returns {Promise<"0.1"|"0.2"|"0.3">} The format version.
349714
349938
  */
349715
349939
  async getShapesFormatVersion(path2) {
349716
349940
  const zattrs = await this.loadSpatialDataElementAttrs(path2);
349717
349941
  const formatVersion = zattrs.spatialdata_attrs.version;
349718
349942
  const geos = zattrs.spatialdata_attrs.geos || {};
349719
349943
  const encodingType = zattrs["encoding-type"];
349720
- if (encodingType !== "ngff:shapes" || !(formatVersion === "0.1" && (geos.name === "POINT" && geos.type === 0) || formatVersion === "0.2")) {
349944
+ if (encodingType !== "ngff:shapes" || !(formatVersion === "0.1" && (geos.name === "POINT" && geos.type === 0) || formatVersion === "0.2" || formatVersion === "0.3")) {
349721
349945
  throw new Error(`Unexpected encoding type or version for shapes spatialdata_attrs: ${encodingType} ${formatVersion}`);
349722
349946
  }
349723
349947
  return formatVersion;
@@ -349926,7 +350150,7 @@ class SpatialDataPointsSource extends SpatialDataTableSource {
349926
350150
  const zattrs = await this.loadSpatialDataElementAttrs(path2);
349927
350151
  const formatVersion = zattrs.spatialdata_attrs.version;
349928
350152
  const encodingType = zattrs["encoding-type"];
349929
- if (encodingType === "ngff:points" && !(formatVersion === "0.1")) {
350153
+ if (encodingType === "ngff:points" && !(formatVersion === "0.1" || formatVersion === "0.2")) {
349930
350154
  throw new Error(`Unexpected version for points spatialdata_attrs: ${formatVersion}`);
349931
350155
  }
349932
350156
  return formatVersion;
@@ -350029,16 +350253,11 @@ class SpatialDataPointsSource extends SpatialDataTableSource {
350029
350253
  const zattrs = await this.loadSpatialDataElementAttrs(elementPath);
350030
350254
  const {
350031
350255
  // axes,
350032
- spatialdata_attrs: spatialDataAttrs,
350033
- // The bounding box (extent) of all points.
350034
- // Required for un-normalization from uints back to floats.
350035
- // TODO: decide whether these will be stored here or somewhere else.
350036
- // Reference: https://github.com/vitessce/vitessce-python/pull/476#issuecomment-3362656956
350037
- bounding_box: allPointsBbox
350256
+ spatialdata_attrs: spatialDataAttrs
350038
350257
  } = zattrs;
350039
350258
  const { feature_key: featureKey } = spatialDataAttrs;
350040
350259
  const featureIndexColumnName = featureIndexColumnNameFromOptions ?? `${featureKey}_codes`;
350041
- return this.loadParquetTableInRect(parquetPath, tileBbox, allPointsBbox, signal, featureIndexColumnName, mortonCodeColumn);
350260
+ return this.loadParquetTableInRect(parquetPath, tileBbox, signal, featureIndexColumnName, mortonCodeColumn);
350042
350261
  }
350043
350262
  async supportsLoadPointsInRect(elementPath, featureIndexColumnName, mortonCodeColumn) {
350044
350263
  const parquetPath = getParquetPath(elementPath);
@@ -350246,7 +350465,13 @@ class GlbSource {
350246
350465
  class GlbDataLoader extends AbstractTwoStepLoader {
350247
350466
  async load() {
350248
350467
  const { url, options } = this;
350249
- const loader2 = new GLTFLoader$1();
350468
+ const [{ GLTFLoader: GLTFLoader2 }, { DRACOLoader }] = await Promise.all([
350469
+ // eslint-disable-next-line import/no-unresolved
350470
+ import("three/addons/loaders/GLTFLoader.js"),
350471
+ // eslint-disable-next-line import/no-unresolved
350472
+ import("three/addons/loaders/DRACOLoader.js")
350473
+ ]);
350474
+ const loader2 = new GLTFLoader2();
350250
350475
  const dracoLoader = new DRACOLoader();
350251
350476
  dracoLoader.setDecoderPath("https://www.gstatic.com/draco/versioned/decoders/1.5.6/");
350252
350477
  loader2.setDRACOLoader(dracoLoader);
@@ -352812,7 +353037,8 @@ const baseFileTypes = [
352812
353037
  makeFileType(FileType$1.OBS_LOCATIONS_MOLECULES_JSON, DataType$3.OBS_LOCATIONS, MoleculesJsonAsObsLocationsLoader, JsonSource, z.null()),
352813
353038
  makeFileType(FileType$1.OBS_LABELS_MOLECULES_JSON, DataType$3.OBS_LABELS, MoleculesJsonAsObsLabelsLoader, JsonSource, z.null()),
352814
353039
  makeFileType(FileType$1.NEIGHBORHOODS_JSON, DataType$3.NEIGHBORHOODS, JsonLoader, JsonSource, z.null()),
352815
- makeFileType(FileType$1.GENOMIC_PROFILES_ZARR, DataType$3.GENOMIC_PROFILES, GenomicProfilesZarrLoader, ZarrDataSource, z.null())
353040
+ makeFileType(FileType$1.GENOMIC_PROFILES_ZARR, DataType$3.GENOMIC_PROFILES, GenomicProfilesZarrLoader, ZarrDataSource, z.null()),
353041
+ makeFileType(FileType$1.GENOMIC_PROFILES_ZARR_ZIP, DataType$3.GENOMIC_PROFILES, GenomicProfilesZarrLoader, ZarrDataSource, z.null())
352816
353042
  ];
352817
353043
  const baseJointFileTypes = [
352818
353044
  new PluginJointFileType(FileType$1.ANNDATA_ZARR, expandAnndataZarr, anndataZarrSchema),
@@ -352979,6 +353205,7 @@ const baseCoordinationTypes = [
352979
353205
  new PluginCoordinationType(CoordinationType$1.SPATIAL_CHANNEL_LABELS_VISIBLE, true, z.boolean()),
352980
353206
  new PluginCoordinationType(CoordinationType$1.SPATIAL_CHANNEL_LABELS_ORIENTATION, "vertical", z.enum(["vertical", "horizontal"])),
352981
353207
  new PluginCoordinationType(CoordinationType$1.SPATIAL_CHANNEL_LABEL_SIZE, 14, z.number()),
353208
+ new PluginCoordinationType(CoordinationType$1.SPATIAL_CHANNELS_SORT_ORDER, "original", z.enum(["original", "alphabetical"])),
352982
353209
  new PluginCoordinationType(CoordinationType$1.SAMPLE_TYPE, "sample", z.string().nullable()),
352983
353210
  // TODO: remove one array level and use multi-coordination for sampleSetSelection?
352984
353211
  new PluginCoordinationType(CoordinationType$1.SAMPLE_FILTER, null, z.array(z.string()).nullable()),