@vitessce/vit-s 3.3.2 → 3.3.3

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.
@@ -1 +1 @@
1
- {"version":3,"file":"VitS.d.ts","sourceRoot":"","sources":["../src/VitS.js"],"names":[],"mappings":"AA8BA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH;IA7ByB,MAAM,EAApB,MAAM;IAGkB,SAAS,EAAjC,SAAS,GAAC,MAAM;IACF,MAAM,EAApB,MAAM;IACQ,KAAK,EAAnB,MAAM;IAEU,MAAM;IACN,cAAc;IAEd,cAAc;IAEf,cAAc,EAA7B,OAAO;IAIQ,sBAAsB,EAArC,OAAO;IAGY,GAAG,EAAtB,IAAI,GAAC,MAAM;IAGE,SAAS;IACT,SAAS;IACT,cAAc;IACd,iBAAiB;IACX,OAAO,EAA1B,IAAI,GAAC,MAAM;gBA2LrB"}
1
+ {"version":3,"file":"VitS.d.ts","sourceRoot":"","sources":["../src/VitS.js"],"names":[],"mappings":"AA8BA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH;IA7ByB,MAAM,EAApB,MAAM;IAGkB,SAAS,EAAjC,SAAS,GAAC,MAAM;IACF,MAAM,EAApB,MAAM;IACQ,KAAK,EAAnB,MAAM;IAEU,MAAM;IACN,cAAc;IAEd,cAAc;IAEf,cAAc,EAA7B,OAAO;IAIQ,sBAAsB,EAArC,OAAO;IAGY,GAAG,EAAtB,IAAI,GAAC,MAAM;IAGE,SAAS;IACT,SAAS;IACT,cAAc;IACd,iBAAiB;IACX,OAAO,EAA1B,IAAI,GAAC,MAAM;gBA4LrB"}
package/dist-tsc/VitS.js CHANGED
@@ -142,5 +142,5 @@ export function VitS(props) {
142
142
  return createViewConfigStore(null, null);
143
143
  // eslint-disable-next-line react-hooks/exhaustive-deps
144
144
  }, [success, configKey]);
145
- return success ? (_jsx(StylesProvider, { generateClassName: generateClassName, children: _jsx(ThemeProvider, { theme: muiTheme[theme], children: _jsx(QueryClientProvider, { client: queryClient, children: _jsx(ViewConfigProvider, { createStore: createViewConfigStoreClosure, children: _jsxs(AuxiliaryProvider, { createStore: createAuxiliaryStore, children: [_jsx(VitessceGrid, { success: success, configKey: configKey, viewTypes: viewTypes, fileTypes: fileTypes, coordinationTypes: coordinationTypes, config: configOrWarning, rowHeight: rowHeight, height: height, theme: theme, isBounded: isBounded }), _jsx(CallbackPublisher, { onWarn: onWarn, onConfigChange: onConfigChange, onLoaderChange: onLoaderChange, validateOnConfigChange: validateOnConfigChange, pluginSpecificConfigSchema: pluginSpecificConfigSchema })] }) }, configKey) }) }) })) : (_jsx(StylesProvider, { generateClassName: generateClassName, children: _jsx(ThemeProvider, { theme: muiTheme[theme], children: _jsx(Warning, { ...configOrWarning }) }) }));
145
+ return success ? (_jsx(StylesProvider, { generateClassName: generateClassName, children: _jsx(ThemeProvider, { theme: muiTheme[theme], children: _jsx(QueryClientProvider, { client: queryClient, children: _jsx(ViewConfigProvider, { createStore: createViewConfigStoreClosure, children: _jsxs(AuxiliaryProvider, { createStore: createAuxiliaryStore, children: [_jsx(VitessceGrid, { success: success, configKey: configKey, viewTypes: viewTypes, fileTypes: fileTypes, coordinationTypes: coordinationTypes, config: configOrWarning, rowHeight: rowHeight, height: height, theme: theme, isBounded: isBounded, stores: stores }), _jsx(CallbackPublisher, { onWarn: onWarn, onConfigChange: onConfigChange, onLoaderChange: onLoaderChange, validateOnConfigChange: validateOnConfigChange, pluginSpecificConfigSchema: pluginSpecificConfigSchema })] }) }, configKey) }) }) })) : (_jsx(StylesProvider, { generateClassName: generateClassName, children: _jsx(ThemeProvider, { theme: muiTheme[theme], children: _jsx(Warning, { ...configOrWarning }) }) }));
146
146
  }
@@ -1 +1 @@
1
- {"version":3,"file":"VitessceGrid.d.ts","sourceRoot":"","sources":["../src/VitessceGrid.js"],"names":[],"mappings":"AA4BA;;;;;;;;;;;GAWG;AACH;IATyB,SAAS,EAAvB,MAAM;IACQ,MAAM,EAApB,MAAM;IACQ,KAAK,EAAnB,MAAM;IACQ,MAAM,EAApB,MAAM;IACU,MAAM;IACE,SAAS,EAAjC,gBAAgB;IACQ,SAAS,EAAjC,gBAAgB;IACgB,iBAAiB,EAAjD,wBAAwB;gBA4FlC"}
1
+ {"version":3,"file":"VitessceGrid.d.ts","sourceRoot":"","sources":["../src/VitessceGrid.js"],"names":[],"mappings":"AA4BA;;;;;;;;;;;GAWG;AACH;IATyB,SAAS,EAAvB,MAAM;IACQ,MAAM,EAApB,MAAM;IACQ,KAAK,EAAnB,MAAM;IACQ,MAAM,EAApB,MAAM;IACU,MAAM;IACE,SAAS,EAAjC,gBAAgB;IACQ,SAAS,EAAjC,gBAAgB;IACgB,iBAAiB,EAAjD,wBAAwB;gBA8FlC"}
@@ -24,7 +24,7 @@ const margin = 5;
24
24
  * @param {PluginCoordinationType[]} props.coordinationTypes
25
25
  */
26
26
  export default function VitessceGrid(props) {
27
- const { success, configKey, rowHeight: initialRowHeight, config, theme, height, isBounded, viewTypes, fileTypes, coordinationTypes, } = props;
27
+ const { success, configKey, rowHeight: initialRowHeight, config, theme, height, isBounded, viewTypes, fileTypes, coordinationTypes, stores, } = props;
28
28
  const [rowHeight, containerRef] = useRowHeight(config, initialRowHeight, height, margin, padding);
29
29
  const onResize = useEmitGridResize();
30
30
  const [componentWidth] = useClosestVitessceContainerSize(containerRef);
@@ -54,7 +54,7 @@ export default function VitessceGrid(props) {
54
54
  let newLoaders = null;
55
55
  let newConfig = null;
56
56
  if (success) {
57
- newLoaders = createLoaders(config.datasets, config.description, fileTypes, coordinationTypes);
57
+ newLoaders = createLoaders(config.datasets, config.description, fileTypes, coordinationTypes, stores);
58
58
  newConfig = config;
59
59
  }
60
60
  setViewConfig(newConfig);
@@ -60,7 +60,7 @@ export function useDataType(dataType: any, loaders: object, dataset: string, isR
60
60
  * cells is an object and cellsCount is the
61
61
  * number of items in the cells object.
62
62
  */
63
- export function useDataTypeMulti(dataType: any, loaders: object, dataset: string, isRequired: boolean, coordinationSetters: object, initialCoordinationValues: object, matchOnObj: any): array;
63
+ export function useDataTypeMulti(dataType: any, loaders: object, dataset: string, isRequired: boolean, coordinationSetters: object, initialCoordinationValues: object, matchOnObj: any, mergeCoordination: any, viewUid: any): array;
64
64
  export function useHasLoader(loaders: any, dataset: any, dataType: any, matchOn: any): boolean;
65
65
  import { AbstractLoaderError } from "./errors/index.js";
66
66
  //# sourceMappingURL=data-hook-utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"data-hook-utils.d.ts","sourceRoot":"","sources":["../src/data-hook-utils.js"],"names":[],"mappings":"AAcA;;;;GAIG;AACH,4BAFW,mBAAmB,yBAS7B;AAED;;;;;;;;;;GAUG;AACH,8CATW,MAAM,WAGN,MAAM,iBAGN,MAAM,QAiBhB;AAGD,oDAuBC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,oDAhBW,MAAM,WAEN,MAAM,cAEN,OAAO,uBAEP,MAAM,6BAGN,MAAM,uBAkDhB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,yDAhBW,MAAM,WAEN,MAAM,cAEN,OAAO,uBAEP,MAAM,6BAGN,MAAM,0BA+EhB;AAED,+FAGC"}
1
+ {"version":3,"file":"data-hook-utils.d.ts","sourceRoot":"","sources":["../src/data-hook-utils.js"],"names":[],"mappings":"AAkBA;;;;GAIG;AACH,4BAFW,mBAAmB,yBAS7B;AAED;;;;;;;;;;GAUG;AACH,8CATW,MAAM,WAGN,MAAM,iBAGN,MAAM,QAiBhB;AAGD,oDAuBC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,oDAhBW,MAAM,WAEN,MAAM,cAEN,OAAO,uBAEP,MAAM,6BAGN,MAAM,uBAkDhB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,yDAhBW,MAAM,WAEN,MAAM,cAEN,OAAO,uBAEP,MAAM,6BAGN,MAAM,gEAyFhB;AAED,+FAGC"}
@@ -1,6 +1,6 @@
1
1
  import { useEffect, useMemo } from 'react';
2
2
  import { useQuery, useQueries } from '@tanstack/react-query';
3
- import { capitalize, fromEntries } from '@vitessce/utils';
3
+ import { capitalize, fromEntries, getInitialCoordinationScopePrefix, } from '@vitessce/utils';
4
4
  import { STATUS } from '@vitessce/constants-internal';
5
5
  import { getMatchingLoader, useMatchingLoader, useSetWarning, } from './state/hooks.js';
6
6
  import { AbstractLoaderError, LoaderNotFoundError, } from './errors/index.js';
@@ -56,7 +56,7 @@ export async function dataQueryFn(ctx) {
56
56
  const { data, url, coordinationValues } = payload;
57
57
  // Status: success
58
58
  // Array of objects like { url, name }.
59
- const urls = Array.isArray(url) ? url : [{ url, name: dataType }];
59
+ const urls = (Array.isArray(url) ? url : [{ url, name: dataType }]).filter(d => d.url);
60
60
  return { data, coordinationValues, urls };
61
61
  }
62
62
  // No loader was found.
@@ -144,7 +144,7 @@ export function useDataType(dataType, loaders, dataset, isRequired, coordination
144
144
  * cells is an object and cellsCount is the
145
145
  * number of items in the cells object.
146
146
  */
147
- export function useDataTypeMulti(dataType, loaders, dataset, isRequired, coordinationSetters, initialCoordinationValues, matchOnObj) {
147
+ export function useDataTypeMulti(dataType, loaders, dataset, isRequired, coordinationSetters, initialCoordinationValues, matchOnObj, mergeCoordination, viewUid) {
148
148
  const placeholderObject = useMemo(() => ({}), []);
149
149
  const setWarning = useSetWarning();
150
150
  const matchOnEntries = matchOnObj ? Object.entries(matchOnObj) : [];
@@ -172,10 +172,17 @@ export function useDataTypeMulti(dataType, loaders, dataset, isRequired, coordin
172
172
  const isSuccess = dataStatus === STATUS.SUCCESS;
173
173
  useEffect(() => {
174
174
  dataQueries
175
- .map(q => q.data?.coordinationValues)
176
- .filter(v => Boolean(v))
177
- .forEach((coordinationValues) => {
178
- initCoordinationSpace(coordinationValues, coordinationSetters, initialCoordinationValues);
175
+ .filter(q => Boolean(q.data?.coordinationValues))
176
+ .forEach((q) => {
177
+ const { coordinationValues } = q.data;
178
+ if (mergeCoordination) {
179
+ mergeCoordination(coordinationValues,
180
+ // Auto-generate based on the dataset and data type.
181
+ getInitialCoordinationScopePrefix(dataset, dataType), viewUid);
182
+ }
183
+ else {
184
+ initCoordinationSpace(coordinationValues, coordinationSetters, initialCoordinationValues);
185
+ }
179
186
  });
180
187
  // Deliberate dependency omissions: use indirect dependencies for efficiency.
181
188
  // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -1 +1 @@
1
- {"version":3,"file":"data-hooks-multilevel-utils.d.ts","sourceRoot":"","sources":["../src/data-hooks-multilevel-utils.js"],"names":[],"mappings":"AA+CA;;;;;;;;;;;;;GAaG;AACH,mEAPW,MAAM,cACN,MAAM,SACN,MAAM,WACN,MAAM,YACN,MAAM,wBAmBhB;AA8BD;;;;;;;;;;;;GAYG;AACH,gEANW,MAAM,SACN,MAAM,WACN,MAAM,YACN,MAAM,wBAiBhB;AA+BD;;;;;;;;;;;;GAYG;AACH,mDANW,MAAM,SACN,MAAM,WACN,MAAM,YACN,MAAM,wBAiBhB;AAuBD;;;;;;;;;;GAUG;AACH,oDALW,MAAM,EAAE,WACR,MAAM,+BAOhB;AAED;;;;;;GAMG;AACH,0GAUC;AAED;;;;;;GAMG;AACH,0FAYC;AA+DD,gJA6DC;AAuCD,sIAqDC;AAyDD,2HAQC;AAED,sHAQC;AAED,wHAQC"}
1
+ {"version":3,"file":"data-hooks-multilevel-utils.d.ts","sourceRoot":"","sources":["../src/data-hooks-multilevel-utils.js"],"names":[],"mappings":"AA+CA;;;;;;;;;;;;;GAaG;AACH,mEAPW,MAAM,cACN,MAAM,SACN,MAAM,WACN,MAAM,YACN,MAAM,wBAmBhB;AA8BD;;;;;;;;;;;;GAYG;AACH,gEANW,MAAM,SACN,MAAM,WACN,MAAM,YACN,MAAM,wBAiBhB;AA+BD;;;;;;;;;;;;GAYG;AACH,mDANW,MAAM,SACN,MAAM,WACN,MAAM,YACN,MAAM,wBAiBhB;AAuBD;;;;;;;;;;GAUG;AACH,oDALW,MAAM,EAAE,WACR,MAAM,+BAOhB;AAED;;;;;;GAMG;AACH,0GAUC;AAED;;;;;;GAMG;AACH,0FAYC;AA+DD,gJA6DC;AAuCD,sIAuDC;AAyDD,2HAQC;AAED,sHAQC;AAED,wHAQC"}
@@ -281,7 +281,7 @@ export function useFeatureSelectionMultiLevel(loaders, dataset, isRequired, matc
281
281
  // (i.e., a single number, despite possibly different numbers of queries).
282
282
  // Reference: https://github.com/TanStack/query/issues/3049#issuecomment-1253201068
283
283
  // eslint-disable-next-line react-hooks/exhaustive-deps
284
- }, [featureQueries.reduce((a, h) => a + h.dataUpdatedAt, 0)]);
284
+ }, [featureQueries.reduce((a, h) => a + h.dataUpdatedAt, 0), queryKeyScopeTuples]);
285
285
  return [geneData, loadedGeneName, extents, normData, dataStatus];
286
286
  }
287
287
  async function matrixIndicesQueryFn(ctx) {
@@ -361,8 +361,10 @@ export function useObsFeatureMatrixIndicesMultiLevel(loaders, dataset, isRequire
361
361
  // We use .reduce to ensure the number of dependencies is stable
362
362
  // (i.e., a single number, despite possibly different numbers of queries).
363
363
  // Reference: https://github.com/TanStack/query/issues/3049#issuecomment-1253201068
364
+ // We also want to re-compute if any of the keys within the matchOnObj change,
365
+ // so we also use queryKeyScopeTuples as a dependency.
364
366
  // eslint-disable-next-line react-hooks/exhaustive-deps
365
- }, [indicesQueries.reduce((a, h) => a + h.dataUpdatedAt, 0)]);
367
+ }, [indicesQueries.reduce((a, h) => a + h.dataUpdatedAt, 0), queryKeyScopeTuples]);
366
368
  return [indicesData, dataStatus];
367
369
  }
368
370
  function useDataTypeMultiLevel(loaders, dataset, isRequired, matchOnObj, depth, dataType) {
@@ -404,7 +406,7 @@ function useDataTypeMultiLevel(loaders, dataset, isRequired, matchOnObj, depth,
404
406
  // (i.e., a single number, despite possibly different numbers of queries).
405
407
  // Reference: https://github.com/TanStack/query/issues/3049#issuecomment-1253201068
406
408
  // eslint-disable-next-line react-hooks/exhaustive-deps
407
- }, [locationsQueries.reduce((a, h) => a + h.dataUpdatedAt, 0)]);
409
+ }, [locationsQueries.reduce((a, h) => a + h.dataUpdatedAt, 0), queryKeyScopeTuples]);
408
410
  return [locationsData, dataStatus];
409
411
  }
410
412
  export function useObsLocationsMultiLevel(loaders, dataset, isRequired, matchOnObj, depth) {
@@ -1 +1 @@
1
- {"version":3,"file":"data-hooks-multilevel.d.ts","sourceRoot":"","sources":["../src/data-hooks-multilevel.js"],"names":[],"mappings":"AAgBA,4IA+CC;AAED,oIA0CC;AAED,mJAuBC;AAED,2IAsBC;AAED,8HAqBC;AAED,wIAqBC;AAED,mIAqBC"}
1
+ {"version":3,"file":"data-hooks-multilevel.d.ts","sourceRoot":"","sources":["../src/data-hooks-multilevel.js"],"names":[],"mappings":"AAgBA,4IAkDC;AAED,oIA0CC;AAED,mJAuBC;AAED,2IAsBC;AAED,8HAqBC;AAED,wIAqBC;AAED,mIAqBC"}
@@ -17,6 +17,8 @@ export function useSegmentationMultiFeatureSelection(coordinationScopes, coordin
17
17
  // use coordinationScopes and coordinationScopesBy which are
18
18
  // indirect dependencies here.
19
19
  [coordinationScopes, coordinationScopesBy]);
20
+ const useMemoDependency = Object.values(featureSelectionCoordination[0] || {})
21
+ .flatMap(layerVal => Object.values(layerVal).map(cVal => cVal.featureSelection));
20
22
  const selections = useMemo(() => fromEntries(Object.entries(featureSelectionCoordination[0])
21
23
  .map(([layerScope, layerVal]) => ([
22
24
  layerScope,
@@ -25,8 +27,9 @@ export function useSegmentationMultiFeatureSelection(coordinationScopes, coordin
25
27
  ]))),
26
28
  // Need to execute this more frequently, whenever the featureSelections update.
27
29
  [coordinationScopes, coordinationScopesBy,
28
- ...Object.values(featureSelectionCoordination[0] || {})
29
- .flatMap(layerVal => Object.values(layerVal).map(cVal => cVal.featureSelection)),
30
+ // We need to ensure there are always the same number of
31
+ // entries in the full dependency array.
32
+ JSON.stringify(useMemoDependency.length > 0 ? useMemoDependency : [null]),
30
33
  ]);
31
34
  const [featureData, loadedSelections, extents, normData, featureStatus,] = useFeatureSelectionMultiLevel(loaders, dataset, false, matchOnObj, selections, 2);
32
35
  return [featureData, loadedSelections, extents, normData, featureStatus];
@@ -71,10 +71,10 @@ export function useFeatureSelection(loaders: object, dataset: string, isRequired
71
71
  * @returns {object} [attrs] { rows, cols } object containing cell and gene names.
72
72
  */
73
73
  export function useObsFeatureMatrixIndices(loaders: object, dataset: string, isRequired: boolean, matchOn: any): object;
74
- export function useMultiObsPoints(coordinationScopes: any, coordinationScopesBy: any, loaders: any, dataset: any): any[];
75
- export function useMultiObsSpots(coordinationScopes: any, coordinationScopesBy: any, loaders: any, dataset: any): any[];
74
+ export function useMultiObsPoints(coordinationScopes: any, coordinationScopesBy: any, loaders: any, dataset: any, mergeCoordination: any, viewUid: any): any[];
75
+ export function useMultiObsSpots(coordinationScopes: any, coordinationScopesBy: any, loaders: any, dataset: any, mergeCoordination: any, viewUid: any): any[];
76
76
  export function useSpotMultiObsSets(coordinationScopes: any, coordinationScopesBy: any, loaders: any, dataset: any): any[];
77
77
  export function useMultiObsLabels(coordinationScopes: any, obsType: any, loaders: any, dataset: any): any[];
78
- export function useMultiObsSegmentations(coordinationScopes: any, coordinationScopesBy: any, loaders: any, dataset: any): any[];
79
- export function useMultiImages(coordinationScopes: any, coordinationScopesBy: any, loaders: any, dataset: any): any[];
78
+ export function useMultiObsSegmentations(coordinationScopes: any, coordinationScopesBy: any, loaders: any, dataset: any, mergeCoordination: any, viewUid: any): any[];
79
+ export function useMultiImages(coordinationScopes: any, coordinationScopesBy: any, loaders: any, dataset: any, mergeCoordination: any, viewUid: any): any[];
80
80
  //# sourceMappingURL=data-hooks.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"data-hooks.d.ts","sourceRoot":"","sources":["../src/data-hooks.js"],"names":[],"mappings":"AAmBA;;;;;;;;GAQG;AACH,wCAPW,MAAM,WAEN,MAAM,SAsBhB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,6CAhBW,MAAM,WAEN,MAAM,cAEN,OAAO,uBAEP,MAAM,6BAGN,MAAM,uBAgBhB;AAED,4JASC;AAED,6JASC;AAED,gKASC;AAED,6JASC;AAED,oKASC;AAED,2JASC;AAED,oKASC;AAED,iKASC;AAED,yJASC;AAED,mKASC;AAED,iKASC;AAED;;;;;;;;;;;;;GAaG;AACH,6CAVW,MAAM,WAEN,MAAM,cAEN,OAAO,aAEP,OAAO,uBA4EjB;AAED;;;;;;;;;;;;;GAaG;AACH,oDARW,MAAM,WAEN,MAAM,cAEN,OAAO,iBAEL,MAAM,CA2ElB;AAED,yHAsBC;AAED,wHAsBC;AAED,2HAsBC;AAED,4GAmBC;AAED,gIA0BC;AAED,sHAwBC"}
1
+ {"version":3,"file":"data-hooks.d.ts","sourceRoot":"","sources":["../src/data-hooks.js"],"names":[],"mappings":"AAmBA;;;;;;;;GAQG;AACH,wCAPW,MAAM,WAEN,MAAM,SAsBhB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,6CAhBW,MAAM,WAEN,MAAM,cAEN,OAAO,uBAEP,MAAM,6BAGN,MAAM,uBAgBhB;AAED,4JASC;AAED,6JASC;AAED,gKASC;AAED,6JASC;AAED,oKASC;AAED,2JASC;AAED,oKASC;AAED,iKASC;AAED,yJASC;AAED,mKASC;AAED,iKASC;AAED;;;;;;;;;;;;;GAaG;AACH,6CAVW,MAAM,WAEN,MAAM,cAEN,OAAO,aAEP,OAAO,uBA4EjB;AAED;;;;;;;;;;;;;GAaG;AACH,oDARW,MAAM,WAEN,MAAM,cAEN,OAAO,iBAEL,MAAM,CA2ElB;AAED,+JAuBC;AAED,8JAuBC;AAED,2HAsBC;AAED,4GAmBC;AAED,sKA2BC;AAED,4JAyBC"}
@@ -211,7 +211,7 @@ export function useObsFeatureMatrixIndices(loaders, dataset, isRequired, matchOn
211
211
  obsIndex: payloadData.rows,
212
212
  featureIndex: payloadData.cols,
213
213
  },
214
- urls: [{ url, name: DataType.OBS_FEATURE_MATRIX }],
214
+ urls: (url ? [{ url, name: DataType.OBS_FEATURE_MATRIX }] : null),
215
215
  };
216
216
  }
217
217
  // No loadAttrs function.
@@ -250,7 +250,7 @@ export function useObsFeatureMatrixIndices(loaders, dataset, isRequired, matchOn
250
250
  }, [error, setWarning]);
251
251
  return [loadedData, dataStatus, urls];
252
252
  }
253
- export function useMultiObsPoints(coordinationScopes, coordinationScopesBy, loaders, dataset) {
253
+ export function useMultiObsPoints(coordinationScopes, coordinationScopesBy, loaders, dataset, mergeCoordination, viewUid) {
254
254
  const obsTypeCoordination = useComplexCoordination([
255
255
  CoordinationType.OBS_TYPE,
256
256
  ], coordinationScopes, coordinationScopesBy, CoordinationType.POINT_LAYER);
@@ -259,10 +259,10 @@ export function useMultiObsPoints(coordinationScopes, coordinationScopesBy, load
259
259
  // use coordinationScopes and coordinationScopesBy which are
260
260
  // indirect dependencies here.
261
261
  [coordinationScopes, coordinationScopesBy]);
262
- const [obsPointsData, obsPointsDataStatus, obsPointsUrls] = useDataTypeMulti(DataType.OBS_POINTS, loaders, dataset, false, {}, {}, matchOnObj);
262
+ const [obsPointsData, obsPointsDataStatus, obsPointsUrls] = useDataTypeMulti(DataType.OBS_POINTS, loaders, dataset, false, {}, {}, matchOnObj, mergeCoordination, viewUid);
263
263
  return [obsPointsData, obsPointsDataStatus, obsPointsUrls];
264
264
  }
265
- export function useMultiObsSpots(coordinationScopes, coordinationScopesBy, loaders, dataset) {
265
+ export function useMultiObsSpots(coordinationScopes, coordinationScopesBy, loaders, dataset, mergeCoordination, viewUid) {
266
266
  const obsTypeCoordination = useComplexCoordination([
267
267
  CoordinationType.OBS_TYPE,
268
268
  ], coordinationScopes, coordinationScopesBy, CoordinationType.SPOT_LAYER);
@@ -271,7 +271,7 @@ export function useMultiObsSpots(coordinationScopes, coordinationScopesBy, loade
271
271
  // use coordinationScopes and coordinationScopesBy which are
272
272
  // indirect dependencies here.
273
273
  [coordinationScopes, coordinationScopesBy]);
274
- const [obsSpotsData, obsSpotsDataStatus, obsSpotsUrls] = useDataTypeMulti(DataType.OBS_SPOTS, loaders, dataset, false, {}, {}, matchOnObj);
274
+ const [obsSpotsData, obsSpotsDataStatus, obsSpotsUrls] = useDataTypeMulti(DataType.OBS_SPOTS, loaders, dataset, false, {}, {}, matchOnObj, mergeCoordination, viewUid);
275
275
  return [obsSpotsData, obsSpotsDataStatus, obsSpotsUrls];
276
276
  }
277
277
  export function useSpotMultiObsSets(coordinationScopes, coordinationScopesBy, loaders, dataset) {
@@ -295,7 +295,7 @@ export function useMultiObsLabels(coordinationScopes, obsType, loaders, dataset)
295
295
  const [obsLabelsData, obsLabelsDataStatus, obsLabelsUrls] = useDataTypeMulti(DataType.OBS_LABELS, loaders, dataset, false, {}, {}, obsLabelsMatchOnObj);
296
296
  return [obsLabelsTypes, obsLabelsData, obsLabelsDataStatus, obsLabelsUrls];
297
297
  }
298
- export function useMultiObsSegmentations(coordinationScopes, coordinationScopesBy, loaders, dataset) {
298
+ export function useMultiObsSegmentations(coordinationScopes, coordinationScopesBy, loaders, dataset, mergeCoordination, viewUid) {
299
299
  const imageCoordination = useComplexCoordination([
300
300
  CoordinationType.FILE_UID,
301
301
  ], coordinationScopes, coordinationScopesBy, CoordinationType.SEGMENTATION_LAYER);
@@ -304,10 +304,10 @@ export function useMultiObsSegmentations(coordinationScopes, coordinationScopesB
304
304
  // use coordinationScopes and coordinationScopesBy which are
305
305
  // indirect dependencies here.
306
306
  [coordinationScopes, coordinationScopesBy]);
307
- const [obsSegmentationsData, obsSegmentationsDataStatus, obsSegmentationsUrls,] = useDataTypeMulti(DataType.OBS_SEGMENTATIONS, loaders, dataset, false, {}, {}, matchOnObj);
307
+ const [obsSegmentationsData, obsSegmentationsDataStatus, obsSegmentationsUrls,] = useDataTypeMulti(DataType.OBS_SEGMENTATIONS, loaders, dataset, false, {}, {}, matchOnObj, mergeCoordination, viewUid);
308
308
  return [obsSegmentationsData, obsSegmentationsDataStatus, obsSegmentationsUrls];
309
309
  }
310
- export function useMultiImages(coordinationScopes, coordinationScopesBy, loaders, dataset) {
310
+ export function useMultiImages(coordinationScopes, coordinationScopesBy, loaders, dataset, mergeCoordination, viewUid) {
311
311
  // TODO: delegate the generation of matchOnObj to a different hoook and pass as a parameter?
312
312
  // (in all of the useMulti data hooks)?
313
313
  const imageCoordination = useComplexCoordination([
@@ -318,6 +318,6 @@ export function useMultiImages(coordinationScopes, coordinationScopesBy, loaders
318
318
  // use coordinationScopes and coordinationScopesBy which are
319
319
  // indirect dependencies here.
320
320
  [coordinationScopes, coordinationScopesBy]);
321
- const [imageData, imageDataStatus, imageUrls] = useDataTypeMulti(DataType.IMAGE, loaders, dataset, false, {}, {}, matchOnObj);
321
+ const [imageData, imageDataStatus, imageUrls] = useDataTypeMulti(DataType.IMAGE, loaders, dataset, false, {}, {}, matchOnObj, mergeCoordination, viewUid);
322
322
  return [imageData, imageDataStatus, imageUrls];
323
323
  }
@@ -4,7 +4,7 @@ export { PopperMenu } from "./shared-mui/components.js";
4
4
  export { useHasLoader } from "./data-hook-utils.js";
5
5
  export { logConfig } from "./view-config-utils.js";
6
6
  export { useReady, useUrls, useVitessceContainer, useDeckCanvasSize, useUint8ObsFeatureMatrix, useUint8FeatureSelection, useExpressionValueGetter, useGetObsMembership, useGetObsInfo, useClosestVitessceContainerSize, useWindowDimensions, useGridItemSize } from "./hooks.js";
7
- export { useCoordinationScopes, useCoordinationScopesBy, useInitialCoordination, useCoordination, useComplexCoordination, useComplexCoordinationSecondary, useMultiCoordinationScopes, useMultiCoordinationScopesNonNull, useMultiCoordinationScopesSecondary, useMultiCoordinationScopesSecondaryNonNull, useMultiCoordinationValues, useMultiDatasetCoordination, useDatasetUids, useLoaders, useMatchingLoader, useViewConfigStore, useViewConfigStoreApi, useComponentHover, useSetComponentHover, useComponentViewInfo, useSetComponentViewInfo, useWarning, useSetWarning, useAuxiliaryCoordination, useComponentLayout, useRemoveImageChannelInMetaCoordinationScopes, useAddImageChannelInMetaCoordinationScopes } from "./state/hooks.js";
7
+ export { useCoordinationScopes, useCoordinationScopesBy, useInitialCoordination, useCoordination, useComplexCoordination, useComplexCoordinationSecondary, useMultiCoordinationScopes, useMultiCoordinationScopesNonNull, useMultiCoordinationScopesSecondary, useMultiCoordinationScopesSecondaryNonNull, useMultiCoordinationValues, useMultiDatasetCoordination, useDatasetUids, useLoaders, useMergeCoordination, useMatchingLoader, useViewConfigStore, useViewConfigStoreApi, useComponentHover, useSetComponentHover, useComponentViewInfo, useSetComponentViewInfo, useWarning, useSetWarning, useAuxiliaryCoordination, useComponentLayout, useRemoveImageChannelInMetaCoordinationScopes, useAddImageChannelInMetaCoordinationScopes } from "./state/hooks.js";
8
8
  export { useDescription, useImageData, useObsSetsData, useObsEmbeddingData, useFeatureSelection, useObsFeatureMatrixIndices, useMultiObsLabels, useMultiObsSpots, useMultiObsPoints, useSpotMultiObsSets, useMultiObsSegmentations, useMultiImages, useObsSpotsData, useObsPointsData, useObsLocationsData, useObsSegmentationsData, useNeighborhoodsData, useObsLabelsData, useObsFeatureMatrixData, useFeatureLabelsData, useGenomicProfilesData } from "./data-hooks.js";
9
9
  export { usePointMultiObsLabels, useSpotMultiFeatureSelection, useSpotMultiObsFeatureMatrixIndices, useSegmentationMultiFeatureSelection, useSegmentationMultiObsFeatureMatrixIndices, useSegmentationMultiObsLocations, useSegmentationMultiObsSets } from "./data-hooks-multilevel.js";
10
10
  export { AbstractLoader, AbstractTwoStepLoader, LoaderResult } from "./data/index.js";
package/dist-tsc/index.js CHANGED
@@ -3,7 +3,7 @@ export { TitleInfo } from './TitleInfo.js';
3
3
  export { PopperMenu } from './shared-mui/components.js';
4
4
  // For plugin view types:
5
5
  export { useReady, useUrls, useVitessceContainer, useDeckCanvasSize, useUint8ObsFeatureMatrix, useUint8FeatureSelection, useExpressionValueGetter, useGetObsMembership, useGetObsInfo, useClosestVitessceContainerSize, useWindowDimensions, useGridItemSize, } from './hooks.js';
6
- export { useCoordinationScopes, useCoordinationScopesBy, useInitialCoordination, useCoordination, useComplexCoordination, useComplexCoordinationSecondary, useMultiCoordinationScopes, useMultiCoordinationScopesNonNull, useMultiCoordinationScopesSecondary, useMultiCoordinationScopesSecondaryNonNull, useMultiCoordinationValues, useMultiDatasetCoordination, useDatasetUids, useLoaders, useMatchingLoader, useViewConfigStore, useViewConfigStoreApi, useComponentHover, useSetComponentHover, useComponentViewInfo, useSetComponentViewInfo, useWarning, useSetWarning, useAuxiliaryCoordination, useComponentLayout, useRemoveImageChannelInMetaCoordinationScopes, useAddImageChannelInMetaCoordinationScopes, } from './state/hooks.js';
6
+ export { useCoordinationScopes, useCoordinationScopesBy, useInitialCoordination, useCoordination, useComplexCoordination, useComplexCoordinationSecondary, useMultiCoordinationScopes, useMultiCoordinationScopesNonNull, useMultiCoordinationScopesSecondary, useMultiCoordinationScopesSecondaryNonNull, useMultiCoordinationValues, useMultiDatasetCoordination, useDatasetUids, useLoaders, useMergeCoordination, useMatchingLoader, useViewConfigStore, useViewConfigStoreApi, useComponentHover, useSetComponentHover, useComponentViewInfo, useSetComponentViewInfo, useWarning, useSetWarning, useAuxiliaryCoordination, useComponentLayout, useRemoveImageChannelInMetaCoordinationScopes, useAddImageChannelInMetaCoordinationScopes, } from './state/hooks.js';
7
7
  export { useDescription, useImageData, useObsSetsData, useObsEmbeddingData, useFeatureSelection, useObsFeatureMatrixIndices, useMultiObsLabels, useMultiObsSpots, useMultiObsPoints, useSpotMultiObsSets, useMultiObsSegmentations, useMultiImages, useObsSpotsData, useObsPointsData, useObsLocationsData, useObsSegmentationsData, useNeighborhoodsData, useObsLabelsData, useObsFeatureMatrixData, useFeatureLabelsData, useGenomicProfilesData, } from './data-hooks.js';
8
8
  export { usePointMultiObsLabels, useSpotMultiFeatureSelection, useSpotMultiObsFeatureMatrixIndices, useSegmentationMultiFeatureSelection, useSegmentationMultiObsFeatureMatrixIndices, useSegmentationMultiObsLocations, useSegmentationMultiObsSets, } from './data-hooks-multilevel.js';
9
9
  export { useHasLoader, } from './data-hook-utils.js';
@@ -217,6 +217,13 @@ export function useChangeLayout(): Function;
217
217
  * in the `useViewConfigStore` store.
218
218
  */
219
219
  export function useSetLoaders(): Function;
220
+ /**
221
+ * Obtain the loaders setter function from
222
+ * the global app state.
223
+ * @returns {function} The loaders setter function
224
+ * in the `useViewConfigStore` store.
225
+ */
226
+ export function useMergeCoordination(): Function;
220
227
  /**
221
228
  * Obtain the view config setter function from
222
229
  * the global app state.
@@ -1 +1 @@
1
- {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/state/hooks.js"],"names":[],"mappings":"AAkCA;;;;;;GAMG;AACH,oEAFa,MAAM,GAAC,SAAS,CAoB5B;AAED;;;;;;;GAOG;AACH,mGAFa,MAAM,GAAC,SAAS,CAoB5B;AAED;;;;;GAKG;AACH,6CAJW,MAAM,4BAEJ,MAAM,GAAC,SAAS,CAI5B;AAED;;;;;;GAMG;AACH,+CALW,MAAM,oFAGJ,MAAM,GAAC,SAAS,CAc5B;AA2MD;;;;;;;;;GASG;AACH,mDALW,MAAM,EAAE,sBACR,MAAM,GAEJ,MAAM,CAclB;AAED;;;;;;;;;;;;;;;GAeG;AACH,4CATW,MAAM,EAAE,sBACR,MAAM,SAqChB;AAED,yFAKC;AAED,gGAqBC;AAED,0IA4BC;AAED,iJAkEC;AAED;;EAmBC;AAED;;;;GAIG;AACH,mDAHW,MAAM,GACJ,MAAM,CAIlB;AAED;;;;;;;;;;;;;GAaG;AACH,mDAXW,MAAM,EAAE,sBACR,MAAM,wBACN,MAAM,UAEN,MAAM,SA6EhB;AAED;;;;;GAKG;AACH,0DAHW,MAAM,GACJ,MAAM,CAiBlB;AAED;;;;;;GAMG;AACH,4DAJW,MAAM,wBACN,MAAM,GACJ,MAAM,CAgBlB;AAED;;;;;;;GAOG;AACH,4DANW,MAAM,EAAE,iDACR,MAAM,eACN,MAAM,iBACN,MAAM,SAuEhB;AAGD;;;;;;;;;;;GAWG;AACH,wDATW,MAAM,EAAE,sBACR,MAAM,wBACN,MAAM,SAYhB;AA6BD;;;;;;;;;;;;;;;GAeG;AACH,qDATW,MAAM,EAAE,sBACR,MAAM,SAkChB;AAED;;;;;GAKG;AACH,8BAHa,MAAM,CAKlB;AAGD;;;;;;;;;;;;GAYG;AACH,2CARW,MAAM,WACN,MAAM,YACN,MAAM,0BACN,MAAM,OAoBhB;AAED;;;;;;;;;;;;GAYG;AACH,2CARW,MAAM,WACN,MAAM,YACN,MAAM,0BACN,MAAM,OAShB;AAED;;;;;GAKG;AACH,6BAHa,MAAM,EAAE,CAKpB;AAED;;;;;GAKG;AACH,+CAEC;AAED;;;;;GAKG;AACH,0EAEC;AAED;;;;;GAKG;AACH,uEAEC;AAED;;;;;GAKG;AACH,4CAEC;AAED;;;;;GAKG;AACH,0CAEC;AAED;;;;;GAKG;AACH,oEAIC;AAED;;;;;GAKG;AACH,qCAHa,MAAM,CAKlB;AAED;;;;;GAKG;AACH,iDAEC;AAED;;;;;GAKG;AACH,8BAHa,MAAM,CAKlB;AAED;;;;;GAKG;AACH,0CAEC;AAED;;;;;GAKG;AACH,iDAHa,MAAM,CAKlB;AAED;;;;;GAKG;AACH,6DAOC;AAED;;;;GAIG;AACH,iCAFa,MAAM,CAIlB;AAED;;;;;GAKG;AACH,8CAEC;AAnhCD;;;;+QAA0D;AAC1D,sFAA0D;AAC1D;;;;;EAAgE;AAOhE;;;;+QAAwD;AACxD,qFAAwD;AAmGjD,yFA8FJ;AAOI,0FAFM,MAAM,CAOlB;AAcM,iDAUJ"}
1
+ {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/state/hooks.js"],"names":[],"mappings":"AAmCA;;;;;;GAMG;AACH,oEAFa,MAAM,GAAC,SAAS,CA4B5B;AAED;;;;;;;GAOG;AACH,mGAFa,MAAM,GAAC,SAAS,CA0C5B;AAED;;;;;GAKG;AACH,6CAJW,MAAM,4BAEJ,MAAM,GAAC,SAAS,CAI5B;AAED;;;;;;GAMG;AACH,+CALW,MAAM,oFAGJ,MAAM,GAAC,SAAS,CAc5B;AA4RD;;;;;;;;;GASG;AACH,mDALW,MAAM,EAAE,sBACR,MAAM,GAEJ,MAAM,CAclB;AAED;;;;;;;;;;;;;;;GAeG;AACH,4CATW,MAAM,EAAE,sBACR,MAAM,SAqChB;AAED,yFAKC;AAED,gGAqBC;AAED,0IA4BC;AAED,iJAkEC;AAED;;EAmBC;AAED;;;;GAIG;AACH,mDAHW,MAAM,GACJ,MAAM,CAIlB;AAED;;;;;;;;;;;;;GAaG;AACH,mDAXW,MAAM,EAAE,sBACR,MAAM,wBACN,MAAM,UAEN,MAAM,SA6EhB;AAED;;;;;GAKG;AACH,0DAHW,MAAM,GACJ,MAAM,CAiBlB;AAED;;;;;;GAMG;AACH,4DAJW,MAAM,wBACN,MAAM,GACJ,MAAM,CAgBlB;AAED;;;;;;;GAOG;AACH,4DANW,MAAM,EAAE,iDACR,MAAM,eACN,MAAM,iBACN,MAAM,SAuEhB;AAGD;;;;;;;;;;;GAWG;AACH,wDATW,MAAM,EAAE,sBACR,MAAM,wBACN,MAAM,SAYhB;AA6BD;;;;;;;;;;;;;;;GAeG;AACH,qDATW,MAAM,EAAE,sBACR,MAAM,SAkChB;AAED;;;;;GAKG;AACH,8BAHa,MAAM,CAKlB;AAGD;;;;;;;;;;;;GAYG;AACH,2CARW,MAAM,WACN,MAAM,YACN,MAAM,0BACN,MAAM,OAoBhB;AAED;;;;;;;;;;;;GAYG;AACH,2CARW,MAAM,WACN,MAAM,YACN,MAAM,0BACN,MAAM,OAShB;AAED;;;;;GAKG;AACH,6BAHa,MAAM,EAAE,CAKpB;AAED;;;;;GAKG;AACH,+CAEC;AAED;;;;;GAKG;AACH,0EAEC;AAED;;;;;GAKG;AACH,uEAEC;AAED;;;;;GAKG;AACH,4CAEC;AAED;;;;;GAKG;AACH,0CAEC;AAED;;;;;GAKG;AACH,iDAEC;AAED;;;;;GAKG;AACH,oEAIC;AAED;;;;;GAKG;AACH,qCAHa,MAAM,CAKlB;AAED;;;;;GAKG;AACH,iDAEC;AAED;;;;;GAKG;AACH,8BAHa,MAAM,CAKlB;AAED;;;;;GAKG;AACH,0CAEC;AAED;;;;;GAKG;AACH,iDAHa,MAAM,CAKlB;AAED;;;;;GAKG;AACH,6DAOC;AAED;;;;GAIG;AACH,iCAFa,MAAM,CAIlB;AAED;;;;;GAKG;AACH,8CAEC;AA5oCD;;;;+QAA0D;AAC1D,sFAA0D;AAC1D;;;;;EAAgE;AAOhE;;;;+QAAwD;AACxD,qFAAwD;AAiIjD,yFA+KJ;AAOI,0FAFM,MAAM,CAOlB;AAcM,iDAUJ"}
@@ -4,9 +4,10 @@ import { useRef, useCallback, useMemo } from 'react';
4
4
  import create from 'zustand';
5
5
  import createContext from 'zustand/context';
6
6
  import shallow from 'zustand/shallow';
7
- import { isMatch, merge, cloneDeep } from 'lodash-es';
7
+ import { isMatch, cloneDeep } from 'lodash-es';
8
8
  import { CoordinationType } from '@vitessce/constants-internal';
9
9
  import { fromEntries, capitalize } from '@vitessce/utils';
10
+ import { getCoordinationSpaceAndScopes } from '@vitessce/config';
10
11
  import { removeImageChannelInMetaCoordinationScopesHelper, addImageChannelInMetaCoordinationScopesHelper, } from './spatial-reducers.js';
11
12
  // Reference: https://github.com/pmndrs/zustand#react-context
12
13
  // Reference: https://github.com/pmndrs/zustand/blob/e47ea03/tests/context.test.tsx#L60
@@ -37,7 +38,15 @@ export function getScopes(coordinationScopes, metaSpace) {
37
38
  metaScopesArr.forEach((metaScope) => {
38
39
  // Merge the original coordinationScopes with the matching meta-coordinationScopes
39
40
  // from the coordinationSpace.
40
- result = merge(result, metaSpace[metaScope]);
41
+ let o1 = result;
42
+ const o2 = metaSpace[metaScope] || {};
43
+ Object.entries(o2).forEach(([cType, cScope]) => {
44
+ o1 = {
45
+ ...o1,
46
+ [cType]: cScope,
47
+ };
48
+ });
49
+ result = o1;
41
50
  });
42
51
  }
43
52
  }
@@ -64,7 +73,29 @@ export function getScopesBy(coordinationScopes, coordinationScopesBy, metaSpaceB
64
73
  metaScopesArr.forEach((metaScope) => {
65
74
  // Merge the original coordinationScopesBy with the matching meta-coordinationScopesBy
66
75
  // from the coordinationSpace.
67
- result = merge(result, metaSpaceBy[metaScope]);
76
+ let o1 = result;
77
+ const o2 = metaSpaceBy[metaScope] || {};
78
+ // Cannot simply use lodash merge(o1, o2)
79
+ // because we do not want to merge (objects/arrays) at the leaf
80
+ // (i.e., secondaryScopeVal) level.
81
+ // We want the values in o2 to take precedence over the values in o1.
82
+ Object.entries(o2).forEach(([primaryType, primaryObj]) => {
83
+ Object.entries(primaryObj).forEach(([secondaryType, secondaryObj]) => {
84
+ Object.entries(secondaryObj).forEach(([primaryScope, secondaryScopeVal]) => {
85
+ o1 = {
86
+ ...o1,
87
+ [primaryType]: {
88
+ ...(o1?.[primaryType] || {}),
89
+ [secondaryType]: {
90
+ ...(o1?.[primaryType]?.[secondaryType] || {}),
91
+ [primaryScope]: secondaryScopeVal,
92
+ },
93
+ },
94
+ };
95
+ });
96
+ });
97
+ });
98
+ result = o1;
68
99
  });
69
100
  }
70
101
  }
@@ -146,6 +177,85 @@ export const createViewConfigStore = (initialLoaders, initialConfig) => create(s
146
177
  },
147
178
  };
148
179
  }),
180
+ mergeCoordination: (newCoordinationValues, scopePrefix, viewUid) => set((state) => {
181
+ const { coordinationSpace, layout } = state.viewConfig;
182
+ const { coordinationSpace: newCoordinationSpace, coordinationScopes, } = getCoordinationSpaceAndScopes(newCoordinationValues, scopePrefix);
183
+ // Merge coordination objects in coordination space
184
+ Object.entries(newCoordinationSpace).forEach(([coordinationType, coordinationObj]) => {
185
+ if (coordinationType === CoordinationType.META_COORDINATION_SCOPES) {
186
+ // Perform an extra level of merging for meta-coordination scopes.
187
+ Object.entries(coordinationObj).forEach(([coordinationScope, coordinationValue]) => {
188
+ coordinationSpace[coordinationType] = {
189
+ ...coordinationSpace[coordinationType],
190
+ [coordinationScope]: {
191
+ ...coordinationValue,
192
+ ...(coordinationSpace[coordinationType]?.[coordinationScope] || {}),
193
+ },
194
+ };
195
+ });
196
+ }
197
+ else if (coordinationType === CoordinationType.META_COORDINATION_SCOPES_BY) {
198
+ // Perform two extra levels of merging for meta-coordination scopesBy.
199
+ Object.entries(coordinationObj).forEach(([coordinationScope, coordinationValue]) => {
200
+ Object.entries(coordinationValue).forEach(([primaryType, primaryObj]) => {
201
+ Object.entries(primaryObj).forEach(([secondaryType, secondaryObj]) => {
202
+ coordinationSpace[coordinationType] = {
203
+ ...coordinationSpace[coordinationType],
204
+ [coordinationScope]: {
205
+ ...(coordinationSpace[coordinationType]?.[coordinationScope] || {}),
206
+ [primaryType]: {
207
+ ...(coordinationSpace[coordinationType]?.[coordinationScope]?.[primaryType] || {}),
208
+ [secondaryType]: {
209
+ ...secondaryObj,
210
+ ...(coordinationSpace[coordinationType]?.[coordinationScope]?.[primaryType]?.[secondaryType] || {}),
211
+ },
212
+ },
213
+ },
214
+ };
215
+ });
216
+ });
217
+ });
218
+ }
219
+ else {
220
+ coordinationSpace[coordinationType] = {
221
+ ...coordinationObj,
222
+ // Existing coordination values should be preserved,
223
+ // so that user-defined values take precedence over auto-initialization values.
224
+ ...(coordinationSpace[coordinationType] || {}),
225
+ };
226
+ }
227
+ });
228
+ const newViewConfig = {
229
+ ...state.viewConfig,
230
+ coordinationSpace: {
231
+ ...coordinationSpace,
232
+ },
233
+ layout: layout.map((viewObj) => {
234
+ if (viewObj.uid === viewUid) {
235
+ // Merge coordination scopes for views
236
+ return {
237
+ ...viewObj,
238
+ coordinationScopes: {
239
+ ...viewObj.coordinationScopes,
240
+ [CoordinationType.META_COORDINATION_SCOPES]: [
241
+ ...(coordinationScopes[CoordinationType.META_COORDINATION_SCOPES] || []),
242
+ ...(viewObj.coordinationScopes[CoordinationType.META_COORDINATION_SCOPES] || []),
243
+ ],
244
+ [CoordinationType.META_COORDINATION_SCOPES_BY]: [
245
+ ...(coordinationScopes[CoordinationType.META_COORDINATION_SCOPES_BY] || []),
246
+ ...(viewObj.coordinationScopes[CoordinationType.META_COORDINATION_SCOPES_BY] || []),
247
+ ],
248
+ },
249
+ };
250
+ }
251
+ return viewObj;
252
+ }),
253
+ };
254
+ // console.log('newViewConfig', newViewConfig);
255
+ return {
256
+ viewConfig: newViewConfig,
257
+ };
258
+ }),
149
259
  removeImageChannelInMetaCoordinationScopes: (coordinationScopesRaw, layerScope, channelScope) => set((state) => {
150
260
  const { coordinationSpace } = state.viewConfig;
151
261
  return {
@@ -854,6 +964,15 @@ export function useChangeLayout() {
854
964
  export function useSetLoaders() {
855
965
  return useViewConfigStore(state => state.setLoaders);
856
966
  }
967
+ /**
968
+ * Obtain the loaders setter function from
969
+ * the global app state.
970
+ * @returns {function} The loaders setter function
971
+ * in the `useViewConfigStore` store.
972
+ */
973
+ export function useMergeCoordination() {
974
+ return useViewConfigStore(state => state.mergeCoordination);
975
+ }
857
976
  /**
858
977
  * Obtain the view config setter function from
859
978
  * the global app state.
@@ -24,7 +24,7 @@ export function getMetaScope(coordinationScopes, coordinationSpace, parameter) {
24
24
  metaScopesArr.forEach((metaScope) => {
25
25
  // Merge the original coordinationScopes with the matching meta-coordinationScopes
26
26
  // from the coordinationSpace.
27
- if (metaSpace[metaScope][parameter]) {
27
+ if (metaSpace[metaScope]?.[parameter]) {
28
28
  latestMetaScope = metaScope;
29
29
  }
30
30
  });
@@ -81,7 +81,7 @@ export function useRowHeight(config, initialRowHeight, height, margin, padding)
81
81
  function withDefaults(coordinationValues, dataType, fileType, datasetUid, defaultCoordinationValues) {
82
82
  const defaultKeys = DATA_TYPE_COORDINATION_VALUE_USAGE[dataType]
83
83
  .filter(k => (Object.keys(defaultCoordinationValues).includes(k)
84
- && defaultCoordinationValues[k]
84
+ // && defaultCoordinationValues[k]
85
85
  && !Object.keys(coordinationValues).includes(k)));
86
86
  const defaultValues = pick(defaultCoordinationValues, defaultKeys);
87
87
  const coordinationValuesWithDefaults = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vitessce/vit-s",
3
- "version": "3.3.2",
3
+ "version": "3.3.3",
4
4
  "author": "Gehlenborg Lab",
5
5
  "homepage": "http://vitessce.io",
6
6
  "repository": {
@@ -29,10 +29,11 @@
29
29
  "uuid": "^9.0.0",
30
30
  "zustand": "^3.5.10",
31
31
  "react-aria": "^3.28.0",
32
- "@vitessce/constants-internal": "3.3.2",
33
- "@vitessce/plugins": "3.3.2",
34
- "@vitessce/schemas": "3.3.2",
35
- "@vitessce/utils": "3.3.2"
32
+ "@vitessce/plugins": "3.3.3",
33
+ "@vitessce/schemas": "3.3.3",
34
+ "@vitessce/config": "3.3.3",
35
+ "@vitessce/utils": "3.3.3",
36
+ "@vitessce/constants-internal": "3.3.3"
36
37
  },
37
38
  "devDependencies": {
38
39
  "@testing-library/jest-dom": "^5.16.4",
package/src/VitS.js CHANGED
@@ -224,6 +224,7 @@ export function VitS(props) {
224
224
  height={height}
225
225
  theme={theme}
226
226
  isBounded={isBounded}
227
+ stores={stores}
227
228
  />
228
229
  <CallbackPublisher
229
230
  onWarn={onWarn}
@@ -50,6 +50,7 @@ export default function VitessceGrid(props) {
50
50
  viewTypes,
51
51
  fileTypes,
52
52
  coordinationTypes,
53
+ stores,
53
54
  } = props;
54
55
 
55
56
  const [rowHeight, containerRef] = useRowHeight(config, initialRowHeight, height, margin, padding);
@@ -93,6 +94,7 @@ export default function VitessceGrid(props) {
93
94
  config.description,
94
95
  fileTypes,
95
96
  coordinationTypes,
97
+ stores,
96
98
  );
97
99
  newConfig = config;
98
100
  }
@@ -1,6 +1,10 @@
1
1
  import { useEffect, useMemo } from 'react';
2
2
  import { useQuery, useQueries } from '@tanstack/react-query';
3
- import { capitalize, fromEntries } from '@vitessce/utils';
3
+ import {
4
+ capitalize,
5
+ fromEntries,
6
+ getInitialCoordinationScopePrefix,
7
+ } from '@vitessce/utils';
4
8
  import { STATUS } from '@vitessce/constants-internal';
5
9
  import {
6
10
  getMatchingLoader,
@@ -66,7 +70,7 @@ export async function dataQueryFn(ctx) {
66
70
  const { data, url, coordinationValues } = payload;
67
71
  // Status: success
68
72
  // Array of objects like { url, name }.
69
- const urls = Array.isArray(url) ? url : [{ url, name: dataType }];
73
+ const urls = (Array.isArray(url) ? url : [{ url, name: dataType }]).filter(d => d.url);
70
74
  return { data, coordinationValues, urls };
71
75
  }
72
76
  // No loader was found.
@@ -169,6 +173,7 @@ export function useDataType(
169
173
  export function useDataTypeMulti(
170
174
  dataType, loaders, dataset, isRequired,
171
175
  coordinationSetters, initialCoordinationValues, matchOnObj,
176
+ mergeCoordination, viewUid,
172
177
  ) {
173
178
  const placeholderObject = useMemo(() => ({}), []);
174
179
  const setWarning = useSetWarning();
@@ -200,14 +205,23 @@ export function useDataTypeMulti(
200
205
 
201
206
  useEffect(() => {
202
207
  dataQueries
203
- .map(q => q.data?.coordinationValues)
204
- .filter(v => Boolean(v))
205
- .forEach((coordinationValues) => {
206
- initCoordinationSpace(
207
- coordinationValues,
208
- coordinationSetters,
209
- initialCoordinationValues,
210
- );
208
+ .filter(q => Boolean(q.data?.coordinationValues))
209
+ .forEach((q) => {
210
+ const { coordinationValues } = q.data;
211
+ if (mergeCoordination) {
212
+ mergeCoordination(
213
+ coordinationValues,
214
+ // Auto-generate based on the dataset and data type.
215
+ getInitialCoordinationScopePrefix(dataset, dataType),
216
+ viewUid,
217
+ );
218
+ } else {
219
+ initCoordinationSpace(
220
+ coordinationValues,
221
+ coordinationSetters,
222
+ initialCoordinationValues,
223
+ );
224
+ }
211
225
  });
212
226
  // Deliberate dependency omissions: use indirect dependencies for efficiency.
213
227
  // eslint-disable-next-line react-hooks/exhaustive-deps