@haniffalab/cherita-react 1.0.0 → 1.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.
Files changed (106) hide show
  1. package/LICENSE +1 -1
  2. package/dist/{components → cjs/components}/full-page/FullPage.js +32 -22
  3. package/dist/{components → cjs/components}/full-page/FullPagePseudospatial.js +7 -6
  4. package/dist/{components → cjs/components}/obs-list/ObsItem.js +88 -77
  5. package/dist/{components → cjs/components}/obs-list/ObsList.js +133 -50
  6. package/dist/cjs/components/obs-list/ObsToolbar.js +24 -0
  7. package/dist/{components → cjs/components}/obsm-list/ObsmList.js +8 -5
  8. package/dist/{components → cjs/components}/offcanvas/index.js +24 -20
  9. package/dist/{components → cjs/components}/pseudospatial/Pseudospatial.js +10 -9
  10. package/dist/{components → cjs/components}/pseudospatial/PseudospatialToolbar.js +4 -3
  11. package/dist/{components → cjs/components}/scatterplot/Scatterplot.js +33 -24
  12. package/dist/{components → cjs/components}/scatterplot/SpatialControls.js +43 -42
  13. package/dist/cjs/components/scatterplot/Toolbox.js +62 -0
  14. package/dist/{components → cjs/components}/search-bar/SearchBar.js +24 -7
  15. package/dist/{components → cjs/components}/search-bar/SearchResults.js +13 -17
  16. package/dist/{components → cjs/components}/var-list/VarItem.js +38 -29
  17. package/dist/{components → cjs/components}/var-list/VarList.js +59 -31
  18. package/dist/{components → cjs/components}/var-list/VarListToolbar.js +18 -14
  19. package/dist/{components → cjs/components}/var-list/VarSet.js +24 -20
  20. package/dist/{components → cjs/components}/violin/Violin.js +4 -3
  21. package/dist/{constants → cjs/constants}/constants.js +6 -2
  22. package/dist/{context → cjs/context}/DatasetContext.js +12 -11
  23. package/dist/{context → cjs/context}/FilterContext.js +4 -3
  24. package/dist/{context → cjs/context}/ZarrDataContext.js +4 -3
  25. package/dist/{helpers → cjs/helpers}/color-helper.js +12 -11
  26. package/dist/{helpers → cjs/helpers}/map-helper.js +8 -7
  27. package/dist/{helpers → cjs/helpers}/zarr-helper.js +30 -38
  28. package/dist/{utils → cjs/utils}/Filter.js +1 -1
  29. package/dist/{utils → cjs/utils}/Histogram.js +12 -8
  30. package/dist/{utils → cjs/utils}/ImageViewer.js +6 -5
  31. package/dist/{utils → cjs/utils}/Legend.js +8 -7
  32. package/dist/{utils → cjs/utils}/LoadingIndicators.js +5 -4
  33. package/dist/cjs/utils/Skeleton.js +19 -0
  34. package/dist/{utils → cjs/utils}/VirtualizedList.js +10 -9
  35. package/dist/{utils → cjs/utils}/requests.js +37 -39
  36. package/dist/{utils → cjs/utils}/string.js +9 -4
  37. package/dist/{utils → cjs/utils}/zarrData.js +12 -4
  38. package/dist/css/cherita.css +147 -152
  39. package/dist/css/cherita.css.map +1 -1
  40. package/dist/esm/components/dotplot/Dotplot.js +135 -0
  41. package/dist/esm/components/dotplot/DotplotControls.js +148 -0
  42. package/dist/esm/components/full-page/FullPage.js +143 -0
  43. package/dist/esm/components/full-page/FullPagePseudospatial.js +151 -0
  44. package/dist/esm/components/heatmap/Heatmap.js +105 -0
  45. package/dist/esm/components/heatmap/HeatmapControls.js +23 -0
  46. package/dist/esm/components/matrixplot/Matrixplot.js +107 -0
  47. package/dist/esm/components/matrixplot/MatrixplotControls.js +38 -0
  48. package/dist/esm/components/obs-list/ObsItem.js +484 -0
  49. package/dist/esm/components/obs-list/ObsList.js +338 -0
  50. package/dist/esm/components/obs-list/ObsToolbar.js +17 -0
  51. package/dist/esm/components/obsm-list/ObsmList.js +75 -0
  52. package/dist/esm/components/offcanvas/index.js +67 -0
  53. package/dist/esm/components/pseudospatial/Pseudospatial.js +228 -0
  54. package/dist/esm/components/pseudospatial/PseudospatialToolbar.js +123 -0
  55. package/dist/esm/components/scatterplot/Scatterplot.js +394 -0
  56. package/dist/esm/components/scatterplot/ScatterplotControls.js +71 -0
  57. package/dist/esm/components/scatterplot/SpatialControls.js +140 -0
  58. package/dist/esm/components/scatterplot/Toolbox.js +55 -0
  59. package/dist/esm/components/search-bar/SearchBar.js +90 -0
  60. package/dist/esm/components/search-bar/SearchResults.js +139 -0
  61. package/dist/esm/components/var-list/VarItem.js +254 -0
  62. package/dist/esm/components/var-list/VarList.js +291 -0
  63. package/dist/esm/components/var-list/VarListToolbar.js +87 -0
  64. package/dist/esm/components/var-list/VarSet.js +194 -0
  65. package/dist/esm/components/violin/Violin.js +141 -0
  66. package/dist/esm/components/violin/ViolinControls.js +24 -0
  67. package/dist/esm/constants/colorscales.js +22 -0
  68. package/dist/esm/constants/constants.js +88 -0
  69. package/dist/esm/context/DatasetContext.js +571 -0
  70. package/dist/esm/context/FilterContext.js +48 -0
  71. package/dist/esm/context/ZarrDataContext.js +26 -0
  72. package/dist/esm/helpers/color-helper.js +66 -0
  73. package/dist/esm/helpers/map-helper.js +53 -0
  74. package/dist/esm/helpers/zarr-helper.js +111 -0
  75. package/dist/esm/index.js +22 -0
  76. package/dist/esm/utils/Filter.js +147 -0
  77. package/dist/esm/utils/Histogram.js +44 -0
  78. package/dist/esm/utils/ImageViewer.js +27 -0
  79. package/dist/esm/utils/Legend.js +58 -0
  80. package/dist/esm/utils/LoadingIndicators.js +22 -0
  81. package/dist/esm/utils/Skeleton.js +12 -0
  82. package/dist/esm/utils/VirtualizedList.js +55 -0
  83. package/dist/esm/utils/errors.js +47 -0
  84. package/dist/esm/utils/requests.js +102 -0
  85. package/dist/esm/utils/search.js +39 -0
  86. package/dist/esm/utils/string.js +59 -0
  87. package/dist/esm/utils/zarrData.js +102 -0
  88. package/package.json +19 -7
  89. package/scss/cherita.scss +19 -50
  90. package/scss/components/accordions.scss +32 -0
  91. package/scss/components/layouts.scss +2 -1
  92. package/scss/components/lists.scss +14 -0
  93. package/dist/components/obs-list/ObsToolbar.js +0 -64
  94. package/dist/components/scatterplot/Toolbox.js +0 -31
  95. /package/dist/{components → cjs/components}/dotplot/Dotplot.js +0 -0
  96. /package/dist/{components → cjs/components}/dotplot/DotplotControls.js +0 -0
  97. /package/dist/{components → cjs/components}/heatmap/Heatmap.js +0 -0
  98. /package/dist/{components → cjs/components}/heatmap/HeatmapControls.js +0 -0
  99. /package/dist/{components → cjs/components}/matrixplot/Matrixplot.js +0 -0
  100. /package/dist/{components → cjs/components}/matrixplot/MatrixplotControls.js +0 -0
  101. /package/dist/{components → cjs/components}/scatterplot/ScatterplotControls.js +0 -0
  102. /package/dist/{components → cjs/components}/violin/ViolinControls.js +0 -0
  103. /package/dist/{constants → cjs/constants}/colorscales.js +0 -0
  104. /package/dist/{index.js → cjs/index.js} +0 -0
  105. /package/dist/{utils → cjs/utils}/errors.js +0 -0
  106. /package/dist/{utils → cjs/utils}/search.js +0 -0
@@ -0,0 +1,571 @@
1
+ import React, { useEffect, createContext, useContext, useReducer } from "react";
2
+ import { createSyncStoragePersister } from "@tanstack/query-sync-storage-persister";
3
+ import { QueryClient, QueryCache } from "@tanstack/react-query";
4
+ import { PersistQueryClientProvider } from "@tanstack/react-query-persist-client";
5
+ import _ from "lodash";
6
+ import { FilterProvider } from "./FilterContext";
7
+ import { ZarrDataProvider } from "./ZarrDataContext";
8
+ import { COLOR_ENCODINGS, DOTPLOT_SCALES, LOCAL_STORAGE_KEY, MATRIXPLOT_SCALES, OBS_TYPES, PSEUDOSPATIAL_CATEGORICAL_MODES, VAR_SORT, VAR_SORT_ORDER, VIOLINPLOT_SCALES } from "../constants/constants";
9
+ export const DatasetContext = /*#__PURE__*/createContext(null);
10
+ export const DatasetDispatchContext = /*#__PURE__*/createContext(null);
11
+ const queryClient = new QueryClient({
12
+ defaultOptions: {
13
+ queries: {
14
+ gcTime: 1000 * 60 * 15,
15
+ // garbage collect after 15min of inactive
16
+ staleTime: 1000 * 60 * 60,
17
+ refetchOnMount: false,
18
+ refetchOnReconnect: false,
19
+ refetchOnWindowFocus: false
20
+ }
21
+ },
22
+ queryCache: new QueryCache({
23
+ onError: error => {
24
+ console.error(error);
25
+ }
26
+ })
27
+ });
28
+ // Type of queries to store responses
29
+ const persistKeys = ["obs/cols", "var/names", "obsm/keys", "obs/bins", "obs/distribution"];
30
+ const persistOptions = {
31
+ persister: createSyncStoragePersister({
32
+ storage: window.localStorage
33
+ }),
34
+ dehydrateOptions: {
35
+ shouldDehydrateQuery: _ref => {
36
+ let {
37
+ queryKey,
38
+ state
39
+ } = _ref;
40
+ if (state.status === "success") {
41
+ return persistKeys.includes(queryKey?.[0]);
42
+ }
43
+ return false;
44
+ }
45
+ }
46
+ // @TODO: add maxAge and buster (app and api version numbers as busters)
47
+ };
48
+ const initialDataset = {
49
+ varNamesCol: null,
50
+ selectedObs: null,
51
+ selectedObsm: null,
52
+ selectedVar: null,
53
+ selectedMultiObs: [],
54
+ selectedMultiVar: [],
55
+ colorEncoding: null,
56
+ labelObs: [],
57
+ varSets: [],
58
+ sliceBy: {
59
+ obs: false,
60
+ polygons: false
61
+ },
62
+ controls: {
63
+ colorScale: "Viridis",
64
+ valueRange: [0, 1],
65
+ range: [0, 1],
66
+ colorAxis: {
67
+ dmin: 0,
68
+ dmax: 1,
69
+ cmin: 0,
70
+ cmax: 1
71
+ },
72
+ scale: {
73
+ dotplot: DOTPLOT_SCALES.NONE,
74
+ matrixplot: MATRIXPLOT_SCALES.NONE,
75
+ violinplot: VIOLINPLOT_SCALES.WIDTH
76
+ },
77
+ meanOnlyExpressed: false,
78
+ expressionCutoff: 0.0
79
+ },
80
+ diseaseDatasets: [],
81
+ selectedDisease: null,
82
+ varSort: {
83
+ var: {
84
+ sort: VAR_SORT.NONE,
85
+ sortOrder: VAR_SORT_ORDER.ASC
86
+ },
87
+ disease: {
88
+ sort: VAR_SORT.NONE,
89
+ sortOrder: VAR_SORT_ORDER.ASC
90
+ }
91
+ },
92
+ obsGroups: null,
93
+ imageUrl: null,
94
+ pseudospatial: {
95
+ maskSet: null,
96
+ maskValues: null,
97
+ categoricalMode: PSEUDOSPATIAL_CATEGORICAL_MODES.ACROSS.value
98
+ },
99
+ polygons: {}
100
+ };
101
+ const initializer = initialState => {
102
+ const localObj = (JSON.parse(localStorage.getItem(LOCAL_STORAGE_KEY)) || {})[initialState.url] || {};
103
+ const keys = _.keys(initialState);
104
+ const localValues = _.pick(localObj, keys);
105
+ return _.assign(initialState, localValues);
106
+ };
107
+ export function DatasetProvider(_ref2) {
108
+ let {
109
+ dataset_url,
110
+ children,
111
+ ...dataset_params
112
+ } = _ref2;
113
+ const [dataset, dispatch] = useReducer(datasetReducer, _.assign(initializer({
114
+ url: dataset_url,
115
+ ...initialDataset
116
+ }), dataset_params));
117
+ useEffect(() => {
118
+ try {
119
+ const localObj = JSON.parse(localStorage.getItem(LOCAL_STORAGE_KEY)) || {};
120
+ localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify({
121
+ ...localObj,
122
+ [dataset.url]: dataset
123
+ }));
124
+ } catch (err) {
125
+ if (err.code === 22 || err.code === 1014 || err.name === "QuotaExceededError" || err.name === "NS_ERROR_DOM_QUOTA_REACHED") {
126
+ console.err("Browser storage quota exceeded");
127
+ } else {
128
+ console.err(err);
129
+ }
130
+ }
131
+ }, [dataset]);
132
+ return /*#__PURE__*/React.createElement(DatasetContext.Provider, {
133
+ value: dataset
134
+ }, /*#__PURE__*/React.createElement(DatasetDispatchContext.Provider, {
135
+ value: dispatch
136
+ }, /*#__PURE__*/React.createElement(PersistQueryClientProvider, {
137
+ client: queryClient,
138
+ persistOptions: persistOptions
139
+ }, /*#__PURE__*/React.createElement(FilterProvider, null, /*#__PURE__*/React.createElement(ZarrDataProvider, null, children)))));
140
+ }
141
+ export function useDataset() {
142
+ return useContext(DatasetContext);
143
+ }
144
+ export function useDatasetDispatch() {
145
+ return useContext(DatasetDispatchContext);
146
+ }
147
+ function datasetReducer(dataset, action) {
148
+ switch (action.type) {
149
+ case "select.obs":
150
+ {
151
+ return {
152
+ ...dataset,
153
+ selectedObs: action.obs,
154
+ controls: {
155
+ ...dataset.controls,
156
+ range: action.obs?.type === OBS_TYPES.CATEGORICAL ? [0, 1] : dataset.controls.range
157
+ },
158
+ colorEncoding: dataset.colorEncoding === COLOR_ENCODINGS.OBS && !action.obs ? null : dataset.colorEncoding,
159
+ sliceBy: {
160
+ ...dataset.sliceBy,
161
+ obs: action.obs ? dataset.sliceBy.obs : false
162
+ }
163
+ };
164
+ }
165
+ case "select.obsm":
166
+ {
167
+ return {
168
+ ...dataset,
169
+ selectedObsm: action.obsm
170
+ };
171
+ }
172
+ case "select.var":
173
+ {
174
+ return {
175
+ ...dataset,
176
+ selectedVar: action.var
177
+ };
178
+ }
179
+ case "select.multivar":
180
+ {
181
+ if (dataset.selectedMultiVar.find(i => action.var.isSet ? i.name === action.var.name : i.matrix_index === action.var.matrix_index)) {
182
+ return dataset;
183
+ } else {
184
+ return {
185
+ ...dataset,
186
+ selectedMultiVar: [...dataset.selectedMultiVar, action.var]
187
+ };
188
+ }
189
+ }
190
+ case "deselect.multivar":
191
+ {
192
+ return {
193
+ ...dataset,
194
+ selectedMultiVar: dataset.selectedMultiVar.filter(a => action.var.isSet ? a.name !== action.var.name : a.matrix_index !== action.var.matrix_index)
195
+ };
196
+ }
197
+ case "update.multivar":
198
+ {
199
+ return {
200
+ ...dataset,
201
+ selelectedMultiVar: dataset.selectedMultiVar.map(i => {
202
+ if (i.isSet) {
203
+ return action.vars.find(s => s.name === i.name);
204
+ }
205
+ return i;
206
+ })
207
+ };
208
+ }
209
+ case "set.colorEncoding":
210
+ {
211
+ return {
212
+ ...dataset,
213
+ colorEncoding: action.value
214
+ };
215
+ }
216
+ case "reset.multiVar":
217
+ {
218
+ return {
219
+ ...dataset,
220
+ selectedMultiVar: [],
221
+ colorEncoding: dataset.colorEncoding === COLOR_ENCODINGS.VAR ? null : dataset.colorEncoding
222
+ };
223
+ }
224
+ case "reset.var":
225
+ {
226
+ return {
227
+ ...dataset,
228
+ selectedVar: null,
229
+ colorEncoding: dataset.colorEncoding === COLOR_ENCODINGS.VAR ? null : dataset.colorEncoding
230
+ };
231
+ }
232
+ case "add.varSet":
233
+ {
234
+ return {
235
+ ...dataset,
236
+ varSets: [...dataset.varSets, action.varSet]
237
+ };
238
+ }
239
+ case "remove.varSet":
240
+ {
241
+ return {
242
+ ...dataset,
243
+ varSets: dataset.varSets.filter(a => a.name !== action.varSet.name)
244
+ };
245
+ }
246
+ case "reset.varSets":
247
+ {
248
+ return {
249
+ ...dataset,
250
+ varSets: []
251
+ };
252
+ }
253
+ case "add.varSet.var":
254
+ {
255
+ const varSet = dataset.varSets.find(s => s.name === action.varSet.name);
256
+ if (varSet.vars.find(v => _.isEqual(v, action.var))) {
257
+ return dataset;
258
+ } else {
259
+ return {
260
+ ...dataset,
261
+ varSets: dataset.varSets.map(s => {
262
+ if (s.name === varSet.name) {
263
+ return {
264
+ ...s,
265
+ vars: [...s.vars, action.var]
266
+ };
267
+ } else {
268
+ return s;
269
+ }
270
+ })
271
+ };
272
+ }
273
+ }
274
+ case "remove.varSet.var":
275
+ {
276
+ const varSet = dataset.varSets.find(s => s.name === action.varSet.name);
277
+ return {
278
+ ...dataset,
279
+ varSets: dataset.varSets.map(s => {
280
+ if (s.name === varSet.name) {
281
+ return {
282
+ ...s,
283
+ vars: s.vars.filter(v => v.name !== action.var.name)
284
+ };
285
+ } else {
286
+ return s;
287
+ }
288
+ })
289
+ };
290
+ }
291
+ case "select.disease":
292
+ {
293
+ return {
294
+ ...dataset,
295
+ selectedDisease: {
296
+ id: action.id,
297
+ name: action.name
298
+ }
299
+ };
300
+ }
301
+ case "reset.disease":
302
+ {
303
+ return {
304
+ ...dataset,
305
+ selectedDisease: null
306
+ };
307
+ }
308
+ case "set.controls.colorScale":
309
+ {
310
+ return {
311
+ ...dataset,
312
+ controls: {
313
+ ...dataset.controls,
314
+ colorScale: action.colorScale
315
+ }
316
+ };
317
+ }
318
+ case "set.controls.valueRange":
319
+ {
320
+ return {
321
+ ...dataset,
322
+ controls: {
323
+ ...dataset.controls,
324
+ valueRange: action.valueRange
325
+ }
326
+ };
327
+ }
328
+ case "set.controls.range":
329
+ {
330
+ return {
331
+ ...dataset,
332
+ controls: {
333
+ ...dataset.controls,
334
+ range: action.range
335
+ }
336
+ };
337
+ }
338
+ case "set.controls.colorAxis":
339
+ {
340
+ return {
341
+ ...dataset,
342
+ controls: {
343
+ ...dataset.controls,
344
+ colorAxis: action.colorAxis
345
+ }
346
+ };
347
+ }
348
+ case "set.controls.colorAxis.crange":
349
+ {
350
+ return {
351
+ ...dataset,
352
+ controls: {
353
+ ...dataset.controls,
354
+ colorAxis: {
355
+ ...dataset.controls.colorAxis,
356
+ cmin: action.cmin,
357
+ cmax: action.cmax
358
+ }
359
+ }
360
+ };
361
+ }
362
+ case "set.controls.colorAxis.cmin":
363
+ {
364
+ return {
365
+ ...dataset,
366
+ controls: {
367
+ ...dataset.controls,
368
+ colorAxis: {
369
+ ...dataset.controls.colorAxis,
370
+ cmin: action.cmin
371
+ }
372
+ }
373
+ };
374
+ }
375
+ case "set.controls.colorAxis.cmax":
376
+ {
377
+ return {
378
+ ...dataset,
379
+ controls: {
380
+ ...dataset.controls,
381
+ colorAxis: {
382
+ ...dataset.controls.colorAxis,
383
+ cmax: action.cmax
384
+ }
385
+ }
386
+ };
387
+ }
388
+ case "set.controls.scale":
389
+ {
390
+ return {
391
+ ...dataset,
392
+ controls: {
393
+ ...dataset.controls,
394
+ scale: {
395
+ ...dataset.controls.scale,
396
+ [action.plot]: action.scale
397
+ }
398
+ }
399
+ };
400
+ }
401
+ case "set.controls.meanOnlyExpressed":
402
+ {
403
+ return {
404
+ ...dataset,
405
+ controls: {
406
+ ...dataset.controls,
407
+ meanOnlyExpressed: action.meanOnlyExpressed
408
+ }
409
+ };
410
+ }
411
+ case "set.controls.expressionCutoff":
412
+ {
413
+ return {
414
+ ...dataset,
415
+ controls: {
416
+ ...dataset.controls,
417
+ expressionCutoff: action.expressionCutoff
418
+ }
419
+ };
420
+ }
421
+ case "toggle.slice.obs":
422
+ {
423
+ if (_.isEqual(dataset.selectedObs, action.obs)) {
424
+ return {
425
+ ...dataset,
426
+ sliceBy: {
427
+ ...dataset.sliceBy,
428
+ obs: !dataset.sliceBy.obs
429
+ }
430
+ };
431
+ } else {
432
+ return {
433
+ ...dataset,
434
+ selectedObs: action.obs,
435
+ sliceBy: {
436
+ ...dataset.sliceBy,
437
+ obs: true
438
+ }
439
+ };
440
+ }
441
+ }
442
+ case "toggle.slice.polygons":
443
+ {
444
+ return {
445
+ ...dataset,
446
+ sliceBy: {
447
+ ...dataset.sliceBy,
448
+ polygons: !dataset.sliceBy.polygons
449
+ }
450
+ };
451
+ }
452
+ case "disable.slice.polygons":
453
+ {
454
+ return {
455
+ ...dataset,
456
+ sliceBy: {
457
+ ...dataset.sliceBy,
458
+ polygons: false
459
+ }
460
+ };
461
+ }
462
+ case "add.label.obs":
463
+ {
464
+ if (dataset.labelObs.find(i => _.isEqual(i, action.obs))) {
465
+ return dataset;
466
+ } else {
467
+ return {
468
+ ...dataset,
469
+ labelObs: [...dataset.labelObs, action.obs]
470
+ };
471
+ }
472
+ }
473
+ case "remove.label.obs":
474
+ {
475
+ return {
476
+ ...dataset,
477
+ labelObs: dataset.labelObs.filter(a => a.name !== action.obsName)
478
+ };
479
+ }
480
+ case "reset.label.obs":
481
+ {
482
+ return {
483
+ ...dataset,
484
+ labelObs: []
485
+ };
486
+ }
487
+ case "set.varSort":
488
+ {
489
+ return {
490
+ ...dataset,
491
+ varSort: {
492
+ ...dataset.varSort,
493
+ [action.var]: {
494
+ sort: action.sort,
495
+ sortOrder: action.sortOrder
496
+ }
497
+ }
498
+ };
499
+ }
500
+ case "set.varSort.sort":
501
+ {
502
+ return {
503
+ ...dataset,
504
+ varSort: {
505
+ ...dataset.varSort,
506
+ [action.var]: {
507
+ ...dataset.varSort[action.var],
508
+ sort: action.sort
509
+ }
510
+ }
511
+ };
512
+ }
513
+ case "set.varSort.sortOrder":
514
+ {
515
+ return {
516
+ ...dataset,
517
+ varSort: {
518
+ ...dataset.varSort,
519
+ [action.var]: {
520
+ ...dataset.varSort[action.var],
521
+ sortOrder: action.sortOrder
522
+ }
523
+ }
524
+ };
525
+ }
526
+ case "set.polygons":
527
+ {
528
+ return {
529
+ ...dataset,
530
+ polygons: {
531
+ ...dataset.polygons,
532
+ [action.obsm]: action.polygons
533
+ }
534
+ };
535
+ }
536
+ case "set.pseudospatial.maskSet":
537
+ {
538
+ return {
539
+ ...dataset,
540
+ pseudospatial: {
541
+ ...dataset.pseudospatial,
542
+ maskSet: action.maskSet
543
+ }
544
+ };
545
+ }
546
+ case "set.pseudospatial.maskValues":
547
+ {
548
+ return {
549
+ ...dataset,
550
+ pseudospatial: {
551
+ ...dataset.pseudospatial,
552
+ maskValues: action.maskValues
553
+ }
554
+ };
555
+ }
556
+ case "set.pseudospatial.categoricalMode":
557
+ {
558
+ return {
559
+ ...dataset,
560
+ pseudospatial: {
561
+ ...dataset.pseudospatial,
562
+ categoricalMode: action.categoricalMode
563
+ }
564
+ };
565
+ }
566
+ default:
567
+ {
568
+ throw Error("Unknown action: " + action.type);
569
+ }
570
+ }
571
+ }
@@ -0,0 +1,48 @@
1
+ import React, { useReducer, createContext, useContext } from "react";
2
+ export const FilteredDataContext = /*#__PURE__*/createContext(null);
3
+ export const FilteredDataDispatchContext = /*#__PURE__*/createContext(null);
4
+ const initialFilterData = {
5
+ obsIndices: null,
6
+ valueMin: null,
7
+ valueMax: null,
8
+ slicedLength: null,
9
+ isSliced: false
10
+ };
11
+ export function FilterProvider(_ref) {
12
+ let {
13
+ children
14
+ } = _ref;
15
+ const [filteredData, dispatch] = useReducer(filterReducer, {
16
+ ...initialFilterData
17
+ });
18
+ return /*#__PURE__*/React.createElement(FilteredDataContext.Provider, {
19
+ value: filteredData
20
+ }, /*#__PURE__*/React.createElement(FilteredDataDispatchContext.Provider, {
21
+ value: dispatch
22
+ }, children));
23
+ }
24
+ export function useFilteredData() {
25
+ return useContext(FilteredDataContext);
26
+ }
27
+ export function useFilteredDataDispatch() {
28
+ return useContext(FilteredDataDispatchContext);
29
+ }
30
+ function filterReducer(filteredData, action) {
31
+ switch (action.type) {
32
+ case "set.obs.indices":
33
+ {
34
+ return {
35
+ ...filteredData,
36
+ obsIndices: action.indices,
37
+ valueMin: action.valueMin,
38
+ valueMax: action.valueMax,
39
+ slicedLength: action.slicedLength,
40
+ isSliced: action.isSliced
41
+ };
42
+ }
43
+ default:
44
+ {
45
+ throw Error("Unknown action: " + action.type);
46
+ }
47
+ }
48
+ }
@@ -0,0 +1,26 @@
1
+ import React, { createContext, useContext } from "react";
2
+ import { useFilter } from "../utils/Filter";
3
+ import { useObsData, useObsmData, useXData } from "../utils/zarrData";
4
+ const ZarrDataContext = /*#__PURE__*/createContext(null);
5
+ export function ZarrDataProvider(_ref) {
6
+ let {
7
+ children
8
+ } = _ref;
9
+ const obsmData = useObsmData();
10
+ const obsData = useObsData();
11
+ const xData = useXData();
12
+ const data = {
13
+ obsmData: obsmData,
14
+ obsData: obsData,
15
+ xData: xData,
16
+ isPending: obsmData.isPending || obsData.isPending || xData.isPending,
17
+ serverError: obsmData.serverError || obsData.serverError || xData.serverError
18
+ };
19
+ useFilter(data);
20
+ return /*#__PURE__*/React.createElement(ZarrDataContext.Provider, {
21
+ value: data
22
+ }, children);
23
+ }
24
+ export function useZarrData() {
25
+ return useContext(ZarrDataContext);
26
+ }
@@ -0,0 +1,66 @@
1
+ import { useCallback } from "react";
2
+ import { COLORSCALES } from "../constants/colorscales";
3
+ import { useDataset } from "../context/DatasetContext";
4
+ const GRAY = [214, 212, 212];
5
+ const parseHexColor = color => {
6
+ const r = parseInt(color?.substring(1, 3), 16);
7
+ const g = parseInt(color?.substring(3, 5), 16);
8
+ const b = parseInt(color?.substring(5, 7), 16);
9
+ return [r, g, b];
10
+ };
11
+ const interpolateColor = (color1, color2, factor) => {
12
+ const [r1, g1, b1] = parseHexColor(color1);
13
+ const [r2, g2, b2] = parseHexColor(color2);
14
+ const r = Math.round(r1 + factor * (r2 - r1));
15
+ const g = Math.round(g1 + factor * (g2 - g1));
16
+ const b = Math.round(b1 + factor * (b2 - b1));
17
+ return [r, g, b];
18
+ };
19
+ const computeColor = (colormap, value) => {
20
+ if (!colormap || isNaN(value)) {
21
+ return [0, 0, 0, 255];
22
+ } else if (value <= 0) {
23
+ return parseHexColor(colormap[0]);
24
+ } else if (value >= 1) {
25
+ return parseHexColor(colormap[colormap.length - 1]);
26
+ }
27
+ const index1 = Math.floor(value * (colormap.length - 1));
28
+ const index2 = Math.ceil(value * (colormap.length - 1));
29
+ const factor = value * (colormap.length - 1) % 1;
30
+ return interpolateColor(colormap[index1], colormap[index2], factor);
31
+ };
32
+ export const rgbToHex = color => {
33
+ const [r, g, b] = color || [0, 0, 0, 0];
34
+ return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
35
+ };
36
+ export const useColor = () => {
37
+ const dataset = useDataset();
38
+ const getColor = useCallback(_ref => {
39
+ let {
40
+ value,
41
+ categorical = false,
42
+ grayOut = false,
43
+ grayParams: {
44
+ alpha = 0.75,
45
+ gray = 0.95
46
+ } = {},
47
+ colorEncoding = dataset.colorEncoding,
48
+ colorscale = null
49
+ } = _ref;
50
+ const colormap = colorscale || COLORSCALES[categorical ? "Accent" : dataset.controls.colorScale];
51
+ if (colorEncoding) {
52
+ if (grayOut) {
53
+ // Mix color with gray manually instead of chroma.mix to get better performance with deck.gl
54
+ const rgb = computeColor(colormap, value);
55
+ return [rgb[0] * (1 - gray) + GRAY[0] * gray, rgb[1] * (1 - gray) + GRAY[1] * gray, rgb[2] * (1 - gray) + GRAY[2] * gray, 255 * alpha];
56
+ } else {
57
+ return [...computeColor(colormap, value), 255];
58
+ }
59
+ } else {
60
+ return null;
61
+ }
62
+ }, [dataset.colorEncoding, dataset.controls.colorScale]);
63
+ return {
64
+ getColor
65
+ };
66
+ };