@vitessce/vit-s 3.0.0 → 3.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 (105) hide show
  1. package/dist/index.js +28348 -25624
  2. package/dist-tsc/VitS.d.ts +7 -2
  3. package/dist-tsc/VitS.d.ts.map +1 -1
  4. package/dist-tsc/VitS.js +43 -23
  5. package/dist-tsc/VitessceGrid.d.ts.map +1 -1
  6. package/dist-tsc/VitessceGrid.js +14 -11
  7. package/dist-tsc/VitessceGrid.test.js +5 -2
  8. package/dist-tsc/Warning.js +2 -2
  9. package/dist-tsc/data/LoaderResult.d.ts +8 -3
  10. package/dist-tsc/data/LoaderResult.d.ts.map +1 -1
  11. package/dist-tsc/data/LoaderResult.js +5 -0
  12. package/dist-tsc/data-hook-utils.d.ts +3 -7
  13. package/dist-tsc/data-hook-utils.d.ts.map +1 -1
  14. package/dist-tsc/data-hook-utils.js +97 -79
  15. package/dist-tsc/data-hooks.d.ts +12 -16
  16. package/dist-tsc/data-hooks.d.ts.map +1 -1
  17. package/dist-tsc/data-hooks.js +140 -127
  18. package/dist-tsc/errors/DataSourceFetchError.js +1 -1
  19. package/dist-tsc/hooks.d.ts +3 -7
  20. package/dist-tsc/hooks.d.ts.map +1 -1
  21. package/dist-tsc/hooks.js +9 -18
  22. package/dist-tsc/index.d.ts +2 -1
  23. package/dist-tsc/index.js +2 -1
  24. package/dist-tsc/mui-utils.d.ts +2 -0
  25. package/dist-tsc/mui-utils.d.ts.map +1 -0
  26. package/dist-tsc/mui-utils.js +44 -0
  27. package/dist-tsc/shared-plot-options/OptionSelect.js +1 -1
  28. package/dist-tsc/shared-plot-options/styles.js +1 -1
  29. package/dist-tsc/state/hooks.d.ts +27 -1
  30. package/dist-tsc/state/hooks.d.ts.map +1 -1
  31. package/dist-tsc/state/hooks.js +61 -21
  32. package/dist-tsc/view-config-utils.d.ts +1 -0
  33. package/dist-tsc/view-config-utils.d.ts.map +1 -1
  34. package/dist-tsc/view-config-utils.js +7 -1
  35. package/dist-tsc/view-config-utils.test.js +1 -0
  36. package/dist-tsc/vitessce-grid-layout/VitessceGridLayout.test.js +1 -1
  37. package/dist-tsc/vitessce-grid-layout/layout-utils.test.js +1 -0
  38. package/package.json +10 -9
  39. package/src/VitS.js +79 -43
  40. package/src/VitessceGrid.js +16 -10
  41. package/src/VitessceGrid.test.jsx +8 -2
  42. package/src/Warning.js +2 -2
  43. package/src/data/LoaderResult.js +5 -0
  44. package/src/data-hook-utils.js +116 -81
  45. package/src/data-hooks.js +148 -129
  46. package/src/errors/DataSourceFetchError.js +1 -1
  47. package/src/hooks.js +11 -21
  48. package/src/index.js +2 -0
  49. package/src/mui-utils.js +52 -0
  50. package/src/shared-plot-options/OptionSelect.js +1 -1
  51. package/src/shared-plot-options/styles.js +1 -1
  52. package/src/state/hooks.js +66 -21
  53. package/src/view-config-utils.js +8 -0
  54. package/src/view-config-utils.test.jsx +1 -0
  55. package/src/vitessce-grid-layout/VitessceGridLayout.test.jsx +1 -1
  56. package/src/vitessce-grid-layout/layout-utils.test.js +1 -0
  57. package/dist-tsc/schemas/config-0.1.0.schema.json +0 -84
  58. package/dist-tsc/schemas/config-1.0.0.schema.json +0 -733
  59. package/dist-tsc/schemas/config-1.0.1.schema.json +0 -909
  60. package/dist-tsc/schemas/config-1.0.10.schema.json +0 -969
  61. package/dist-tsc/schemas/config-1.0.11.schema.json +0 -990
  62. package/dist-tsc/schemas/config-1.0.12.schema.json +0 -997
  63. package/dist-tsc/schemas/config-1.0.13.schema.json +0 -1013
  64. package/dist-tsc/schemas/config-1.0.14.schema.json +0 -1048
  65. package/dist-tsc/schemas/config-1.0.15.schema.json +0 -1048
  66. package/dist-tsc/schemas/config-1.0.16.schema.json +0 -1089
  67. package/dist-tsc/schemas/config-1.0.2.schema.json +0 -910
  68. package/dist-tsc/schemas/config-1.0.3.schema.json +0 -910
  69. package/dist-tsc/schemas/config-1.0.4.schema.json +0 -949
  70. package/dist-tsc/schemas/config-1.0.5.schema.json +0 -949
  71. package/dist-tsc/schemas/config-1.0.6.schema.json +0 -949
  72. package/dist-tsc/schemas/config-1.0.7.schema.json +0 -949
  73. package/dist-tsc/schemas/config-1.0.8.schema.json +0 -965
  74. package/dist-tsc/schemas/config-1.0.9.schema.json +0 -965
  75. package/dist-tsc/schemas/obsSets.schema.d.ts +0 -179
  76. package/dist-tsc/schemas/obsSets.schema.d.ts.map +0 -1
  77. package/dist-tsc/schemas/obsSets.schema.js +0 -195
  78. package/dist-tsc/schemas/obsSetsTabular.schema.d.ts +0 -57
  79. package/dist-tsc/schemas/obsSetsTabular.schema.d.ts.map +0 -1
  80. package/dist-tsc/schemas/obsSetsTabular.schema.js +0 -38
  81. package/dist-tsc/schemas/raster.schema.d.ts +0 -239
  82. package/dist-tsc/schemas/raster.schema.d.ts.map +0 -1
  83. package/dist-tsc/schemas/raster.schema.js +0 -120
  84. package/src/schemas/config-0.1.0.schema.json +0 -85
  85. package/src/schemas/config-1.0.0.schema.json +0 -733
  86. package/src/schemas/config-1.0.1.schema.json +0 -909
  87. package/src/schemas/config-1.0.10.schema.json +0 -969
  88. package/src/schemas/config-1.0.11.schema.json +0 -990
  89. package/src/schemas/config-1.0.12.schema.json +0 -997
  90. package/src/schemas/config-1.0.13.schema.json +0 -1013
  91. package/src/schemas/config-1.0.14.schema.json +0 -1048
  92. package/src/schemas/config-1.0.15.schema.json +0 -1048
  93. package/src/schemas/config-1.0.16.schema.json +0 -1089
  94. package/src/schemas/config-1.0.2.schema.json +0 -911
  95. package/src/schemas/config-1.0.3.schema.json +0 -911
  96. package/src/schemas/config-1.0.4.schema.json +0 -949
  97. package/src/schemas/config-1.0.5.schema.json +0 -949
  98. package/src/schemas/config-1.0.6.schema.json +0 -950
  99. package/src/schemas/config-1.0.7.schema.json +0 -950
  100. package/src/schemas/config-1.0.8.schema.json +0 -966
  101. package/src/schemas/config-1.0.9.schema.json +0 -965
  102. package/src/schemas/obsSets.schema.js +0 -195
  103. package/src/schemas/obsSetsTabular.schema.js +0 -39
  104. package/src/schemas/raster.schema.js +0 -121
  105. package/src/schemas/schema-schema.sh +0 -34
@@ -1,7 +1,8 @@
1
1
  import { useState, useEffect, useMemo } from 'react';
2
2
  import { CoordinationType, DataType, STATUS } from '@vitessce/constants-internal';
3
3
  import { fromEntries } from '@vitessce/utils';
4
- import { useMatchingLoader, useMultiCoordinationValues, useSetWarning } from './state/hooks.js';
4
+ import { useQuery, useQueries } from '@tanstack/react-query';
5
+ import { getMatchingLoader, useMultiCoordinationValues, useSetWarning, } from './state/hooks.js';
5
6
  import { LoaderNotFoundError, } from './errors/index.js';
6
7
  import { warn, useDataType, useDataTypeMulti, } from './data-hook-utils.js';
7
8
  /**
@@ -38,8 +39,6 @@ export function useDescription(loaders, dataset) {
38
39
  * datasets and data types to loader instances.
39
40
  * @param {string} dataset The key for a dataset,
40
41
  * used to identify which loader to use.
41
- * @param {function} addUrl A function to call to update
42
- * the URL list.
43
42
  * @param {boolean} isRequired Should a warning be thrown if
44
43
  * loading is unsuccessful?
45
44
  * @param {object} coordinationSetters Object where
@@ -52,35 +51,35 @@ export function useDescription(loaders, dataset) {
52
51
  * cells is an object and cellsCount is the
53
52
  * number of items in the cells object.
54
53
  */
55
- export function useObsEmbeddingData(loaders, dataset, addUrl, isRequired, coordinationSetters, initialCoordinationValues, matchOn) {
56
- return useDataType(DataType.OBS_EMBEDDING, loaders, dataset, addUrl, isRequired, coordinationSetters, initialCoordinationValues, matchOn);
54
+ export function useObsEmbeddingData(loaders, dataset, isRequired, coordinationSetters, initialCoordinationValues, matchOn) {
55
+ return useDataType(DataType.OBS_EMBEDDING, loaders, dataset, isRequired, coordinationSetters, initialCoordinationValues, matchOn);
57
56
  }
58
- export function useObsLocationsData(loaders, dataset, addUrl, isRequired, coordinationSetters, initialCoordinationValues, matchOn) {
59
- return useDataType(DataType.OBS_LOCATIONS, loaders, dataset, addUrl, isRequired, coordinationSetters, initialCoordinationValues, matchOn);
57
+ export function useObsLocationsData(loaders, dataset, isRequired, coordinationSetters, initialCoordinationValues, matchOn) {
58
+ return useDataType(DataType.OBS_LOCATIONS, loaders, dataset, isRequired, coordinationSetters, initialCoordinationValues, matchOn);
60
59
  }
61
- export function useObsLabelsData(loaders, dataset, addUrl, isRequired, coordinationSetters, initialCoordinationValues, matchOn) {
62
- return useDataType(DataType.OBS_LABELS, loaders, dataset, addUrl, isRequired, coordinationSetters, initialCoordinationValues, matchOn);
60
+ export function useObsLabelsData(loaders, dataset, isRequired, coordinationSetters, initialCoordinationValues, matchOn) {
61
+ return useDataType(DataType.OBS_LABELS, loaders, dataset, isRequired, coordinationSetters, initialCoordinationValues, matchOn);
63
62
  }
64
- export function useObsSegmentationsData(loaders, dataset, addUrl, isRequired, coordinationSetters, initialCoordinationValues, matchOn) {
65
- return useDataType(DataType.OBS_SEGMENTATIONS, loaders, dataset, addUrl, isRequired, coordinationSetters, initialCoordinationValues, matchOn);
63
+ export function useObsSegmentationsData(loaders, dataset, isRequired, coordinationSetters, initialCoordinationValues, matchOn) {
64
+ return useDataType(DataType.OBS_SEGMENTATIONS, loaders, dataset, isRequired, coordinationSetters, initialCoordinationValues, matchOn);
66
65
  }
67
- export function useObsSetsData(loaders, dataset, addUrl, isRequired, coordinationSetters, initialCoordinationValues, matchOn) {
68
- return useDataType(DataType.OBS_SETS, loaders, dataset, addUrl, isRequired, coordinationSetters, initialCoordinationValues, matchOn);
66
+ export function useObsSetsData(loaders, dataset, isRequired, coordinationSetters, initialCoordinationValues, matchOn) {
67
+ return useDataType(DataType.OBS_SETS, loaders, dataset, isRequired, coordinationSetters, initialCoordinationValues, matchOn);
69
68
  }
70
- export function useObsFeatureMatrixData(loaders, dataset, addUrl, isRequired, coordinationSetters, initialCoordinationValues, matchOn) {
71
- return useDataType(DataType.OBS_FEATURE_MATRIX, loaders, dataset, addUrl, isRequired, coordinationSetters, initialCoordinationValues, matchOn);
69
+ export function useObsFeatureMatrixData(loaders, dataset, isRequired, coordinationSetters, initialCoordinationValues, matchOn) {
70
+ return useDataType(DataType.OBS_FEATURE_MATRIX, loaders, dataset, isRequired, coordinationSetters, initialCoordinationValues, matchOn);
72
71
  }
73
- export function useFeatureLabelsData(loaders, dataset, addUrl, isRequired, coordinationSetters, initialCoordinationValues, matchOn) {
74
- return useDataType(DataType.FEATURE_LABELS, loaders, dataset, addUrl, isRequired, coordinationSetters, initialCoordinationValues, matchOn);
72
+ export function useFeatureLabelsData(loaders, dataset, isRequired, coordinationSetters, initialCoordinationValues, matchOn) {
73
+ return useDataType(DataType.FEATURE_LABELS, loaders, dataset, isRequired, coordinationSetters, initialCoordinationValues, matchOn);
75
74
  }
76
- export function useImageData(loaders, dataset, addUrl, isRequired, coordinationSetters, initialCoordinationValues, matchOn) {
77
- return useDataType(DataType.IMAGE, loaders, dataset, addUrl, isRequired, coordinationSetters, initialCoordinationValues, matchOn);
75
+ export function useImageData(loaders, dataset, isRequired, coordinationSetters, initialCoordinationValues, matchOn) {
76
+ return useDataType(DataType.IMAGE, loaders, dataset, isRequired, coordinationSetters, initialCoordinationValues, matchOn);
78
77
  }
79
- export function useGenomicProfilesData(loaders, dataset, addUrl, isRequired, coordinationSetters, initialCoordinationValues, matchOn) {
80
- return useDataType(DataType.GENOMIC_PROFILES, loaders, dataset, addUrl, isRequired, coordinationSetters, initialCoordinationValues, matchOn);
78
+ export function useGenomicProfilesData(loaders, dataset, isRequired, coordinationSetters, initialCoordinationValues, matchOn) {
79
+ return useDataType(DataType.GENOMIC_PROFILES, loaders, dataset, isRequired, coordinationSetters, initialCoordinationValues, matchOn);
81
80
  }
82
- export function useNeighborhoodsData(loaders, dataset, addUrl, isRequired, coordinationSetters, initialCoordinationValues, matchOn) {
83
- return useDataType(DataType.NEIGHBORHOODS, loaders, dataset, addUrl, isRequired, coordinationSetters, initialCoordinationValues, matchOn);
81
+ export function useNeighborhoodsData(loaders, dataset, isRequired, coordinationSetters, initialCoordinationValues, matchOn) {
82
+ return useDataType(DataType.NEIGHBORHOODS, loaders, dataset, isRequired, coordinationSetters, initialCoordinationValues, matchOn);
84
83
  }
85
84
  /**
86
85
  * Get data from the expression matrix data type loader for a given gene selection.
@@ -97,72 +96,70 @@ export function useNeighborhoodsData(loaders, dataset, addUrl, isRequired, coord
97
96
  * for however many genes are in the selection.
98
97
  */
99
98
  export function useFeatureSelection(loaders, dataset, isRequired, selection, matchOn) {
100
- const [geneData, setGeneData] = useState();
101
- const [status, setStatus] = useState(STATUS.LOADING);
102
- const [loadedGeneName, setLoadedGeneName] = useState(null);
103
99
  const setWarning = useSetWarning();
104
- const loader = useMatchingLoader(loaders, dataset, DataType.OBS_FEATURE_MATRIX, matchOn);
105
- useEffect(() => {
106
- if (!selection) {
107
- setGeneData(null);
108
- setLoadedGeneName(null);
109
- setStatus(STATUS.SUCCESS);
110
- return;
111
- }
112
- if (loader) {
113
- setGeneData(null);
114
- setLoadedGeneName(null);
115
- setStatus(STATUS.LOADING);
116
- const implementsGeneSelection = typeof loader.loadGeneSelection === 'function';
117
- if (implementsGeneSelection) {
118
- loader
119
- .loadGeneSelection({ selection })
120
- .catch(e => warn(e, setWarning))
121
- .then((payload) => {
122
- if (!payload)
123
- return;
124
- const { data } = payload;
125
- setGeneData(data);
126
- setStatus(STATUS.SUCCESS);
127
- setLoadedGeneName(selection);
128
- });
129
- }
130
- else {
131
- loader.load().catch(e => warn(e, setWarning)).then((payload) => {
100
+ const featureQueries = useQueries({
101
+ queries: selection?.map(featureId => ({
102
+ structuralSharing: false,
103
+ placeholderData: null,
104
+ queryKey: [dataset, DataType.OBS_FEATURE_MATRIX, matchOn, featureId, 'useFeatureSelection'],
105
+ // Query function should return an object
106
+ // { data, dataKey } where dataKey is the loaded gene selection.
107
+ queryFn: async (ctx) => {
108
+ const loader = getMatchingLoader(ctx.meta.loaders, ctx.queryKey[0], ctx.queryKey[1], ctx.queryKey[2]);
109
+ if (loader) {
110
+ const implementsGeneSelection = typeof loader.loadGeneSelection === 'function';
111
+ if (implementsGeneSelection) {
112
+ const payload = await loader.loadGeneSelection({ selection: [featureId] });
113
+ if (!payload)
114
+ return null;
115
+ const { data } = payload;
116
+ return { data: data[0], dataKey: selection };
117
+ }
118
+ // Loader does not implement loadGeneSelection.
119
+ const payload = await loader.load();
132
120
  if (!payload)
133
- return;
121
+ return null;
134
122
  const { data } = payload;
135
123
  const { obsIndex, featureIndex, obsFeatureMatrix } = data;
136
- const expressionDataForSelection = selection.map((sel) => {
137
- const geneIndex = featureIndex.indexOf(sel);
138
- const numGenes = featureIndex.length;
139
- const numCells = obsIndex.length;
140
- const expressionData = new Float32Array(numCells);
141
- for (let cellIndex = 0; cellIndex < numCells; cellIndex += 1) {
142
- expressionData[cellIndex] = obsFeatureMatrix.data[cellIndex * numGenes + geneIndex];
143
- }
144
- return expressionData;
145
- });
146
- setGeneData(expressionDataForSelection);
147
- setStatus(STATUS.SUCCESS);
148
- setLoadedGeneName(selection);
149
- });
150
- }
151
- }
152
- else {
153
- setGeneData(null);
154
- setLoadedGeneName(null);
155
- if (isRequired) {
156
- warn(new LoaderNotFoundError(loaders, dataset, DataType.OBS_FEATURE_MATRIX, matchOn), setWarning);
157
- setStatus(STATUS.ERROR);
158
- }
159
- else {
160
- setStatus(STATUS.SUCCESS);
161
- }
162
- }
124
+ // Compute expressionData
125
+ const geneIndex = featureIndex.indexOf(featureId);
126
+ const numGenes = featureIndex.length;
127
+ const numCells = obsIndex.length;
128
+ const expressionData = new Float32Array(numCells);
129
+ for (let cellIndex = 0; cellIndex < numCells; cellIndex += 1) {
130
+ expressionData[cellIndex] = obsFeatureMatrix.data[cellIndex * numGenes + geneIndex];
131
+ }
132
+ return { data: expressionData, dataKey: featureId };
133
+ }
134
+ // No loader was found.
135
+ if (isRequired) {
136
+ throw new LoaderNotFoundError(loaders, dataset, DataType.OBS_FEATURE_MATRIX, matchOn);
137
+ }
138
+ else {
139
+ return { data: null, dataKey: null };
140
+ }
141
+ },
142
+ meta: { loaders },
143
+ })) || [],
144
+ });
145
+ const anyLoading = featureQueries.some(q => q.isFetching);
146
+ const anyError = featureQueries.some(q => q.isError);
147
+ // eslint-disable-next-line no-nested-ternary
148
+ const dataStatus = anyLoading ? STATUS.LOADING : (anyError ? STATUS.ERROR : STATUS.SUCCESS);
149
+ const isSuccess = dataStatus === STATUS.SUCCESS;
150
+ const geneData = isSuccess ? featureQueries.map(q => q.data?.data || null) : null;
151
+ const loadedGeneName = isSuccess ? featureQueries.map(q => q.data?.dataKey || null) : null;
152
+ useEffect(() => {
153
+ featureQueries
154
+ .map(q => q.error)
155
+ .filter(e => Boolean(e))
156
+ .forEach((error) => {
157
+ warn(error, setWarning);
158
+ });
159
+ // Deliberate dependency omissions: use indirect dependencies for efficiency.
163
160
  // eslint-disable-next-line react-hooks/exhaustive-deps
164
- }, [loader, selection]);
165
- return [geneData, loadedGeneName, status];
161
+ }, [anyError, setWarning]);
162
+ return [geneData, loadedGeneName, dataStatus];
166
163
  }
167
164
  /**
168
165
  * Get the attributes for the expression matrix data type loader,
@@ -174,68 +171,84 @@ export function useFeatureSelection(loaders, dataset, isRequired, selection, mat
174
171
  * datasets and data types to loader instances.
175
172
  * @param {string} dataset The key for a dataset,
176
173
  * used to identify which loader to use.
177
- * @param {function} addUrl A function to call to update
178
- * the URL list.
179
174
  * @param {boolean} isRequired Should a warning be thrown if
180
175
  * loading is unsuccessful?
181
176
  * @returns {object} [attrs] { rows, cols } object containing cell and gene names.
182
177
  */
183
- export function useObsFeatureMatrixIndices(loaders, dataset, addUrl, isRequired, matchOn) {
184
- const [data, setData] = useState({});
185
- const [status, setStatus] = useState(STATUS.LOADING);
178
+ export function useObsFeatureMatrixIndices(loaders, dataset, isRequired, matchOn) {
186
179
  const setWarning = useSetWarning();
187
- const loader = useMatchingLoader(loaders, dataset, DataType.OBS_FEATURE_MATRIX, matchOn);
188
- useEffect(() => {
189
- if (loader) {
190
- setStatus(STATUS.LOADING);
191
- const implementsLoadAttrs = typeof loader.loadAttrs === 'function';
192
- if (implementsLoadAttrs) {
193
- loader.loadAttrs().catch(e => warn(e, setWarning)).then((payload) => {
194
- if (!payload)
195
- return;
196
- const { data: payloadData, url } = payload;
197
- setData({
198
- obsIndex: payloadData.rows,
199
- featureIndex: payloadData.cols,
200
- });
201
- addUrl(url, DataType.OBS_FEATURE_MATRIX);
202
- setStatus(STATUS.SUCCESS);
203
- });
204
- }
205
- else {
206
- loader.load().catch(e => warn(e, setWarning)).then((payload) => {
180
+ const placeholderObject = useMemo(() => ({}), []);
181
+ const indicesQuery = useQuery({
182
+ // TODO: only enable once `loaders` is available?
183
+ structuralSharing: false,
184
+ placeholderData: placeholderObject,
185
+ // Include the hook name in the queryKey to prevent the case in which an identical queryKey
186
+ // in a different hook would cause an accidental cache hit.
187
+ queryKey: [dataset, DataType.OBS_FEATURE_MATRIX, matchOn, 'useObsFeatureMatrixIndices'],
188
+ // Query function should return an object
189
+ // { data, dataKey } where dataKey is the loaded gene selection.
190
+ // TODO: use TypeScript to type the return value?
191
+ queryFn: async (ctx) => {
192
+ const loader = getMatchingLoader(ctx.meta.loaders, ctx.queryKey[0], ctx.queryKey[1], ctx.queryKey[2]);
193
+ if (loader) {
194
+ const implementsLoadAttrs = typeof loader.loadAttrs === 'function';
195
+ if (implementsLoadAttrs) {
196
+ // Has loadAttrs function.
197
+ const payload = await loader.loadAttrs();
207
198
  if (!payload)
208
- return;
199
+ return placeholderObject;
209
200
  const { data: payloadData, url } = payload;
210
- setData({
201
+ return {
202
+ data: {
203
+ obsIndex: payloadData.rows,
204
+ featureIndex: payloadData.cols,
205
+ },
206
+ urls: [{ url, name: DataType.OBS_FEATURE_MATRIX }],
207
+ };
208
+ }
209
+ // No loadAttrs function.
210
+ const payload = await loader.load();
211
+ if (!payload)
212
+ return placeholderObject;
213
+ const { data: payloadData, url } = payload;
214
+ return {
215
+ data: {
211
216
  obsIndex: payloadData.obsIndex,
212
217
  featureIndex: payloadData.featureIndex,
213
- });
214
- addUrl(url, DataType.OBS_FEATURE_MATRIX);
215
- setStatus(STATUS.SUCCESS);
216
- });
218
+ },
219
+ urls: [{ url, name: DataType.OBS_FEATURE_MATRIX }],
220
+ };
217
221
  }
218
- }
219
- else {
220
- setData({});
222
+ // No loader was found.
221
223
  if (isRequired) {
222
- warn(new LoaderNotFoundError(loaders, dataset, DataType.OBS_FEATURE_MATRIX, matchOn), setWarning);
223
- setStatus(STATUS.ERROR);
224
+ // Status: error
225
+ throw new LoaderNotFoundError(loaders, dataset, DataType.OBS_FEATURE_MATRIX, matchOn);
224
226
  }
225
227
  else {
226
- setStatus(STATUS.SUCCESS);
228
+ // Status: success
229
+ return { data: placeholderObject, dataKey: null };
227
230
  }
231
+ },
232
+ meta: { loaders },
233
+ });
234
+ const { data, status, isFetching, error } = indicesQuery;
235
+ const loadedData = data?.data || placeholderObject;
236
+ const dataStatus = isFetching ? STATUS.LOADING : status;
237
+ const urls = data?.urls;
238
+ useEffect(() => {
239
+ if (error) {
240
+ setWarning(error.message);
228
241
  }
229
- // eslint-disable-next-line react-hooks/exhaustive-deps
230
- }, [loader]);
231
- return [data, status];
242
+ }, [error, setWarning]);
243
+ return [loadedData, dataStatus, urls];
232
244
  }
233
- export function useMultiObsLabels(coordinationScopes, obsType, loaders, dataset, addUrl) {
245
+ export function useMultiObsLabels(coordinationScopes, obsType, loaders, dataset) {
234
246
  const obsLabelsTypes = useMultiCoordinationValues(CoordinationType.OBS_LABELS_TYPE, coordinationScopes);
235
247
  const obsLabelsMatchOnObj = useMemo(() => fromEntries(Object.entries(obsLabelsTypes).map(([scope, obsLabelsType]) => ([
236
248
  scope,
237
249
  { obsLabelsType, obsType },
238
250
  ]))), [obsLabelsTypes, obsType]);
239
- const [obsLabelsData, obsLabelsDataStatus] = useDataTypeMulti(DataType.OBS_LABELS, loaders, dataset, addUrl, false, {}, {}, obsLabelsMatchOnObj);
240
- return [obsLabelsTypes, obsLabelsData, obsLabelsDataStatus];
251
+ const [obsLabelsData, obsLabelsDataStatus] = useDataTypeMulti(DataType.OBS_LABELS, loaders, dataset, false, {}, {}, obsLabelsMatchOnObj);
252
+ const urls = null; // TODO?
253
+ return [obsLabelsTypes, obsLabelsData, obsLabelsDataStatus, urls];
241
254
  }
@@ -8,6 +8,6 @@ export default class DataSourceFetchError extends AbstractLoaderError {
8
8
  }
9
9
  warnInConsole() {
10
10
  const { source, url, headers } = this;
11
- console.warn(`${source} failed to fetch from ${url} with headers ${headers}`);
11
+ console.warn(`${source} failed to fetch from ${url} with headers ${JSON.stringify(headers)}`);
12
12
  }
13
13
  }
@@ -28,14 +28,10 @@ export function useDeckCanvasSize(): array;
28
28
  export function useReady(statusValues: string[]): boolean;
29
29
  /**
30
30
  * This hook helps manage a list of URLs.
31
- * @param {object} loaders The loaders dependency.
32
- * @param {string} dataset The dataset UID dependency.
33
- * @returns {array} An array
34
- * [urls, addUrl]
35
- * where urls is the array of URL objects,
36
- * and addUrl is a function for adding a URL to the array.
31
+ * @param {(null|object[])[]} urls Array of (null or array of { url, name }).
32
+ * @returns {array} An array of { url, name } objects (flattened from the input).
37
33
  */
38
- export function useUrls(loaders: object, dataset: string): array;
34
+ export function useUrls(urls: (null | object[])[]): array;
39
35
  /**
40
36
  * Custom hook, subscribes to the width and height of the closest .vitessce-container
41
37
  * element and updates upon window resize events.
@@ -1 +1 @@
1
- {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.js"],"names":[],"mappings":"AAiBA,oDAOC;AAED;;;;GAIG;AACH,6CAgBC;AAED;;;;GAIG;AACH,yCAiCC;AAED;;;;;GAKG;AACH,2CAiCC;AAED;;;;;;GAMG;AACH,uCAHW,MAAM,EAAE,GACN,OAAO,CAOnB;AAED;;;;;;;;GAQG;AACH,iCAPW,MAAM,WACN,MAAM,SAoBhB;AAED;;;;;;GAMG;AACH,iEAuBC;AAED;;;;;;;;;;GAUG;AACH;IAR0B,gBAAgB,EAA/B,MAAM;UAqBhB;AAED;;;;;;;;;;GAUG;AACH,yDARW,QAAM,IAAI,SAuBpB;AAED;;;;QA2BC;AAED,iEAOC;AAED,kHAuBC"}
1
+ {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.js"],"names":[],"mappings":"AAkBA,oDAOC;AAED;;;;GAIG;AACH,6CAgBC;AAED;;;;GAIG;AACH,yCAiCC;AAED;;;;;GAKG;AACH,2CAiCC;AAED;;;;;;GAMG;AACH,uCAHW,MAAM,EAAE,GACN,OAAO,CAOnB;AAED;;;;GAIG;AACH,8BAHW,CAAC,IAAI,GAAC,MAAM,EAAE,CAAC,EAAE,SAU3B;AAED;;;;;;GAMG;AACH,iEAuBC;AAED;;;;;;;;;;GAUG;AACH;IAR0B,gBAAgB,EAA/B,MAAM;UAqBhB;AAED;;;;;;;;;;GAUG;AACH,yDARW,QAAM,IAAI,SAuBpB;AAED;;;;QA2BC;AAED,iEAOC;AAED,kHAuBC"}
package/dist-tsc/hooks.js CHANGED
@@ -2,6 +2,7 @@ import { useRef, useState, useEffect, useCallback, useMemo, } from 'react';
2
2
  import { debounce, every } from 'lodash-es';
3
3
  import { extent } from 'd3-array';
4
4
  import { capitalize, fromEntries } from '@vitessce/utils';
5
+ import { STATUS } from '@vitessce/constants-internal';
5
6
  import { useGridResize, useEmitGridResize } from './state/hooks.js';
6
7
  import { VITESSCE_CONTAINER } from './classNames.js';
7
8
  function getWindowDimensions() {
@@ -115,28 +116,18 @@ export function useDeckCanvasSize() {
115
116
  * @returns {boolean} Whether the status values are all success.
116
117
  */
117
118
  export function useReady(statusValues) {
118
- return useMemo(() => every(statusValues, val => val === 'success'), statusValues);
119
+ return useMemo(() => every(statusValues, val => val !== STATUS.LOADING), statusValues);
119
120
  }
120
121
  /**
121
122
  * This hook helps manage a list of URLs.
122
- * @param {object} loaders The loaders dependency.
123
- * @param {string} dataset The dataset UID dependency.
124
- * @returns {array} An array
125
- * [urls, addUrl]
126
- * where urls is the array of URL objects,
127
- * and addUrl is a function for adding a URL to the array.
123
+ * @param {(null|object[])[]} urls Array of (null or array of { url, name }).
124
+ * @returns {array} An array of { url, name } objects (flattened from the input).
128
125
  */
129
- export function useUrls(loaders, dataset) {
130
- const [urls, setUrls] = useState([]);
131
- const addUrl = useCallback((url, name) => {
132
- if (url) {
133
- setUrls(prev => ([...prev, { url, name }]));
134
- }
135
- }, [setUrls]);
136
- useEffect(() => {
137
- setUrls([]);
138
- }, [loaders, dataset]);
139
- return [urls, addUrl];
126
+ export function useUrls(urls) {
127
+ const mergedUrls = useMemo(() => urls.filter(a => Array.isArray(a)).flat(),
128
+ // eslint-disable-next-line react-hooks/exhaustive-deps
129
+ urls);
130
+ return mergedUrls;
140
131
  }
141
132
  /**
142
133
  * Custom hook, subscribes to the width and height of the closest .vitessce-container
@@ -2,8 +2,9 @@ export { VitS } from "./VitS.js";
2
2
  export { TitleInfo } from "./TitleInfo.js";
3
3
  export { PopperMenu } from "./shared-mui/components.js";
4
4
  export { useHasLoader } from "./data-hook-utils.js";
5
+ export { logConfig } from "./view-config-utils.js";
5
6
  export { useReady, useUrls, useVitessceContainer, useDeckCanvasSize, useUint8ObsFeatureMatrix, useUint8FeatureSelection, useExpressionValueGetter, useGetObsMembership, useGetObsInfo, useClosestVitessceContainerSize, useWindowDimensions, useGridItemSize } from "./hooks.js";
6
- export { useCoordination, useComplexCoordination, useMultiCoordinationValues, useMultiDatasetCoordination, useDatasetUids, useLoaders, useMatchingLoader, useViewConfigStore, useViewConfigStoreApi, useComponentHover, useSetComponentHover, useComponentViewInfo, useSetComponentViewInfo, useWarning, useSetWarning, useAuxiliaryCoordination, useComponentLayout } from "./state/hooks.js";
7
+ export { useInitialCoordination, useCoordination, useComplexCoordination, useMultiCoordinationValues, useMultiDatasetCoordination, useDatasetUids, useLoaders, useMatchingLoader, useViewConfigStore, useViewConfigStoreApi, useComponentHover, useSetComponentHover, useComponentViewInfo, useSetComponentViewInfo, useWarning, useSetWarning, useAuxiliaryCoordination, useComponentLayout } from "./state/hooks.js";
7
8
  export { useDescription, useImageData, useObsSetsData, useObsEmbeddingData, useFeatureSelection, useObsFeatureMatrixIndices, useMultiObsLabels, useObsLocationsData, useObsSegmentationsData, useNeighborhoodsData, useObsLabelsData, useObsFeatureMatrixData, useFeatureLabelsData, useGenomicProfilesData } from "./data-hooks.js";
8
9
  export { AbstractLoader, AbstractTwoStepLoader, LoaderResult } from "./data/index.js";
9
10
  export { AbstractLoaderError, DatasetNotFoundError, LoaderNotFoundError, LoaderValidationError, DataSourceFetchError } from "./errors/index.js";
package/dist-tsc/index.js CHANGED
@@ -3,9 +3,10 @@ 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 { useCoordination, useComplexCoordination, useMultiCoordinationValues, useMultiDatasetCoordination, useDatasetUids, useLoaders, useMatchingLoader, useViewConfigStore, useViewConfigStoreApi, useComponentHover, useSetComponentHover, useComponentViewInfo, useSetComponentViewInfo, useWarning, useSetWarning, useAuxiliaryCoordination, useComponentLayout, } from './state/hooks.js';
6
+ export { useInitialCoordination, useCoordination, useComplexCoordination, useMultiCoordinationValues, useMultiDatasetCoordination, useDatasetUids, useLoaders, useMatchingLoader, useViewConfigStore, useViewConfigStoreApi, useComponentHover, useSetComponentHover, useComponentViewInfo, useSetComponentViewInfo, useWarning, useSetWarning, useAuxiliaryCoordination, useComponentLayout, } from './state/hooks.js';
7
7
  export { useDescription, useImageData, useObsSetsData, useObsEmbeddingData, useFeatureSelection, useObsFeatureMatrixIndices, useMultiObsLabels, useObsLocationsData, useObsSegmentationsData, useNeighborhoodsData, useObsLabelsData, useObsFeatureMatrixData, useFeatureLabelsData, useGenomicProfilesData, } from './data-hooks.js';
8
8
  export { useHasLoader, } from './data-hook-utils.js';
9
9
  export { AbstractLoader, AbstractTwoStepLoader, LoaderResult, } from './data/index.js';
10
10
  export { AbstractLoaderError, DatasetNotFoundError, LoaderNotFoundError, LoaderValidationError, DataSourceFetchError, } from './errors/index.js';
11
11
  export { CellColorEncodingOption, OptionsContainer, OptionSelect, usePlotOptionsStyles, } from './shared-plot-options/index.js';
12
+ export { logConfig } from './view-config-utils.js';
@@ -0,0 +1,2 @@
1
+ export function createGenerateClassName(customPrefix: any): (rule: any, styleSheet: any) => string;
2
+ //# sourceMappingURL=mui-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mui-utils.d.ts","sourceRoot":"","sources":["../src/mui-utils.js"],"names":[],"mappings":"AAyBA,mGA0BC"}
@@ -0,0 +1,44 @@
1
+ // This function has been copied from MUI v4
2
+ // with logic related to randomness / random numbers removed.
3
+ // Reference: https://github.com/mui/material-ui/blob/0adada09/packages/mui-styles/src/createGenerateClassName/createGenerateClassName.js#L29
4
+ /**
5
+ * This is the list of the style rule name we use as drop in replacement for the built-in
6
+ * pseudo classes (:checked, :disabled, :focused, etc.).
7
+ *
8
+ * Why do they exist in the first place?
9
+ * These classes are used at a specificity of 2.
10
+ * It allows them to override previously defined styles as well as
11
+ * being untouched by simple user overrides.
12
+ */
13
+ const stateClasses = [
14
+ 'checked',
15
+ 'disabled',
16
+ 'error',
17
+ 'focused',
18
+ 'focusVisible',
19
+ 'required',
20
+ 'expanded',
21
+ 'selected',
22
+ ];
23
+ const defaultPrefix = 'vit-';
24
+ export function createGenerateClassName(customPrefix) {
25
+ return (rule, styleSheet) => {
26
+ const { name: styleSheetName, link: styleSheetLink, classNamePrefix, } = styleSheet.options;
27
+ const { key: ruleKey } = rule;
28
+ const seedPrefix = customPrefix ? `${customPrefix}-` : defaultPrefix;
29
+ // Is a global static MUI style?
30
+ if (styleSheetName && styleSheetName.indexOf('Mui') === 0 && !styleSheetLink) {
31
+ // We can use a shorthand class name, we never use the keys to style the components.
32
+ if (stateClasses.indexOf(ruleKey) !== -1) {
33
+ return `Mui-${ruleKey}`;
34
+ }
35
+ const prefix = `${seedPrefix}${styleSheetName}-${ruleKey}`;
36
+ return prefix;
37
+ }
38
+ // Help with debuggability.
39
+ if (classNamePrefix) {
40
+ return `${seedPrefix}${classNamePrefix}-${ruleKey}`;
41
+ }
42
+ return `${seedPrefix}${ruleKey}`;
43
+ };
44
+ }
@@ -6,7 +6,7 @@ export default function OptionSelect(props) {
6
6
  const { classes: classesProp = {} } = props;
7
7
  const classes = useStyles();
8
8
  return (_jsx(Select, { native: true, disableUnderline: true, ...props, classes: {
9
- root: classes.selectRoot,
9
+ root: classes.optionSelectRoot,
10
10
  ...classesProp,
11
11
  } }));
12
12
  }
@@ -41,7 +41,7 @@ export const useStyles = makeStyles(theme => ({
41
41
  fontSize: '14px',
42
42
  },
43
43
  },
44
- selectRoot: {
44
+ optionSelectRoot: {
45
45
  padding: 0,
46
46
  height: 'auto',
47
47
  },
@@ -1,3 +1,14 @@
1
+ /**
2
+ * This hook uses the same logic as for the `values` part of
3
+ * the useCoordination hook, with the difference that it
4
+ * gets its values from the _initial_ view config rather
5
+ * than the current view config.
6
+ * @param {string[]} parameters Array of coordination types.
7
+ * @param {object} coordinationScopes Mapping of coordination types
8
+ * to scope names.
9
+ * @returns {object} Object containing all coordination values.
10
+ */
11
+ export function useInitialCoordination(parameters: string[], coordinationScopes: object): object;
1
12
  /**
2
13
  * The useCoordination hook returns both the
3
14
  * values and setter functions for the coordination objects
@@ -74,6 +85,20 @@ export function useAuxiliaryCoordination(parameters: string[], coordinationScope
74
85
  * in the `useViewConfigStore` store.
75
86
  */
76
87
  export function useLoaders(): object;
88
+ /**
89
+ * Find a specific loader instance for a particular dataset, data type, and view
90
+ * coordination values (mapping from coordination types to coordination values).
91
+ * Uses lodash/isMatch to perform matching against the file definition's
92
+ * coordination value mapping.
93
+ * @param {object} loaders The value returned by useLoaders.
94
+ * @param {string} dataset The dataset UID.
95
+ * @param {string} dataType The data type for the matching file.
96
+ * @param {object} viewCoordinationValues Current coordination values
97
+ * from the view. Match these against a subset of file definition coordination
98
+ * values.
99
+ * @returns The matching loader instance or `null`.
100
+ */
101
+ export function getMatchingLoader(loaders: object, dataset: string, dataType: string, viewCoordinationValues: object): any;
77
102
  /**
78
103
  * Find a specific loader instance for a particular dataset, data type, and view
79
104
  * coordination values (mapping from coordination types to coordination values).
@@ -93,6 +118,7 @@ export function useMatchingLoader(loaders: object, dataset: string, dataType: st
93
118
  * coordination values (mapping from coordination types to coordination values).
94
119
  * Uses lodash/isMatch to perform matching against the file definition's
95
120
  * coordination value mapping.
121
+ * TODO: can this function be removed?
96
122
  * @param {object} loaders The value returned by useLoaders.
97
123
  * @param {string} dataset The dataset UID.
98
124
  * @param {string} dataType The data type for the matching file.
@@ -210,7 +236,7 @@ export const AuxiliaryProvider: ({ initialStore, createStore, children, }: {
210
236
  children: import("../../../plugins/node_modules/@types/react/ts5.0").ReactNode;
211
237
  }) => import("../../../plugins/node_modules/@types/react/ts5.0").FunctionComponentElement<import("../../../plugins/node_modules/@types/react/ts5.0").ProviderProps<import("zustand").UseBoundStore<object, import("zustand").StoreApi<object>> | undefined>>;
212
238
  export const useAuxiliaryStore: import("zustand/context").UseContextStore<object>;
213
- export function createViewConfigStore(): Function;
239
+ export function createViewConfigStore(initialLoaders: any, initialConfig: any): Function;
214
240
  export function useComponentLayout(component: any, scopes: any, coordinationScopes: any): Object;
215
241
  export function createAuxiliaryStore(): Function;
216
242
  //# sourceMappingURL=hooks.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/state/hooks.js"],"names":[],"mappings":"AAuLA;;;;;;;;;;;;;;;GAeG;AACH,4CATW,MAAM,EAAE,sBACR,MAAM,SAkChB;AAED,yFAmBC;AAED;;;;GAIG;AACH,mDAHW,MAAM,GACJ,MAAM,CAIlB;AAED;;;;;;;;;;;;;GAaG;AACH,mDAXW,MAAM,EAAE,sBACR,MAAM,wBACN,MAAM,UAEN,MAAM,SAsEhB;AAED;;;;;;;;;;;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;AAED;;;;;;;;;;;;GAYG;AACH,2CARW,MAAM,WACN,MAAM,YACN,MAAM,0BACN,MAAM,OAsBhB;AAED;;;;;;;;;;;;GAYG;AACH,4CARW,MAAM,WACN,MAAM,YACN,MAAM,uCA4BhB;AAED;;;;;GAKG;AACH,6BAHa,MAAM,EAAE,CAKpB;AAED;;;;;GAKG;AACH,+CAEC;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;AA9mBD;;;;6PAA0D;AAC1D,mFAA0D;AAC1D;;;;;EAAgE;AAOhE;;;;6PAAwD;AACxD,kFAAwD;AAajD,kDA+CJ;AAOI,0FAFM,MAAM,CAOlB;AAcM,iDAUJ"}
1
+ {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/state/hooks.js"],"names":[],"mappings":"AAyLA;;;;;;;;;GASG;AACH,mDALW,MAAM,EAAE,sBACR,MAAM,GAEJ,MAAM,CAclB;AAED;;;;;;;;;;;;;;;GAeG;AACH,4CATW,MAAM,EAAE,sBACR,MAAM,SAkChB;AAED,yFAmBC;AAED;;;;GAIG;AACH,mDAHW,MAAM,GACJ,MAAM,CAIlB;AAED;;;;;;;;;;;;;GAaG;AACH,mDAXW,MAAM,EAAE,sBACR,MAAM,wBACN,MAAM,UAEN,MAAM,SAsEhB;AAED;;;;;;;;;;;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;;;;;;;;;;;;;GAaG;AACH,4CARW,MAAM,WACN,MAAM,YACN,MAAM,uCA4BhB;AAED;;;;;GAKG;AACH,6BAHa,MAAM,EAAE,CAKpB;AAED;;;;;GAKG;AACH,+CAEC;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;AA3pBD;;;;6PAA0D;AAC1D,mFAA0D;AAC1D;;;;;EAAgE;AAOhE;;;;6PAAwD;AACxD,kFAAwD;AAajD,yFAiDJ;AAOI,0FAFM,MAAM,CAOlB;AAcM,iDAUJ"}