@vitessce/config 3.0.1 → 3.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -93,6 +93,10 @@ const FileType$1 = {
93
93
  ANNDATA_EXPRESSION_MATRIX_ZARR: "anndata-expression-matrix.zarr"
94
94
  };
95
95
  const CoordinationType$1 = {
96
+ // Meta coordination scopes
97
+ META_COORDINATION_SCOPES: "metaCoordinationScopes",
98
+ META_COORDINATION_SCOPES_BY: "metaCoordinationScopesBy",
99
+ // Other coordination scopes
96
100
  DATASET: "dataset",
97
101
  // Entity types
98
102
  OBS_TYPE: "obsType",
@@ -15245,6 +15249,72 @@ class VitessceConfigDataset {
15245
15249
  };
15246
15250
  }
15247
15251
  }
15252
+ function useComplexCoordinationHelper(scopes, coordinationScopes, coordinationScopesBy) {
15253
+ function processLevel(parentType, parentScope, levelType, levelVal) {
15254
+ var _a, _b;
15255
+ if (Array.isArray(levelVal)) {
15256
+ coordinationScopesBy[parentType] = {
15257
+ ...coordinationScopesBy[parentType] || {},
15258
+ [levelType]: {
15259
+ ...((_a = coordinationScopesBy[parentType]) == null ? void 0 : _a[levelType]) || {},
15260
+ [parentScope.cScope]: levelVal.map((childVal) => childVal.scope.cScope)
15261
+ }
15262
+ };
15263
+ levelVal.forEach((childVal) => {
15264
+ if (childVal.children) {
15265
+ Object.entries(childVal.children).forEach(([nextLevelType, nextLevelVal]) => processLevel(
15266
+ levelType,
15267
+ childVal.scope,
15268
+ nextLevelType,
15269
+ nextLevelVal
15270
+ ));
15271
+ }
15272
+ });
15273
+ } else {
15274
+ coordinationScopesBy[parentType] = {
15275
+ ...coordinationScopesBy[parentType] || {},
15276
+ [levelType]: {
15277
+ ...((_b = coordinationScopesBy[parentType]) == null ? void 0 : _b[levelType]) || {},
15278
+ [parentScope.cScope]: levelVal.scope.cScope
15279
+ }
15280
+ };
15281
+ if (levelVal.children) {
15282
+ Object.entries(levelVal.children).forEach(([nextLevelType, nextLevelVal]) => processLevel(
15283
+ levelType,
15284
+ levelVal.scope,
15285
+ nextLevelType,
15286
+ nextLevelVal
15287
+ ));
15288
+ }
15289
+ }
15290
+ }
15291
+ Object.entries(scopes).forEach(([topLevelType, topLevelVal]) => {
15292
+ if (Array.isArray(topLevelVal)) {
15293
+ coordinationScopes[topLevelType] = topLevelVal.map((levelVal) => levelVal.scope.cScope);
15294
+ topLevelVal.forEach((levelVal) => {
15295
+ if (levelVal.children) {
15296
+ Object.entries(levelVal.children).forEach(([nextLevelType, nextLevelVal]) => processLevel(
15297
+ topLevelType,
15298
+ levelVal.scope,
15299
+ nextLevelType,
15300
+ nextLevelVal
15301
+ ));
15302
+ }
15303
+ });
15304
+ } else {
15305
+ coordinationScopes[topLevelType] = topLevelVal.scope.cScope;
15306
+ if (topLevelVal.children) {
15307
+ Object.entries(topLevelVal.children).forEach(([nextLevelType, nextLevelVal]) => processLevel(
15308
+ topLevelType,
15309
+ topLevelVal.scope,
15310
+ nextLevelType,
15311
+ nextLevelVal
15312
+ ));
15313
+ }
15314
+ }
15315
+ });
15316
+ return [coordinationScopes, coordinationScopesBy];
15317
+ }
15248
15318
  class VitessceConfigView {
15249
15319
  /**
15250
15320
  * Construct a new view instance.
@@ -15260,6 +15330,8 @@ class VitessceConfigView {
15260
15330
  this.view = {
15261
15331
  component,
15262
15332
  coordinationScopes,
15333
+ coordinationScopesBy: void 0,
15334
+ // TODO: initialize from parameter?
15263
15335
  x,
15264
15336
  y,
15265
15337
  w,
@@ -15279,6 +15351,41 @@ class VitessceConfigView {
15279
15351
  });
15280
15352
  return this;
15281
15353
  }
15354
+ useComplexCoordination(scopes) {
15355
+ if (!this.view.coordinationScopes) {
15356
+ this.view.coordinationScopes = {};
15357
+ }
15358
+ if (!this.view.coordinationScopesBy) {
15359
+ this.view.coordinationScopesBy = {};
15360
+ }
15361
+ const [nextCoordinationScopes, nextCoordinationScopesBy] = useComplexCoordinationHelper(
15362
+ scopes,
15363
+ this.view.coordinationScopes,
15364
+ this.view.coordinationScopesBy
15365
+ );
15366
+ this.view.coordinationScopes = nextCoordinationScopes;
15367
+ this.view.coordinationScopesBy = nextCoordinationScopesBy;
15368
+ return this;
15369
+ }
15370
+ /**
15371
+ * Attach meta coordination scopes to this view.
15372
+ * @param {VitessceConfigMetaCoordinationScope} metaScope A meta coordination scope instance.
15373
+ * @returns {VitessceConfigView} This, to allow chaining.
15374
+ */
15375
+ useMetaCoordination(metaScope) {
15376
+ if (!this.view.coordinationScopes) {
15377
+ this.view.coordinationScopes = {};
15378
+ }
15379
+ this.view.coordinationScopes[CoordinationType$1.META_COORDINATION_SCOPES] = [
15380
+ ...this.view.coordinationScopes[CoordinationType$1.META_COORDINATION_SCOPES] || [],
15381
+ metaScope.metaScope.cScope
15382
+ ];
15383
+ this.view.coordinationScopes[CoordinationType$1.META_COORDINATION_SCOPES_BY] = [
15384
+ ...this.view.coordinationScopes[CoordinationType$1.META_COORDINATION_SCOPES_BY] || [],
15385
+ metaScope.metaByScope.cScope
15386
+ ];
15387
+ return this;
15388
+ }
15282
15389
  /**
15283
15390
  * Set the x, y, w, h values for this view.
15284
15391
  * @param {number} x The x-coordinate of the view in the layout.
@@ -15330,6 +15437,11 @@ function vconcat(...views) {
15330
15437
  const vcvvc = new VitessceConfigViewVConcat(views);
15331
15438
  return vcvvc;
15332
15439
  }
15440
+ class CoordinationLevel {
15441
+ constructor(value) {
15442
+ this.value = value;
15443
+ }
15444
+ }
15333
15445
  class VitessceConfigCoordinationScope {
15334
15446
  /**
15335
15447
  * Construct a new coordination scope instance.
@@ -15351,6 +15463,63 @@ class VitessceConfigCoordinationScope {
15351
15463
  return this;
15352
15464
  }
15353
15465
  }
15466
+ class VitessceConfigMetaCoordinationScope {
15467
+ /**
15468
+ * Construct a new coordination scope instance.
15469
+ * @param {string} metaScope The name of the coordination scope for metaCoordinationScopes.
15470
+ * @param {string} metaByScope The name of the coordination scope for metaCoordinationScopesBy.
15471
+ */
15472
+ constructor(metaScope, metaByScope) {
15473
+ this.metaScope = new VitessceConfigCoordinationScope(
15474
+ CoordinationType$1.META_COORDINATION_SCOPES,
15475
+ metaScope
15476
+ );
15477
+ this.metaByScope = new VitessceConfigCoordinationScope(
15478
+ CoordinationType$1.META_COORDINATION_SCOPES_BY,
15479
+ metaByScope
15480
+ );
15481
+ }
15482
+ /**
15483
+ * Attach coordination scopes to this meta scope.
15484
+ * @param {...VitessceConfigCoordinationScope} args A variable number of
15485
+ * coordination scope instances.
15486
+ * @returns {VitessceConfigMetaCoordinationScope} This, to allow chaining.
15487
+ */
15488
+ useCoordination(...args) {
15489
+ const cScopes = args;
15490
+ const metaScopesVal = this.metaScope.cValue;
15491
+ cScopes.forEach((cScope) => {
15492
+ metaScopesVal[cScope.cType] = cScope.cScope;
15493
+ });
15494
+ this.metaScope.setValue(metaScopesVal);
15495
+ return this;
15496
+ }
15497
+ useComplexCoordination(scopes) {
15498
+ if (!this.metaScope.cValue) {
15499
+ this.metaScope.setValue({});
15500
+ }
15501
+ if (!this.metaByScope.cValue) {
15502
+ this.metaByScope.setValue({});
15503
+ }
15504
+ const [metaScopesVal, metaByScopesVal] = useComplexCoordinationHelper(
15505
+ scopes,
15506
+ this.metaScope.cValue,
15507
+ this.metaByScope.cValue
15508
+ );
15509
+ this.metaScope.setValue(metaScopesVal);
15510
+ this.metaByScope.setValue(metaByScopesVal);
15511
+ return this;
15512
+ }
15513
+ /**
15514
+ * Set the coordination value of the coordination scope.
15515
+ * @param {any} cValue The value to set.
15516
+ * @returns {VitessceConfigCoordinationScope} This, to allow chaining.
15517
+ */
15518
+ setValue(cValue) {
15519
+ this.cValue = cValue;
15520
+ return this;
15521
+ }
15522
+ }
15354
15523
  class VitessceConfig {
15355
15524
  /**
15356
15525
  * Construct a new view config instance.
@@ -15472,6 +15641,53 @@ class VitessceConfig {
15472
15641
  });
15473
15642
  return result;
15474
15643
  }
15644
+ addMetaCoordination() {
15645
+ const prevMetaScopes = this.config.coordinationSpace[CoordinationType$1.META_COORDINATION_SCOPES] ? Object.keys(this.config.coordinationSpace[CoordinationType$1.META_COORDINATION_SCOPES]) : [];
15646
+ const prevMetaByScopes = this.config.coordinationSpace[CoordinationType$1.META_COORDINATION_SCOPES_BY] ? Object.keys(this.config.coordinationSpace[CoordinationType$1.META_COORDINATION_SCOPES_BY]) : [];
15647
+ const metaContainer = new VitessceConfigMetaCoordinationScope(
15648
+ getNextScope(prevMetaScopes),
15649
+ getNextScope(prevMetaByScopes)
15650
+ );
15651
+ if (!this.config.coordinationSpace[CoordinationType$1.META_COORDINATION_SCOPES]) {
15652
+ this.config.coordinationSpace[CoordinationType$1.META_COORDINATION_SCOPES] = {};
15653
+ }
15654
+ if (!this.config.coordinationSpace[CoordinationType$1.META_COORDINATION_SCOPES_BY]) {
15655
+ this.config.coordinationSpace[CoordinationType$1.META_COORDINATION_SCOPES_BY] = {};
15656
+ }
15657
+ this.config.coordinationSpace[CoordinationType$1.META_COORDINATION_SCOPES][metaContainer.metaScope.cScope] = metaContainer.metaScope;
15658
+ this.config.coordinationSpace[CoordinationType$1.META_COORDINATION_SCOPES_BY][metaContainer.metaByScope.cScope] = metaContainer.metaByScope;
15659
+ return metaContainer;
15660
+ }
15661
+ addComplexCoordination(input) {
15662
+ const processLevel = (level) => {
15663
+ const result = {};
15664
+ Object.entries(level).forEach(([cType, nextLevelOrInitialValue]) => {
15665
+ if (nextLevelOrInitialValue instanceof CoordinationLevel) {
15666
+ const nextLevel = nextLevelOrInitialValue.value;
15667
+ if (Array.isArray(nextLevel)) {
15668
+ result[cType] = nextLevel.map((nextEl) => {
15669
+ const [dummyScope] = this.addCoordination(cType);
15670
+ dummyScope.setValue("__dummy__");
15671
+ return {
15672
+ scope: dummyScope,
15673
+ children: processLevel(nextEl)
15674
+ };
15675
+ });
15676
+ } else {
15677
+ throw new Error("Expected CoordinationLevel.value to be an array.");
15678
+ }
15679
+ } else {
15680
+ const initialValue = nextLevelOrInitialValue;
15681
+ const [scope] = this.addCoordination(cType);
15682
+ scope.setValue(initialValue);
15683
+ result[cType] = { scope };
15684
+ }
15685
+ });
15686
+ return result;
15687
+ };
15688
+ const output = processLevel(input);
15689
+ return output;
15690
+ }
15475
15691
  /**
15476
15692
  * A convenience function for setting up new coordination scopes across a set of views.
15477
15693
  * @param {VitessceConfigView[]} views An array of view objects to link together.
@@ -15584,6 +15800,109 @@ class VitessceConfig {
15584
15800
  return vc;
15585
15801
  }
15586
15802
  }
15803
+ const SINGLE_CELL_WITH_HEATMAP_VIEWS = {
15804
+ obsSets: { x: 4, y: 0, w: 4, h: 4 },
15805
+ obsSetSizes: { x: 8, y: 0, w: 4, h: 4 },
15806
+ scatterplot: { x: 0, y: 0, w: 4, h: 4 },
15807
+ heatmap: { x: 0, y: 4, w: 8, h: 4 },
15808
+ featureList: { x: 8, y: 4, w: 4, h: 4 }
15809
+ };
15810
+ const SINGLE_CELL_WITHOUT_HEATMAP_VIEWS = {
15811
+ obsSets: { x: 10, y: 6, w: 2, h: 6 },
15812
+ obsSetSizes: { x: 8, y: 1, w: 4, h: 6 },
15813
+ scatterplot: { x: 0, y: 0, w: 8, h: 12 },
15814
+ featureList: { x: 8, y: 6, w: 2, h: 6 }
15815
+ };
15816
+ const SPATIAL_TRANSCRIPTOMICS_VIEWS = {
15817
+ scatterplot: { x: 0, y: 0, w: 3, h: 4 },
15818
+ spatial: { x: 3, y: 0, w: 5, h: 4 },
15819
+ obsSets: { x: 8, y: 0, w: 4, h: 2 },
15820
+ featureList: { x: 8, y: 0, w: 4, h: 2 },
15821
+ heatmap: { x: 0, y: 4, w: 6, h: 4 },
15822
+ obsSetFeatureValueDistribution: { x: 6, y: 4, w: 6, h: 4 }
15823
+ };
15824
+ const SPATIAL_TRANSCRIPTOMICS_WITH_HSITOLOGY_VIEWS = {
15825
+ spatial: { x: 0, y: 0, w: 6, h: 6 },
15826
+ heatmap: { x: 0, y: 6, w: 8, h: 6 },
15827
+ layerController: { x: 8, y: 6, w: 4, h: 6 },
15828
+ obsSets: { x: 9, y: 0, w: 3, h: 6 },
15829
+ featureList: { x: 6, y: 0, w: 3, h: 6 }
15830
+ };
15831
+ const IMAGE_VIEWS = {
15832
+ spatial: { x: 0, y: 0, w: 8, h: 12 },
15833
+ layerController: { x: 8, y: 0, w: 4, h: 7 },
15834
+ description: { x: 8, y: 9, w: 4, h: 5 }
15835
+ };
15836
+ const NO_HINTS_CONFIG = {
15837
+ views: {},
15838
+ coordinationValues: {}
15839
+ };
15840
+ const HINTS_CONFIG = {
15841
+ "No hints are available. Generate config with no hints.": NO_HINTS_CONFIG,
15842
+ Basic: NO_HINTS_CONFIG,
15843
+ "Transcriptomics / scRNA-seq (with heatmap)": {
15844
+ views: SINGLE_CELL_WITH_HEATMAP_VIEWS
15845
+ },
15846
+ "Transcriptomics / scRNA-seq (without heatmap)": {
15847
+ views: SINGLE_CELL_WITHOUT_HEATMAP_VIEWS
15848
+ },
15849
+ "Spatial transcriptomics (with polygon cell segmentations)": {
15850
+ views: SPATIAL_TRANSCRIPTOMICS_VIEWS
15851
+ },
15852
+ "Chromatin accessibility / scATAC-seq (with heatmap)": {
15853
+ views: SINGLE_CELL_WITH_HEATMAP_VIEWS,
15854
+ coordinationValues: {
15855
+ featureType: "peak"
15856
+ }
15857
+ },
15858
+ "Chromatin accessibility / scATAC-seq (without heatmap)": {
15859
+ views: SINGLE_CELL_WITHOUT_HEATMAP_VIEWS,
15860
+ coordinationValues: {
15861
+ featureType: "peak"
15862
+ }
15863
+ },
15864
+ "Spatial transcriptomics (with histology image and polygon cell segmentations)": {
15865
+ views: SPATIAL_TRANSCRIPTOMICS_WITH_HSITOLOGY_VIEWS,
15866
+ coordinationSpaceRequired: true
15867
+ },
15868
+ Image: {
15869
+ views: IMAGE_VIEWS
15870
+ }
15871
+ };
15872
+ const HINT_TYPE_TO_FILE_TYPE_MAP = {
15873
+ "AnnData-Zarr": [
15874
+ "Basic",
15875
+ "Transcriptomics / scRNA-seq (with heatmap)",
15876
+ "Transcriptomics / scRNA-seq (without heatmap)",
15877
+ "Spatial transcriptomics (with polygon cell segmentations)",
15878
+ "Chromatin accessibility / scATAC-seq (with heatmap)",
15879
+ "Chromatin accessibility / scATAC-seq (without heatmap)"
15880
+ ],
15881
+ "OME-TIFF": [
15882
+ "Basic",
15883
+ "Image"
15884
+ ],
15885
+ "AnnData-Zarr,OME-TIFF": [
15886
+ "Basic",
15887
+ "Spatial transcriptomics (with histology image and polygon cell segmentations)"
15888
+ ]
15889
+ };
15890
+ const filterViews = (hintsConfig, possibleViews) => {
15891
+ const requiredViews = Object.keys(hintsConfig.views);
15892
+ if (requiredViews.length === 0) {
15893
+ return possibleViews;
15894
+ }
15895
+ const resultViews = [];
15896
+ requiredViews.forEach((requiredView) => {
15897
+ const match = possibleViews.find((possibleView) => possibleView[0] === requiredView);
15898
+ if (match)
15899
+ resultViews.push(match);
15900
+ });
15901
+ if (resultViews.length === 0) {
15902
+ throw new Error("No views found that are compatible with the supplied dataset URLs and hint.");
15903
+ }
15904
+ return resultViews;
15905
+ };
15587
15906
  class AbstractAutoConfig {
15588
15907
  async composeViewsConfig() {
15589
15908
  throw new Error("The composeViewsConfig() method has not been implemented.");
@@ -15599,12 +15918,11 @@ class OmeTiffAutoConfig extends AbstractAutoConfig {
15599
15918
  this.fileType = FileType$1.RASTER_JSON;
15600
15919
  this.fileName = fileUrl.split("/").at(-1);
15601
15920
  }
15602
- async composeViewsConfig() {
15603
- return [
15604
- ["description"],
15605
- ["spatial"],
15606
- ["layerController"]
15607
- ];
15921
+ async composeViewsConfig(hintsConfig) {
15922
+ return filterViews(
15923
+ hintsConfig,
15924
+ [["description"], ["spatial"], ["layerController"]]
15925
+ );
15608
15926
  }
15609
15927
  async composeFileConfig() {
15610
15928
  return {
@@ -15633,13 +15951,11 @@ class OmeZarrAutoConfig extends AbstractAutoConfig {
15633
15951
  this.fileType = FileType$1.RASTER_OME_ZARR;
15634
15952
  this.fileName = fileUrl.split("/").at(-1);
15635
15953
  }
15636
- async composeViewsConfig() {
15637
- return [
15638
- ["description"],
15639
- ["spatial"],
15640
- ["layerController"],
15641
- ["status"]
15642
- ];
15954
+ async composeViewsConfig(hintsConfig) {
15955
+ return filterViews(
15956
+ hintsConfig,
15957
+ [["description"], ["spatial"], ["layerController"]]
15958
+ );
15643
15959
  }
15644
15960
  async composeFileConfig() {
15645
15961
  return {
@@ -15658,6 +15974,7 @@ class AnndataZarrAutoConfig extends AbstractAutoConfig {
15658
15974
  this.metadataSummary = {};
15659
15975
  }
15660
15976
  async composeFileConfig() {
15977
+ var _a;
15661
15978
  this.metadataSummary = await this.setMetadataSummary();
15662
15979
  const options = {
15663
15980
  obsEmbedding: [],
@@ -15684,8 +16001,10 @@ class AnndataZarrAutoConfig extends AbstractAutoConfig {
15684
16001
  });
15685
16002
  const supportedObsSetsKeys = [
15686
16003
  "cluster",
16004
+ "clusters",
15687
16005
  "subcluster",
15688
16006
  "cell_type",
16007
+ "celltype",
15689
16008
  "leiden",
15690
16009
  "louvain",
15691
16010
  "disease",
@@ -15710,6 +16029,15 @@ class AnndataZarrAutoConfig extends AbstractAutoConfig {
15710
16029
  }
15711
16030
  });
15712
16031
  });
16032
+ options.obsSets = (_a = options.obsSets) == null ? void 0 : _a.map((obsSet) => {
16033
+ if (obsSet.path.length === 1) {
16034
+ return {
16035
+ ...obsSet,
16036
+ path: obsSet.path[0]
16037
+ };
16038
+ }
16039
+ return obsSet;
16040
+ });
15713
16041
  return {
15714
16042
  options,
15715
16043
  fileType: this.fileType,
@@ -15721,34 +16049,37 @@ class AnndataZarrAutoConfig extends AbstractAutoConfig {
15721
16049
  }
15722
16050
  };
15723
16051
  }
15724
- async composeViewsConfig() {
16052
+ async composeViewsConfig(hintsConfig) {
15725
16053
  this.metadataSummary = await this.setMetadataSummary();
15726
- const views = [];
15727
- const hasCellSetData = this.metadataSummary.obs.filter((key) => key.toLowerCase().includes("cluster") || key.toLowerCase().includes("cell_type"));
16054
+ const possibleViews = [];
16055
+ const hasCellSetData = this.metadataSummary.obs.filter((key) => key.toLowerCase().includes("cluster") || key.toLowerCase().includes("cell_type") || key.toLowerCase().includes("celltype"));
15728
16056
  if (hasCellSetData.length > 0) {
15729
- views.push(["obsSets"]);
16057
+ possibleViews.push(["obsSets"]);
15730
16058
  }
15731
16059
  this.metadataSummary.obsm.forEach((key) => {
15732
16060
  if (key.toLowerCase().includes("obsm/x_umap")) {
15733
- views.push(["scatterplot", { mapping: "UMAP" }]);
16061
+ possibleViews.push(["scatterplot", { mapping: "UMAP" }]);
15734
16062
  }
15735
16063
  if (key.toLowerCase().includes("obsm/x_tsne")) {
15736
- views.push(["scatterplot", { mapping: "t-SNE" }]);
16064
+ possibleViews.push(["scatterplot", { mapping: "t-SNE" }]);
15737
16065
  }
15738
16066
  if (key.toLowerCase().includes("obsm/x_pca")) {
15739
- views.push(["scatterplot", { mapping: "PCA" }]);
16067
+ possibleViews.push(["scatterplot", { mapping: "PCA" }]);
15740
16068
  }
15741
16069
  if (key.toLowerCase().includes("obsm/x_segmentations")) {
15742
- views.push(["layerController"]);
16070
+ possibleViews.push(["layerController"]);
15743
16071
  }
15744
16072
  if (key.toLowerCase().includes("obsm/x_spatial")) {
15745
- views.push(["spatial"]);
16073
+ possibleViews.push(["spatial"]);
15746
16074
  }
15747
16075
  });
16076
+ possibleViews.push(["obsSetSizes"]);
16077
+ possibleViews.push(["obsSetFeatureValueDistribution"]);
15748
16078
  if (this.metadataSummary.X) {
15749
- views.push(["heatmap"]);
15750
- views.push(["featureList"]);
16079
+ possibleViews.push(["heatmap"]);
16080
+ possibleViews.push(["featureList"]);
15751
16081
  }
16082
+ const views = filterViews(hintsConfig, possibleViews);
15752
16083
  return views;
15753
16084
  }
15754
16085
  async setMetadataSummaryWithZmetadata(response) {
@@ -15780,7 +16111,9 @@ class AnndataZarrAutoConfig extends AbstractAutoConfig {
15780
16111
  "/obsm/X_spatial/.zarray",
15781
16112
  "/obsm/X_segmentations/.zarray",
15782
16113
  "/obs/.zattrs",
15783
- "/X/.zarray"
16114
+ "/X/.zarray",
16115
+ "/X/data/.zarray"
16116
+ // for https://s3.amazonaws.com/vitessce-data/0.0.33/main/human-lymph-node-10x-visium/human_lymph_node_10x_visium.h5ad.zarr
15784
16117
  ];
15785
16118
  const getObsmKey = (url) => {
15786
16119
  const obsmKeyStartIndex = `${this.fileUrl}/`.length;
@@ -15836,32 +16169,28 @@ class AnndataZarrAutoConfig extends AbstractAutoConfig {
15836
16169
  return this.setMetadataSummaryWithoutZmetadata();
15837
16170
  }
15838
16171
  throw new Error(`Could not generate config: ${response.statusText}`);
16172
+ }).catch((error) => {
16173
+ throw new Error(`Could not generate config for URL ${this.fileUrl}: ${error}`);
15839
16174
  });
15840
16175
  }
15841
16176
  }
15842
16177
  const configClasses = [
15843
16178
  {
15844
16179
  extensions: [".ome.tif", ".ome.tiff", ".ome.tf2", ".ome.tf8"],
15845
- class: OmeTiffAutoConfig
16180
+ class: OmeTiffAutoConfig,
16181
+ name: "OME-TIFF"
15846
16182
  },
15847
16183
  {
15848
16184
  extensions: [".h5ad.zarr", ".adata.zarr", ".anndata.zarr"],
15849
- class: AnndataZarrAutoConfig
16185
+ class: AnndataZarrAutoConfig,
16186
+ name: "AnnData-Zarr"
15850
16187
  },
15851
16188
  {
15852
16189
  extensions: ["ome.zarr"],
15853
- class: OmeZarrAutoConfig
16190
+ class: OmeZarrAutoConfig,
16191
+ name: "OME-Zarr"
15854
16192
  }
15855
16193
  ];
15856
- function getFileType(url) {
15857
- const match = configClasses.find((obj) => obj.extensions.filter(
15858
- (ext) => url.endsWith(ext)
15859
- ).length === 1);
15860
- if (!match) {
15861
- throw new Error(`Could not generate config for URL: ${url}. This file type is not supported.`);
15862
- }
15863
- return match.class;
15864
- }
15865
16194
  function calculateCoordinates(viewsNumb) {
15866
16195
  const rows = Math.ceil(Math.sqrt(viewsNumb));
15867
16196
  const cols = Math.ceil(viewsNumb / rows);
@@ -15873,14 +16202,117 @@ function calculateCoordinates(viewsNumb) {
15873
16202
  const col = i % cols;
15874
16203
  const x = col * width;
15875
16204
  const y = row * height;
15876
- coords.push([x, y, width, height]);
16205
+ coords.push([
16206
+ Math.floor(x),
16207
+ Math.floor(y),
16208
+ // Ensure width/height is at least 1.
16209
+ Math.max(1, Math.floor(width)),
16210
+ Math.max(1, Math.floor(height))
16211
+ ]);
15877
16212
  }
15878
16213
  return coords;
15879
16214
  }
15880
- async function generateConfig(url, vc) {
16215
+ const spatialSegmentationLayerValue = {
16216
+ radius: 65,
16217
+ stroked: true,
16218
+ visible: true,
16219
+ opacity: 1
16220
+ };
16221
+ function insertCoordinationSpaceForSpatial(views, vc) {
16222
+ const [
16223
+ spatialSegmentationLayer,
16224
+ spatialImageLayer,
16225
+ spatialZoom,
16226
+ spatialTargetX,
16227
+ spatialTargetY
16228
+ ] = vc.addCoordination(
16229
+ CoordinationType$1.SPATIAL_SEGMENTATION_LAYER,
16230
+ CoordinationType$1.SPATIAL_IMAGE_LAYER,
16231
+ CoordinationType$1.SPATIAL_ZOOM,
16232
+ CoordinationType$1.SPATIAL_TARGET_X,
16233
+ CoordinationType$1.SPATIAL_TARGET_Y
16234
+ );
16235
+ spatialSegmentationLayer.setValue(spatialSegmentationLayerValue);
16236
+ spatialImageLayer.setValue([
16237
+ {
16238
+ type: "raster",
16239
+ index: 0,
16240
+ colormap: null,
16241
+ transparentColor: null,
16242
+ opacity: 1,
16243
+ domainType: "Min/Max",
16244
+ channels: [
16245
+ {
16246
+ selection: {
16247
+ c: 0
16248
+ },
16249
+ color: [
16250
+ 255,
16251
+ 0,
16252
+ 0
16253
+ ],
16254
+ visible: true,
16255
+ slider: [
16256
+ 0,
16257
+ 255
16258
+ ]
16259
+ },
16260
+ {
16261
+ selection: {
16262
+ c: 1
16263
+ },
16264
+ color: [
16265
+ 0,
16266
+ 255,
16267
+ 0
16268
+ ],
16269
+ visible: true,
16270
+ slider: [
16271
+ 0,
16272
+ 255
16273
+ ]
16274
+ },
16275
+ {
16276
+ selection: {
16277
+ c: 2
16278
+ },
16279
+ color: [
16280
+ 0,
16281
+ 0,
16282
+ 255
16283
+ ],
16284
+ visible: true,
16285
+ slider: [
16286
+ 0,
16287
+ 255
16288
+ ]
16289
+ }
16290
+ ]
16291
+ }
16292
+ ]);
16293
+ views.forEach((view) => {
16294
+ if (view.view.component === "spatial" || view.view.component === "layerController") {
16295
+ view.useCoordination(spatialImageLayer);
16296
+ view.useCoordination(spatialSegmentationLayer);
16297
+ view.useCoordination(spatialZoom);
16298
+ view.useCoordination(spatialTargetX);
16299
+ view.useCoordination(spatialTargetY);
16300
+ }
16301
+ });
16302
+ }
16303
+ function getFileType(url) {
16304
+ const match = configClasses.find((obj) => obj.extensions.filter(
16305
+ (ext) => url.endsWith(ext)
16306
+ ).length === 1);
16307
+ if (!match) {
16308
+ throw new Error("One or more of the URLs provided point to unsupported file types.");
16309
+ }
16310
+ return match;
16311
+ }
16312
+ async function generateViewDefinition(url, vc, dataset, hintsConfig) {
15881
16313
  let ConfigClassName;
15882
16314
  try {
15883
- ConfigClassName = getFileType(url);
16315
+ ConfigClassName = getFileType(url).class;
15884
16316
  } catch (err) {
15885
16317
  return Promise.reject(err);
15886
16318
  }
@@ -15889,12 +16321,12 @@ async function generateConfig(url, vc) {
15889
16321
  let viewsConfig;
15890
16322
  try {
15891
16323
  fileConfig = await configInstance.composeFileConfig();
15892
- viewsConfig = await configInstance.composeViewsConfig();
16324
+ viewsConfig = await configInstance.composeViewsConfig(hintsConfig);
15893
16325
  } catch (error) {
15894
16326
  console.error(error);
15895
16327
  return Promise.reject(error);
15896
16328
  }
15897
- const dataset = vc.addDataset(configInstance.fileName).addFile(fileConfig);
16329
+ dataset.addFile(fileConfig);
15898
16330
  let layerControllerView = false;
15899
16331
  let spatialView = false;
15900
16332
  const views = [];
@@ -15906,7 +16338,7 @@ async function generateConfig(url, vc) {
15906
16338
  if (v[0] === "spatial") {
15907
16339
  spatialView = view;
15908
16340
  }
15909
- if (v[0] === "layerController" && configInstance instanceof OmeTiffAutoConfig) {
16341
+ if (v[0] === "layerController") {
15910
16342
  view.setProps({
15911
16343
  disable3d: [],
15912
16344
  disableChannelsIfRgbDetected: true
@@ -15918,47 +16350,71 @@ async function generateConfig(url, vc) {
15918
16350
  views.push(view);
15919
16351
  });
15920
16352
  if (layerControllerView && spatialView && configInstance instanceof AnndataZarrAutoConfig) {
15921
- const spatialSegmentationLayerValue = {
15922
- opacity: 1,
15923
- radius: 0,
15924
- visible: true,
15925
- stroked: false
15926
- };
15927
16353
  vc.linkViews(
15928
16354
  [spatialView, layerControllerView],
15929
16355
  [
15930
- CoordinationType$1.SPATIAL_ZOOM,
15931
- CoordinationType$1.SPATIAL_TARGET_X,
15932
- CoordinationType$1.SPATIAL_TARGET_Y,
15933
16356
  CoordinationType$1.SPATIAL_SEGMENTATION_LAYER
15934
16357
  ],
15935
- [-5.5, 16e3, 2e4, spatialSegmentationLayerValue]
16358
+ [spatialSegmentationLayerValue]
15936
16359
  );
15937
16360
  }
15938
16361
  return views;
15939
16362
  }
15940
- async function generateConfigs(fileUrls) {
16363
+ function getHintOptions(fileUrls) {
16364
+ const fileTypes = {};
16365
+ fileUrls.forEach((url) => {
16366
+ const match = getFileType(url);
16367
+ if (match.name === "OME-Zarr") {
16368
+ fileTypes["OME-TIFF"] = true;
16369
+ } else {
16370
+ fileTypes[match.name] = true;
16371
+ }
16372
+ });
16373
+ const datasetType = Object.keys(fileTypes).sort().join(",");
16374
+ return (HINT_TYPE_TO_FILE_TYPE_MAP == null ? void 0 : HINT_TYPE_TO_FILE_TYPE_MAP[datasetType]) || [];
16375
+ }
16376
+ async function generateConfig(fileUrls, hintTitle = null) {
16377
+ var _a;
15941
16378
  const vc = new VitessceConfig({
15942
16379
  schemaVersion: "1.0.15",
15943
16380
  name: "An automatically generated config. Adjust values and add layout components if needed.",
15944
16381
  description: "Populate with text relevant to this visualisation."
15945
16382
  });
15946
16383
  const allViews = [];
16384
+ const dataset = vc.addDataset("An automatically generated view config for dataset. Adjust values and add layout components if needed.");
16385
+ const hintsConfig = !hintTitle ? { views: {} } : HINTS_CONFIG == null ? void 0 : HINTS_CONFIG[hintTitle];
16386
+ if (!hintsConfig) {
16387
+ throw new Error(`Hints config not found for the supplied hint: ${hintTitle}.`);
16388
+ }
16389
+ const useHints = ((_a = Object.keys(hintsConfig == null ? void 0 : hintsConfig.views)) == null ? void 0 : _a.length) > 0;
15947
16390
  fileUrls.forEach((url) => {
15948
- allViews.push(generateConfig(url, vc));
16391
+ allViews.push(generateViewDefinition(url, vc, dataset, hintsConfig));
15949
16392
  });
15950
16393
  return Promise.all(allViews).then((views) => {
15951
16394
  const flattenedViews = views.flat();
15952
- const coord = calculateCoordinates(flattenedViews.length);
15953
- for (let i = 0; i < flattenedViews.length; i++) {
15954
- flattenedViews[i].setXYWH(...coord[i]);
16395
+ if (hintsConfig == null ? void 0 : hintsConfig.coordinationSpaceRequired) {
16396
+ insertCoordinationSpaceForSpatial(flattenedViews, vc);
16397
+ }
16398
+ if (!useHints) {
16399
+ const coord = calculateCoordinates(flattenedViews.length);
16400
+ for (let i = 0; i < flattenedViews.length; i++) {
16401
+ flattenedViews[i].setXYWH(...coord[i]);
16402
+ }
16403
+ } else {
16404
+ flattenedViews.forEach((vitessceConfigView) => {
16405
+ const coordinates = Object.values(hintsConfig.views[vitessceConfigView.view.component]);
16406
+ vitessceConfigView.setXYWH(...coordinates);
16407
+ });
15955
16408
  }
15956
16409
  return vc.toJSON();
15957
16410
  });
15958
16411
  }
15959
16412
  export {
16413
+ HINTS_CONFIG,
16414
+ HINT_TYPE_TO_FILE_TYPE_MAP,
15960
16415
  VitessceConfig,
15961
- generateConfigs,
16416
+ generateConfig,
16417
+ getHintOptions,
15962
16418
  hconcat,
15963
16419
  vconcat
15964
16420
  };