@vitessce/config 3.0.1 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +515 -59
- package/dist-tsc/VitessceAutoConfig.d.ts +13 -1
- package/dist-tsc/VitessceAutoConfig.d.ts.map +1 -1
- package/dist-tsc/VitessceAutoConfig.js +233 -57
- package/dist-tsc/VitessceAutoConfig.test.js +533 -76
- package/dist-tsc/VitessceConfig.d.ts +46 -0
- package/dist-tsc/VitessceConfig.d.ts.map +1 -1
- package/dist-tsc/VitessceConfig.js +353 -0
- package/dist-tsc/VitessceConfig.test.js +328 -1
- package/dist-tsc/constants.d.ts +247 -0
- package/dist-tsc/constants.d.ts.map +1 -0
- package/dist-tsc/constants.js +87 -0
- package/dist-tsc/index.d.ts +2 -1
- package/dist-tsc/index.js +2 -1
- package/package.json +3 -3
- package/src/VitessceAutoConfig.js +271 -65
- package/src/VitessceAutoConfig.test.js +561 -78
- package/src/VitessceConfig.js +393 -0
- package/src/VitessceConfig.test.js +338 -0
- package/src/constants.js +94 -0
- package/src/index.js +2 -1
|
@@ -1,2 +1,14 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Returns the hints that are available for the given file URLs, depending on their types.
|
|
3
|
+
* @param {Array} fileUrls containing urls of files to be loaded into Vitessce
|
|
4
|
+
* @returns the hints available for these file URLs
|
|
5
|
+
*/
|
|
6
|
+
export function getHintOptions(fileUrls: any[]): any;
|
|
7
|
+
/**
|
|
8
|
+
*
|
|
9
|
+
* @param {Array} fileUrls containing urls of files to be loaded into Vitessce
|
|
10
|
+
* @param {String} the hints config to be used for the dataset. Null by default
|
|
11
|
+
* @returns ViewConfig as JSON
|
|
12
|
+
*/
|
|
13
|
+
export function generateConfig(fileUrls: any[], hintTitle?: null): Promise<object>;
|
|
2
14
|
//# sourceMappingURL=VitessceAutoConfig.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VitessceAutoConfig.d.ts","sourceRoot":"","sources":["../src/VitessceAutoConfig.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"VitessceAutoConfig.d.ts","sourceRoot":"","sources":["../src/VitessceAutoConfig.js"],"names":[],"mappings":"AA+jBA;;;;GAIG;AACH,qDAgBC;AAED;;;;;GAKG;AACH,mFA8CC"}
|
|
@@ -1,5 +1,32 @@
|
|
|
1
|
-
import { CoordinationType, FileType } from '@vitessce/constants-internal';
|
|
1
|
+
import { CoordinationType as ct, FileType } from '@vitessce/constants-internal';
|
|
2
2
|
import { VitessceConfig, } from './VitessceConfig.js';
|
|
3
|
+
import { HINTS_CONFIG, HINT_TYPE_TO_FILE_TYPE_MAP } from './constants.js';
|
|
4
|
+
/**
|
|
5
|
+
* @param {Object} hintsConfig. The hints config for the given dataset.
|
|
6
|
+
*
|
|
7
|
+
* @param {Array} possibleViews. All views for a given file type, supported by the dataset.
|
|
8
|
+
* The array contains arrays of strings, each of size >= 1, where the first element of each string
|
|
9
|
+
* is a VitessceConfig view name ('description', 'spatial', 'layerController', etc.)
|
|
10
|
+
*
|
|
11
|
+
* @returns {Array of strings} the intersection of VitessceConfig view names in
|
|
12
|
+
* possibleViews and requiredViews.
|
|
13
|
+
*/
|
|
14
|
+
const filterViews = (hintsConfig, possibleViews) => {
|
|
15
|
+
const requiredViews = Object.keys(hintsConfig.views);
|
|
16
|
+
if (requiredViews.length === 0) {
|
|
17
|
+
return possibleViews;
|
|
18
|
+
}
|
|
19
|
+
const resultViews = [];
|
|
20
|
+
requiredViews.forEach((requiredView) => {
|
|
21
|
+
const match = possibleViews.find(possibleView => possibleView[0] === requiredView);
|
|
22
|
+
if (match)
|
|
23
|
+
resultViews.push(match);
|
|
24
|
+
});
|
|
25
|
+
if (resultViews.length === 0) {
|
|
26
|
+
throw new Error('No views found that are compatible with the supplied dataset URLs and hint.');
|
|
27
|
+
}
|
|
28
|
+
return resultViews;
|
|
29
|
+
};
|
|
3
30
|
class AbstractAutoConfig {
|
|
4
31
|
async composeViewsConfig() {
|
|
5
32
|
throw new Error('The composeViewsConfig() method has not been implemented.');
|
|
@@ -15,12 +42,8 @@ class OmeTiffAutoConfig extends AbstractAutoConfig {
|
|
|
15
42
|
this.fileType = FileType.RASTER_JSON;
|
|
16
43
|
this.fileName = fileUrl.split('/').at(-1);
|
|
17
44
|
}
|
|
18
|
-
async composeViewsConfig() {
|
|
19
|
-
return [
|
|
20
|
-
['description'],
|
|
21
|
-
['spatial'],
|
|
22
|
-
['layerController'],
|
|
23
|
-
];
|
|
45
|
+
async composeViewsConfig(hintsConfig) {
|
|
46
|
+
return filterViews(hintsConfig, [['description'], ['spatial'], ['layerController']]);
|
|
24
47
|
}
|
|
25
48
|
async composeFileConfig() {
|
|
26
49
|
return {
|
|
@@ -49,13 +72,8 @@ class OmeZarrAutoConfig extends AbstractAutoConfig {
|
|
|
49
72
|
this.fileType = FileType.RASTER_OME_ZARR;
|
|
50
73
|
this.fileName = fileUrl.split('/').at(-1);
|
|
51
74
|
}
|
|
52
|
-
async composeViewsConfig() {
|
|
53
|
-
return [
|
|
54
|
-
['description'],
|
|
55
|
-
['spatial'],
|
|
56
|
-
['layerController'],
|
|
57
|
-
['status'],
|
|
58
|
-
];
|
|
75
|
+
async composeViewsConfig(hintsConfig) {
|
|
76
|
+
return filterViews(hintsConfig, [['description'], ['spatial'], ['layerController']]);
|
|
59
77
|
}
|
|
60
78
|
async composeFileConfig() {
|
|
61
79
|
return {
|
|
@@ -99,7 +117,7 @@ class AnndataZarrAutoConfig extends AbstractAutoConfig {
|
|
|
99
117
|
}
|
|
100
118
|
});
|
|
101
119
|
const supportedObsSetsKeys = [
|
|
102
|
-
'cluster', 'subcluster', 'cell_type', 'leiden', 'louvain', 'disease', 'organism', 'self_reported_ethnicity', 'tissue', 'sex',
|
|
120
|
+
'cluster', 'clusters', 'subcluster', 'cell_type', 'celltype', 'leiden', 'louvain', 'disease', 'organism', 'self_reported_ethnicity', 'tissue', 'sex',
|
|
103
121
|
];
|
|
104
122
|
this.metadataSummary.obs.forEach((key) => {
|
|
105
123
|
supportedObsSetsKeys.forEach((supportedKey) => {
|
|
@@ -118,6 +136,18 @@ class AnndataZarrAutoConfig extends AbstractAutoConfig {
|
|
|
118
136
|
}
|
|
119
137
|
});
|
|
120
138
|
});
|
|
139
|
+
// if length of path is 1, storing the value as an array doesn't work
|
|
140
|
+
// es-lint-disable-next-line max-len
|
|
141
|
+
// Example: https://s3.amazonaws.com/vitessce-data/0.0.33/main/human-lymph-node-10x-visium/human_lymph_node_10x_visium.h5ad.zarr
|
|
142
|
+
options.obsSets = options.obsSets?.map((obsSet) => {
|
|
143
|
+
if (obsSet.path.length === 1) {
|
|
144
|
+
return {
|
|
145
|
+
...obsSet,
|
|
146
|
+
path: obsSet.path[0],
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
return obsSet;
|
|
150
|
+
});
|
|
121
151
|
return {
|
|
122
152
|
options,
|
|
123
153
|
fileType: this.fileType,
|
|
@@ -129,35 +159,40 @@ class AnndataZarrAutoConfig extends AbstractAutoConfig {
|
|
|
129
159
|
},
|
|
130
160
|
};
|
|
131
161
|
}
|
|
132
|
-
async composeViewsConfig() {
|
|
162
|
+
async composeViewsConfig(hintsConfig) {
|
|
133
163
|
this.metadataSummary = await this.setMetadataSummary();
|
|
134
|
-
const
|
|
164
|
+
const possibleViews = [];
|
|
135
165
|
const hasCellSetData = this.metadataSummary.obs
|
|
136
|
-
.filter(key => key.toLowerCase().includes('cluster')
|
|
166
|
+
.filter(key => key.toLowerCase().includes('cluster')
|
|
167
|
+
|| key.toLowerCase().includes('cell_type')
|
|
168
|
+
|| key.toLowerCase().includes('celltype'));
|
|
137
169
|
if (hasCellSetData.length > 0) {
|
|
138
|
-
|
|
170
|
+
possibleViews.push(['obsSets']);
|
|
139
171
|
}
|
|
140
172
|
this.metadataSummary.obsm.forEach((key) => {
|
|
141
173
|
if (key.toLowerCase().includes('obsm/x_umap')) {
|
|
142
|
-
|
|
174
|
+
possibleViews.push(['scatterplot', { mapping: 'UMAP' }]);
|
|
143
175
|
}
|
|
144
176
|
if (key.toLowerCase().includes('obsm/x_tsne')) {
|
|
145
|
-
|
|
177
|
+
possibleViews.push(['scatterplot', { mapping: 't-SNE' }]);
|
|
146
178
|
}
|
|
147
179
|
if (key.toLowerCase().includes('obsm/x_pca')) {
|
|
148
|
-
|
|
180
|
+
possibleViews.push(['scatterplot', { mapping: 'PCA' }]);
|
|
149
181
|
}
|
|
150
182
|
if (key.toLowerCase().includes(('obsm/x_segmentations'))) {
|
|
151
|
-
|
|
183
|
+
possibleViews.push(['layerController']);
|
|
152
184
|
}
|
|
153
185
|
if (key.toLowerCase().includes(('obsm/x_spatial'))) {
|
|
154
|
-
|
|
186
|
+
possibleViews.push(['spatial']);
|
|
155
187
|
}
|
|
156
188
|
});
|
|
189
|
+
possibleViews.push(['obsSetSizes']);
|
|
190
|
+
possibleViews.push(['obsSetFeatureValueDistribution']);
|
|
157
191
|
if (this.metadataSummary.X) {
|
|
158
|
-
|
|
159
|
-
|
|
192
|
+
possibleViews.push(['heatmap']);
|
|
193
|
+
possibleViews.push(['featureList']);
|
|
160
194
|
}
|
|
195
|
+
const views = filterViews(hintsConfig, possibleViews);
|
|
161
196
|
return views;
|
|
162
197
|
}
|
|
163
198
|
async setMetadataSummaryWithZmetadata(response) {
|
|
@@ -193,6 +228,7 @@ class AnndataZarrAutoConfig extends AbstractAutoConfig {
|
|
|
193
228
|
'/obsm/X_segmentations/.zarray',
|
|
194
229
|
'/obs/.zattrs',
|
|
195
230
|
'/X/.zarray',
|
|
231
|
+
'/X/data/.zarray', // for https://s3.amazonaws.com/vitessce-data/0.0.33/main/human-lymph-node-10x-visium/human_lymph_node_10x_visium.h5ad.zarr
|
|
196
232
|
];
|
|
197
233
|
const getObsmKey = (url) => {
|
|
198
234
|
// Get the substring "X_pca" from a URL like
|
|
@@ -255,6 +291,8 @@ class AnndataZarrAutoConfig extends AbstractAutoConfig {
|
|
|
255
291
|
return this.setMetadataSummaryWithoutZmetadata();
|
|
256
292
|
}
|
|
257
293
|
throw new Error(`Could not generate config: ${response.statusText}`);
|
|
294
|
+
}).catch((error) => {
|
|
295
|
+
throw new Error(`Could not generate config for URL ${this.fileUrl}: ${error}`);
|
|
258
296
|
});
|
|
259
297
|
}
|
|
260
298
|
}
|
|
@@ -262,23 +300,19 @@ const configClasses = [
|
|
|
262
300
|
{
|
|
263
301
|
extensions: ['.ome.tif', '.ome.tiff', '.ome.tf2', '.ome.tf8'],
|
|
264
302
|
class: OmeTiffAutoConfig,
|
|
303
|
+
name: 'OME-TIFF',
|
|
265
304
|
},
|
|
266
305
|
{
|
|
267
306
|
extensions: ['.h5ad.zarr', '.adata.zarr', '.anndata.zarr'],
|
|
268
307
|
class: AnndataZarrAutoConfig,
|
|
308
|
+
name: 'AnnData-Zarr',
|
|
269
309
|
},
|
|
270
310
|
{
|
|
271
311
|
extensions: ['ome.zarr'],
|
|
272
312
|
class: OmeZarrAutoConfig,
|
|
313
|
+
name: 'OME-Zarr',
|
|
273
314
|
},
|
|
274
315
|
];
|
|
275
|
-
function getFileType(url) {
|
|
276
|
-
const match = configClasses.find(obj => obj.extensions.filter(ext => url.endsWith(ext)).length === 1);
|
|
277
|
-
if (!match) {
|
|
278
|
-
throw new Error(`Could not generate config for URL: ${url}. This file type is not supported.`);
|
|
279
|
-
}
|
|
280
|
-
return match.class;
|
|
281
|
-
}
|
|
282
316
|
function calculateCoordinates(viewsNumb) {
|
|
283
317
|
const rows = Math.ceil(Math.sqrt(viewsNumb));
|
|
284
318
|
const cols = Math.ceil(viewsNumb / rows);
|
|
@@ -290,14 +324,120 @@ function calculateCoordinates(viewsNumb) {
|
|
|
290
324
|
const col = i % cols;
|
|
291
325
|
const x = col * width;
|
|
292
326
|
const y = row * height;
|
|
293
|
-
|
|
327
|
+
// The coordinates have to be integer values:
|
|
328
|
+
coords.push([
|
|
329
|
+
Math.floor(x),
|
|
330
|
+
Math.floor(y),
|
|
331
|
+
// Ensure width/height is at least 1.
|
|
332
|
+
Math.max(1, Math.floor(width)),
|
|
333
|
+
Math.max(1, Math.floor(height)),
|
|
334
|
+
]);
|
|
294
335
|
}
|
|
295
336
|
return coords;
|
|
296
337
|
}
|
|
297
|
-
|
|
338
|
+
const spatialSegmentationLayerValue = {
|
|
339
|
+
radius: 65,
|
|
340
|
+
stroked: true,
|
|
341
|
+
visible: true,
|
|
342
|
+
opacity: 1,
|
|
343
|
+
};
|
|
344
|
+
/**
|
|
345
|
+
* Inserts the spatial coordination space into the VitessceConfig views.
|
|
346
|
+
* @param {Array of VitessceConfigView} of views
|
|
347
|
+
* @param {VitessceConfig} vc instance
|
|
348
|
+
*/
|
|
349
|
+
function insertCoordinationSpaceForSpatial(views, vc) {
|
|
350
|
+
const [spatialSegmentationLayer, spatialImageLayer, spatialZoom, spatialTargetX, spatialTargetY,] = vc.addCoordination(ct.SPATIAL_SEGMENTATION_LAYER, ct.SPATIAL_IMAGE_LAYER, ct.SPATIAL_ZOOM, ct.SPATIAL_TARGET_X, ct.SPATIAL_TARGET_Y);
|
|
351
|
+
// Note: this always assumes the segmentation is polygon-based.
|
|
352
|
+
// In the future, we may want to support both polygon-based and bitmask-based.
|
|
353
|
+
spatialSegmentationLayer.setValue(spatialSegmentationLayerValue);
|
|
354
|
+
// Note: this always assumes the image is RGB.
|
|
355
|
+
// In the future, we may want to support both RGB and multi-channel.
|
|
356
|
+
spatialImageLayer.setValue([
|
|
357
|
+
{
|
|
358
|
+
type: 'raster',
|
|
359
|
+
index: 0,
|
|
360
|
+
colormap: null,
|
|
361
|
+
transparentColor: null,
|
|
362
|
+
opacity: 1,
|
|
363
|
+
domainType: 'Min/Max',
|
|
364
|
+
channels: [
|
|
365
|
+
{
|
|
366
|
+
selection: {
|
|
367
|
+
c: 0,
|
|
368
|
+
},
|
|
369
|
+
color: [
|
|
370
|
+
255,
|
|
371
|
+
0,
|
|
372
|
+
0,
|
|
373
|
+
],
|
|
374
|
+
visible: true,
|
|
375
|
+
slider: [
|
|
376
|
+
0,
|
|
377
|
+
255,
|
|
378
|
+
],
|
|
379
|
+
},
|
|
380
|
+
{
|
|
381
|
+
selection: {
|
|
382
|
+
c: 1,
|
|
383
|
+
},
|
|
384
|
+
color: [
|
|
385
|
+
0,
|
|
386
|
+
255,
|
|
387
|
+
0,
|
|
388
|
+
],
|
|
389
|
+
visible: true,
|
|
390
|
+
slider: [
|
|
391
|
+
0,
|
|
392
|
+
255,
|
|
393
|
+
],
|
|
394
|
+
},
|
|
395
|
+
{
|
|
396
|
+
selection: {
|
|
397
|
+
c: 2,
|
|
398
|
+
},
|
|
399
|
+
color: [
|
|
400
|
+
0,
|
|
401
|
+
0,
|
|
402
|
+
255,
|
|
403
|
+
],
|
|
404
|
+
visible: true,
|
|
405
|
+
slider: [
|
|
406
|
+
0,
|
|
407
|
+
255,
|
|
408
|
+
],
|
|
409
|
+
},
|
|
410
|
+
],
|
|
411
|
+
},
|
|
412
|
+
]);
|
|
413
|
+
views.forEach((view) => {
|
|
414
|
+
if (view.view.component === 'spatial' || view.view.component === 'layerController') {
|
|
415
|
+
view.useCoordination(spatialImageLayer);
|
|
416
|
+
view.useCoordination(spatialSegmentationLayer);
|
|
417
|
+
view.useCoordination(spatialZoom);
|
|
418
|
+
view.useCoordination(spatialTargetX);
|
|
419
|
+
view.useCoordination(spatialTargetY);
|
|
420
|
+
}
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* Returns the type of the file, based on the file extension.
|
|
425
|
+
* @param {string} url of the file.
|
|
426
|
+
* @returns {object} An element from the `configClasses` array, which will be an object with
|
|
427
|
+
* the properties `extensions: string[]`, `class` (an AutoConfig class definition) and
|
|
428
|
+
* `name`: string.
|
|
429
|
+
*/
|
|
430
|
+
function getFileType(url) {
|
|
431
|
+
const match = configClasses.find(obj => obj.extensions.filter(ext => url.endsWith(ext)).length === 1);
|
|
432
|
+
if (!match) {
|
|
433
|
+
throw new Error('One or more of the URLs provided point to unsupported file types.');
|
|
434
|
+
}
|
|
435
|
+
return match;
|
|
436
|
+
}
|
|
437
|
+
async function generateViewDefinition(url, vc, dataset, hintsConfig) {
|
|
298
438
|
let ConfigClassName;
|
|
299
439
|
try {
|
|
300
|
-
ConfigClassName = getFileType(url);
|
|
440
|
+
ConfigClassName = getFileType(url).class;
|
|
301
441
|
}
|
|
302
442
|
catch (err) {
|
|
303
443
|
return Promise.reject(err);
|
|
@@ -307,15 +447,13 @@ async function generateConfig(url, vc) {
|
|
|
307
447
|
let viewsConfig;
|
|
308
448
|
try {
|
|
309
449
|
fileConfig = await configInstance.composeFileConfig();
|
|
310
|
-
viewsConfig = await configInstance.composeViewsConfig();
|
|
450
|
+
viewsConfig = await configInstance.composeViewsConfig(hintsConfig);
|
|
311
451
|
}
|
|
312
452
|
catch (error) {
|
|
313
453
|
console.error(error);
|
|
314
454
|
return Promise.reject(error);
|
|
315
455
|
}
|
|
316
|
-
|
|
317
|
-
.addDataset(configInstance.fileName)
|
|
318
|
-
.addFile(fileConfig);
|
|
456
|
+
dataset.addFile(fileConfig);
|
|
319
457
|
let layerControllerView = false;
|
|
320
458
|
let spatialView = false;
|
|
321
459
|
const views = [];
|
|
@@ -329,7 +467,7 @@ async function generateConfig(url, vc) {
|
|
|
329
467
|
}
|
|
330
468
|
// this piece of code can be removed once these props are added by default to layerController
|
|
331
469
|
// see this issue: https://github.com/vitessce/vitessce/issues/1454
|
|
332
|
-
if (v[0] === 'layerController'
|
|
470
|
+
if (v[0] === 'layerController') {
|
|
333
471
|
view.setProps({
|
|
334
472
|
disable3d: [],
|
|
335
473
|
disableChannelsIfRgbDetected: true,
|
|
@@ -342,36 +480,74 @@ async function generateConfig(url, vc) {
|
|
|
342
480
|
views.push(view);
|
|
343
481
|
});
|
|
344
482
|
if (layerControllerView && spatialView && configInstance instanceof AnndataZarrAutoConfig) {
|
|
345
|
-
const spatialSegmentationLayerValue = {
|
|
346
|
-
opacity: 1,
|
|
347
|
-
radius: 0,
|
|
348
|
-
visible: true,
|
|
349
|
-
stroked: false,
|
|
350
|
-
};
|
|
351
483
|
vc.linkViews([spatialView, layerControllerView], [
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
CoordinationType.SPATIAL_TARGET_Y,
|
|
355
|
-
CoordinationType.SPATIAL_SEGMENTATION_LAYER,
|
|
356
|
-
], [-5.5, 16000, 20000, spatialSegmentationLayerValue]);
|
|
484
|
+
ct.SPATIAL_SEGMENTATION_LAYER,
|
|
485
|
+
], [spatialSegmentationLayerValue]);
|
|
357
486
|
}
|
|
358
487
|
return views;
|
|
359
488
|
}
|
|
360
|
-
|
|
489
|
+
/**
|
|
490
|
+
* Returns the hints that are available for the given file URLs, depending on their types.
|
|
491
|
+
* @param {Array} fileUrls containing urls of files to be loaded into Vitessce
|
|
492
|
+
* @returns the hints available for these file URLs
|
|
493
|
+
*/
|
|
494
|
+
export function getHintOptions(fileUrls) {
|
|
495
|
+
const fileTypes = {};
|
|
496
|
+
fileUrls.forEach((url) => {
|
|
497
|
+
const match = getFileType(url);
|
|
498
|
+
// hints config only has OME-TIFF, since settings are the same for both OME-TIFF and OME-Zarr
|
|
499
|
+
if (match.name === 'OME-Zarr') {
|
|
500
|
+
fileTypes['OME-TIFF'] = true;
|
|
501
|
+
}
|
|
502
|
+
else {
|
|
503
|
+
fileTypes[match.name] = true;
|
|
504
|
+
}
|
|
505
|
+
});
|
|
506
|
+
const datasetType = Object.keys(fileTypes).sort().join(',');
|
|
507
|
+
return HINT_TYPE_TO_FILE_TYPE_MAP?.[datasetType] || [];
|
|
508
|
+
}
|
|
509
|
+
/**
|
|
510
|
+
*
|
|
511
|
+
* @param {Array} fileUrls containing urls of files to be loaded into Vitessce
|
|
512
|
+
* @param {String} the hints config to be used for the dataset. Null by default
|
|
513
|
+
* @returns ViewConfig as JSON
|
|
514
|
+
*/
|
|
515
|
+
export async function generateConfig(fileUrls, hintTitle = null) {
|
|
361
516
|
const vc = new VitessceConfig({
|
|
362
517
|
schemaVersion: '1.0.15',
|
|
363
518
|
name: 'An automatically generated config. Adjust values and add layout components if needed.',
|
|
364
519
|
description: 'Populate with text relevant to this visualisation.',
|
|
365
520
|
});
|
|
366
521
|
const allViews = [];
|
|
522
|
+
const dataset = vc.addDataset('An automatically generated view config for dataset. Adjust values and add layout components if needed.');
|
|
523
|
+
const hintsConfig = !hintTitle ? { views: {} } : HINTS_CONFIG?.[hintTitle];
|
|
524
|
+
if (!hintsConfig) {
|
|
525
|
+
throw new Error(`Hints config not found for the supplied hint: ${hintTitle}.`);
|
|
526
|
+
}
|
|
527
|
+
const useHints = Object.keys(hintsConfig?.views)?.length > 0;
|
|
367
528
|
fileUrls.forEach((url) => {
|
|
368
|
-
allViews.push(
|
|
529
|
+
allViews.push(generateViewDefinition(url, vc, dataset, hintsConfig));
|
|
369
530
|
});
|
|
370
531
|
return Promise.all(allViews).then((views) => {
|
|
371
532
|
const flattenedViews = views.flat();
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
533
|
+
// If coordinationSpaceRequired field is set to true in the HINTS_CONFIG,
|
|
534
|
+
// then insert coordination space.
|
|
535
|
+
// NOTE: the user needs to manually add the coordination values for the image and
|
|
536
|
+
// segmentation layers which will be visualized in the spatial/layer controller views.
|
|
537
|
+
if (hintsConfig?.coordinationSpaceRequired) {
|
|
538
|
+
insertCoordinationSpaceForSpatial(flattenedViews, vc);
|
|
539
|
+
}
|
|
540
|
+
if (!useHints) {
|
|
541
|
+
const coord = calculateCoordinates(flattenedViews.length);
|
|
542
|
+
for (let i = 0; i < flattenedViews.length; i++) {
|
|
543
|
+
flattenedViews[i].setXYWH(...coord[i]);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
else {
|
|
547
|
+
flattenedViews.forEach((vitessceConfigView) => {
|
|
548
|
+
const coordinates = Object.values(hintsConfig.views[vitessceConfigView.view.component]);
|
|
549
|
+
vitessceConfigView.setXYWH(...coordinates);
|
|
550
|
+
});
|
|
375
551
|
}
|
|
376
552
|
return vc.toJSON();
|
|
377
553
|
});
|