@haniffalab/cherita-react 1.4.1-dev.2025-06-30.66ec83a3 → 1.4.1-dev.2025-08-13.8f63c242

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 (31) hide show
  1. package/dist/cjs/components/dotplot/Dotplot.js +12 -16
  2. package/dist/cjs/components/heatmap/Heatmap.js +11 -16
  3. package/dist/cjs/components/matrixplot/Matrixplot.js +11 -16
  4. package/dist/cjs/components/obs-list/ObsItem.js +14 -14
  5. package/dist/cjs/components/obs-list/ObsList.js +24 -23
  6. package/dist/cjs/components/pseudospatial/Pseudospatial.js +25 -31
  7. package/dist/cjs/components/scatterplot/Scatterplot.js +14 -23
  8. package/dist/cjs/components/scatterplot/ScatterplotControls.js +9 -3
  9. package/dist/cjs/components/var-list/VarList.js +16 -14
  10. package/dist/cjs/components/violin/Violin.js +21 -25
  11. package/dist/cjs/context/DatasetContext.js +4 -4
  12. package/dist/cjs/context/SettingsContext.js +176 -41
  13. package/dist/cjs/utils/Filter.js +15 -10
  14. package/dist/cjs/utils/Resolver.js +188 -0
  15. package/dist/cjs/utils/zarrData.js +16 -17
  16. package/dist/esm/components/dotplot/Dotplot.js +12 -16
  17. package/dist/esm/components/heatmap/Heatmap.js +11 -16
  18. package/dist/esm/components/matrixplot/Matrixplot.js +11 -16
  19. package/dist/esm/components/obs-list/ObsItem.js +14 -14
  20. package/dist/esm/components/obs-list/ObsList.js +24 -23
  21. package/dist/esm/components/pseudospatial/Pseudospatial.js +25 -31
  22. package/dist/esm/components/scatterplot/Scatterplot.js +14 -23
  23. package/dist/esm/components/scatterplot/ScatterplotControls.js +9 -3
  24. package/dist/esm/components/var-list/VarList.js +16 -14
  25. package/dist/esm/components/violin/Violin.js +21 -25
  26. package/dist/esm/context/DatasetContext.js +4 -4
  27. package/dist/esm/context/SettingsContext.js +177 -42
  28. package/dist/esm/utils/Filter.js +15 -10
  29. package/dist/esm/utils/Resolver.js +176 -0
  30. package/dist/esm/utils/zarrData.js +16 -17
  31. package/package.json +2 -2
@@ -6,25 +6,26 @@ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol"
6
6
  function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
7
7
  function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; }
8
8
  function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
9
- import React, { createContext, useContext, useEffect, useReducer } from "react";
9
+ import React, { createContext, useContext, useEffect, useReducer, useRef } from "react";
10
10
  import _ from "lodash";
11
11
  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";
12
+ import { useResolver } from "../utils/Resolver";
12
13
  export const SettingsContext = /*#__PURE__*/createContext(null);
13
14
  export const SettingsDispatchContext = /*#__PURE__*/createContext(null);
14
-
15
- // @TODO: consider splitting constant values and dataset-resolved values
16
- // e.g. store only obs name in selectedObs, and resolved obs data (counts, values, etc.) elsewhere
17
- // e.g. store only var name in selectedVar, and resolved var data (index, matrix_index) elsewhere
18
- // would simplify passing and validating defaultSettings and localSettings
19
15
  const initialSettings = {
20
16
  selectedObs: null,
17
+ // { name: "obs_name", omit: ["obs_item"], bins: {} }
21
18
  selectedVar: null,
19
+ // { name: "var_name", isSet: false } or { name: "var_set_name", isSet: true, vars: [{ name: "var1" }, { name: "var2" }] }
22
20
  selectedObsm: null,
23
- selectedMultiObs: [],
21
+ // "obsm_name" (e.g. "X_umap")
24
22
  selectedMultiVar: [],
25
- colorEncoding: null,
23
+ // [{ name: "var_name", isSet: false }, { name: "var_set_name", isSet: true, vars: [{ name: "var1" }, { name: "var2" }] }]
26
24
  labelObs: [],
25
+ // [ "obs_name1", "obs_name2" ]
27
26
  vars: [],
27
+ // [{ name: "var_name", isSet: false }, { name: "var_set_name", isSet: true, vars: [{ name: "var1" }, { name: "var2" }] }]
28
+ colorEncoding: null,
28
29
  sliceBy: {
29
30
  obs: false,
30
31
  polygons: false
@@ -32,8 +33,8 @@ const initialSettings = {
32
33
  polygons: {},
33
34
  controls: {
34
35
  colorScale: "Viridis",
35
- valueRange: [0, 1],
36
36
  range: [0, 1],
37
+ // normalized
37
38
  colorAxis: {
38
39
  dmin: 0,
39
40
  dmax: 1,
@@ -62,11 +63,19 @@ const initialSettings = {
62
63
  maskSet: null,
63
64
  maskValues: null,
64
65
  categoricalMode: PSEUDOSPATIAL_CATEGORICAL_MODES.ACROSS.value
66
+ },
67
+ // dataset resolved values
68
+ data: {
69
+ // store resolved obs and vars from selectedObs, selectedVar, selectedMultiVar, vars, labelObs
70
+ // keys to be removed when not in any selection
71
+ obs: {},
72
+ vars: {}
65
73
  }
66
74
  };
67
75
 
68
76
  // validate on initialization and reducer
69
77
  const validateSettings = settings => {
78
+ var _settings$selectedObs;
70
79
  // make sure selectedVar is in vars
71
80
  if (settings.selectedVar) {
72
81
  const inVars = _.some(settings.vars, v => v.name === settings.selectedVar.name);
@@ -99,6 +108,18 @@ const validateSettings = settings => {
99
108
  settings.colorEncoding = null;
100
109
  }
101
110
  }
111
+
112
+ // @TODO: validate pseudospatial settings
113
+
114
+ // Keep only obs in use (selectedObs, labelObs) in data.obs
115
+ const obsNames = _.uniq(_.compact([(_settings$selectedObs = settings.selectedObs) === null || _settings$selectedObs === void 0 ? void 0 : _settings$selectedObs.name, ...settings.labelObs]));
116
+ const intersectionObs = _.intersection(_.keys(settings.data.obs), obsNames);
117
+ settings.data.obs = _.pick(settings.data.obs, intersectionObs);
118
+
119
+ // Keep only vars in use (settings.vars) in data.vars
120
+ const varNames = _.flatMap(settings.vars, v => v.isSet ? _.map(v.vars, vv => vv.name) : v.name);
121
+ const intersectionVars = _.intersection(_.keys(settings.data.vars), varNames);
122
+ settings.data.vars = _.pick(settings.data.vars, intersectionVars);
102
123
  return settings;
103
124
  };
104
125
  const initializer = _ref => {
@@ -107,9 +128,12 @@ const initializer = _ref => {
107
128
  defaultSettings,
108
129
  localSettings
109
130
  } = _ref;
110
- const mergedSettings = canOverrideSettings ? _.assign({}, initialSettings, defaultSettings, localSettings) : _.assign({}, initialSettings, defaultSettings);
131
+ const mergedSettings = canOverrideSettings ? _.defaultsDeep({}, localSettings, defaultSettings, initialSettings) : _.defaultsDeep({}, defaultSettings, initialSettings);
111
132
  return validateSettings(mergedSettings);
112
133
  };
134
+ const validate = settings => {
135
+ return settings ? validateSettings(settings) : null;
136
+ };
113
137
  export function SettingsProvider(_ref2) {
114
138
  let {
115
139
  dataset_url,
@@ -129,21 +153,34 @@ export function SettingsProvider(_ref2) {
129
153
 
130
154
  // If the buster is not set or does not match the current package version,
131
155
  // reset localSettings to avoid stale data
132
- if (!buster || buster !== "1.4.1-dev.2025-06-30.66ec83a3") {
156
+ if (!buster || buster !== "1.4.1-dev.2025-08-13.8f63c242") {
133
157
  localSettings = {};
134
158
  }
135
- const [settings, dispatch] = useReducer(settingsReducer, {
159
+ const initSettings = useRef(initializer({
136
160
  canOverrideSettings,
137
161
  defaultSettings,
138
162
  localSettings
139
- }, initializer);
163
+ }));
164
+ const resolvedSettings = useResolver(initSettings.current);
165
+ const [settings, dispatch] = useReducer(settingsReducer, resolvedSettings, validate);
166
+ useEffect(() => {
167
+ // If resolvedSettings is null, do not update settings
168
+ if (resolvedSettings) {
169
+ const validatedSettings = validateSettings(resolvedSettings);
170
+ console.log("Initial settings:", validatedSettings);
171
+ dispatch({
172
+ type: "init",
173
+ settings: validatedSettings
174
+ });
175
+ }
176
+ }, [resolvedSettings]);
140
177
  useEffect(() => {
141
178
  if (canOverrideSettings) {
142
179
  try {
143
- localStorage.setItem(DATASET_STORAGE_KEY, JSON.stringify(_objectSpread({
144
- buster: "1.4.1-dev.2025-06-30.66ec83a3" || "0.0.0",
180
+ localStorage.setItem(DATASET_STORAGE_KEY, JSON.stringify(_objectSpread(_objectSpread({
181
+ buster: "1.4.1-dev.2025-08-13.8f63c242" || "0.0.0",
145
182
  timestamp: Date.now()
146
- }, settings)));
183
+ }, _.omit(settings, "data")), settings)));
147
184
  } catch (err) {
148
185
  if (err.code === 22 || err.code === 1014 || err.name === "QuotaExceededError" || err.name === "NS_ERROR_DOM_QUOTA_REACHED") {
149
186
  console.err("Browser storage quota exceeded");
@@ -157,7 +194,7 @@ export function SettingsProvider(_ref2) {
157
194
  value: settings
158
195
  }, /*#__PURE__*/React.createElement(SettingsDispatchContext.Provider, {
159
196
  value: dispatch
160
- }, children));
197
+ }, settings && children));
161
198
  }
162
199
  export function useSettings() {
163
200
  return useContext(SettingsContext);
@@ -165,13 +202,70 @@ export function useSettings() {
165
202
  export function useSettingsDispatch() {
166
203
  return useContext(SettingsDispatchContext);
167
204
  }
205
+ const OBS_DATA_KEYS = ["name", "type",
206
+ // categorical and numerical
207
+ "codes", "codesMap", "values", "n_values", "value_counts",
208
+ // numerical
209
+ "bins", "min", "max", "mean", "median", "n_unique"];
210
+ const splitObs = obs => {
211
+ if (!obs) return {
212
+ settings: null,
213
+ data: {}
214
+ };
215
+ const settings = _.pick(obs, ["name", "omit", "bins"]);
216
+ const data = obs ? {
217
+ [obs.name]: _.pick(obs, OBS_DATA_KEYS)
218
+ } : {};
219
+ return {
220
+ settings,
221
+ data
222
+ };
223
+ };
224
+ const splitVar = v => {
225
+ if (!v) return {
226
+ settings: null,
227
+ data: {}
228
+ };
229
+ let settings, data;
230
+ if (v.isSet) {
231
+ settings = _objectSpread(_objectSpread({}, _.pick(v, ["name", "isSet"])), {}, {
232
+ vars: _.map(v.vars, vv => ({
233
+ name: vv.name
234
+ }))
235
+ });
236
+ data = _.fromPairs(_.map(v.vars, vv => [vv.name, _.pick(vv, ["name", "index", "matrix_index"])]));
237
+ } else {
238
+ settings = _.pick(v, ["name", "isSet"]);
239
+ data = {
240
+ [v.name]: _.pick(v, ["name", "index", "matrix_index"])
241
+ };
242
+ }
243
+ return {
244
+ settings,
245
+ data
246
+ };
247
+ };
168
248
  function settingsReducer(settings, action) {
169
249
  switch (action.type) {
250
+ case "init":
251
+ {
252
+ return action.settings;
253
+ }
170
254
  case "select.obs":
171
255
  {
172
256
  var _action$obs;
173
- return _objectSpread(_objectSpread({}, settings), {}, {
174
- selectedObs: action.obs,
257
+ const {
258
+ settings: obsSettings,
259
+ data: obsData
260
+ } = splitObs(action.obs);
261
+ return _objectSpread(_objectSpread(_objectSpread({}, settings), action.obs ? {
262
+ selectedObs: obsSettings,
263
+ data: _objectSpread(_objectSpread({}, settings.data), {}, {
264
+ obs: _objectSpread(_objectSpread({}, settings.data.obs), obsData)
265
+ })
266
+ } : {
267
+ selectedObs: null
268
+ }), {}, {
175
269
  controls: _objectSpread(_objectSpread({}, settings.controls), {}, {
176
270
  range: ((_action$obs = action.obs) === null || _action$obs === void 0 ? void 0 : _action$obs.type) === OBS_TYPES.CATEGORICAL ? [0, 1] : settings.controls.range
177
271
  }),
@@ -189,8 +283,15 @@ function settingsReducer(settings, action) {
189
283
  }
190
284
  case "select.var":
191
285
  {
286
+ const {
287
+ settings: varSettings,
288
+ data: varData
289
+ } = splitVar(action.var);
192
290
  return validateSettings(_objectSpread(_objectSpread({}, settings), {}, {
193
- selectedVar: action.var
291
+ selectedVar: varSettings,
292
+ data: _objectSpread(_objectSpread({}, settings.data), {}, {
293
+ vars: _objectSpread(_objectSpread({}, settings.data.vars), varData)
294
+ })
194
295
  }));
195
296
  }
196
297
  case "select.multivar":
@@ -199,8 +300,15 @@ function settingsReducer(settings, action) {
199
300
  if (inMultiVar) {
200
301
  return validateSettings(_objectSpread({}, settings));
201
302
  } else {
303
+ const {
304
+ settings: varSettings,
305
+ data: varData
306
+ } = splitVar(action.var);
202
307
  return validateSettings(_objectSpread(_objectSpread({}, settings), {}, {
203
- selectedMultiVar: [...settings.selectedMultiVar, action.var]
308
+ selectedMultiVar: [...settings.selectedMultiVar, varSettings],
309
+ data: _objectSpread(_objectSpread({}, settings.data), {}, {
310
+ vars: _objectSpread(_objectSpread({}, settings.data.vars), varData)
311
+ })
204
312
  }));
205
313
  }
206
314
  }
@@ -218,8 +326,15 @@ function settingsReducer(settings, action) {
218
326
  selectedMultiVar: settings.selectedMultiVar.filter(v => v.name !== action.var.name)
219
327
  }));
220
328
  } else {
329
+ const {
330
+ settings: varSettings,
331
+ data: varData
332
+ } = splitVar(action.var);
221
333
  return validateSettings(_objectSpread(_objectSpread({}, settings), {}, {
222
- selectedMultiVar: [...settings.selectedMultiVar, action.var]
334
+ selectedMultiVar: [...settings.selectedMultiVar, varSettings],
335
+ data: _objectSpread(_objectSpread({}, settings.data), {}, {
336
+ vars: _objectSpread(_objectSpread({}, settings.data.vars), varData)
337
+ })
223
338
  }));
224
339
  }
225
340
  }
@@ -254,8 +369,15 @@ function settingsReducer(settings, action) {
254
369
  if (settings.vars.find(v => v.name === action.var.name)) {
255
370
  return settings;
256
371
  } else {
372
+ const {
373
+ settings: varSettings,
374
+ data: varData
375
+ } = splitVar(action.var);
257
376
  return _objectSpread(_objectSpread({}, settings), {}, {
258
- vars: [...settings.vars, action.var]
377
+ vars: [...settings.vars, varSettings],
378
+ data: _objectSpread(_objectSpread({}, settings.data), {}, {
379
+ vars: _objectSpread(_objectSpread({}, settings.data.vars), varData)
380
+ })
259
381
  });
260
382
  }
261
383
  }
@@ -280,7 +402,11 @@ function settingsReducer(settings, action) {
280
402
  return settings;
281
403
  } else {
282
404
  var _settings$selectedVar2;
283
- const varSetVars = [...varSet.vars, action.var];
405
+ const {
406
+ settings: varSettings,
407
+ data: varData
408
+ } = splitVar(action.var);
409
+ const varSetVars = [...varSet.vars, varSettings];
284
410
  const vars = settings.vars.map(v => {
285
411
  if (v.name === varSet.name) {
286
412
  return _objectSpread(_objectSpread({}, v), {}, {
@@ -305,7 +431,10 @@ function settingsReducer(settings, action) {
305
431
  return validateSettings(_objectSpread(_objectSpread({}, settings), {}, {
306
432
  vars: vars,
307
433
  selectedVar: selectedVar,
308
- selectedMultiVar: selectedMultiVar
434
+ selectedMultiVar: selectedMultiVar,
435
+ data: _objectSpread(_objectSpread({}, settings.data), {}, {
436
+ vars: _objectSpread(_objectSpread({}, settings.data.vars), varData)
437
+ })
309
438
  }));
310
439
  }
311
440
  }
@@ -369,14 +498,6 @@ function settingsReducer(settings, action) {
369
498
  })
370
499
  });
371
500
  }
372
- case "set.controls.valueRange":
373
- {
374
- return _objectSpread(_objectSpread({}, settings), {}, {
375
- controls: _objectSpread(_objectSpread({}, settings.controls), {}, {
376
- valueRange: action.valueRange
377
- })
378
- });
379
- }
380
501
  case "set.controls.range":
381
502
  {
382
503
  return _objectSpread(_objectSpread({}, settings), {}, {
@@ -452,15 +573,22 @@ function settingsReducer(settings, action) {
452
573
  }
453
574
  case "toggle.slice.obs":
454
575
  {
455
- if (_.isEqual(settings.selectedObs, action.obs)) {
576
+ if (settings.selectedObs && settings.selectedObs.name === action.obs.name) {
456
577
  return _objectSpread(_objectSpread({}, settings), {}, {
457
578
  sliceBy: _objectSpread(_objectSpread({}, settings.sliceBy), {}, {
458
579
  obs: !settings.sliceBy.obs
459
580
  })
460
581
  });
461
582
  } else {
583
+ const {
584
+ settings: obsSettings,
585
+ data: obsData
586
+ } = splitObs(action.obs);
462
587
  return _objectSpread(_objectSpread({}, settings), {}, {
463
- selectedObs: action.obs,
588
+ selectedObs: obsSettings,
589
+ data: _objectSpread(_objectSpread({}, settings.data), {}, {
590
+ obs: _objectSpread(_objectSpread({}, settings.data.obs), obsData)
591
+ }),
464
592
  sliceBy: _objectSpread(_objectSpread({}, settings.sliceBy), {}, {
465
593
  obs: true
466
594
  })
@@ -485,25 +613,32 @@ function settingsReducer(settings, action) {
485
613
  }
486
614
  case "add.label.obs":
487
615
  {
488
- if (settings.labelObs.find(i => _.isEqual(i, action.obs))) {
616
+ if (_.includes(settings.labelObs, action.obs.name)) {
489
617
  return settings;
490
618
  } else {
619
+ const {
620
+ settings: obsSettings,
621
+ data: obsData
622
+ } = splitObs(action.obs);
491
623
  return _objectSpread(_objectSpread({}, settings), {}, {
492
- labelObs: [...settings.labelObs, action.obs]
624
+ labelObs: [...settings.labelObs, obsSettings.name],
625
+ data: _objectSpread(_objectSpread({}, settings.data), {}, {
626
+ obs: _objectSpread(_objectSpread({}, settings.data.obs), obsData)
627
+ })
493
628
  });
494
629
  }
495
630
  }
496
631
  case "remove.label.obs":
497
632
  {
498
- return _objectSpread(_objectSpread({}, settings), {}, {
499
- labelObs: settings.labelObs.filter(a => a.name !== action.obsName)
500
- });
633
+ return validateSettings(_objectSpread(_objectSpread({}, settings), {}, {
634
+ labelObs: settings.labelObs.filter(a => a !== action.obsName)
635
+ }));
501
636
  }
502
637
  case "reset.label.obs":
503
638
  {
504
- return _objectSpread(_objectSpread({}, settings), {}, {
639
+ return validateSettings(_objectSpread(_objectSpread({}, settings), {}, {
505
640
  labelObs: []
506
- });
641
+ }));
507
642
  }
508
643
  case "set.varSort":
509
644
  {
@@ -1,6 +1,7 @@
1
1
  import { useEffect, useCallback, useMemo } from "react";
2
2
  import { booleanPointInPolygon, point } from "@turf/turf";
3
3
  import _ from "lodash";
4
+ import { useSelectedObs } from "./Resolver";
4
5
  import { COLOR_ENCODINGS, OBS_TYPES } from "../constants/constants";
5
6
  import { useFilteredDataDispatch } from "../context/FilterContext";
6
7
  import { useSettings } from "../context/SettingsContext";
@@ -29,9 +30,14 @@ const isInValues = (omit, value) => {
29
30
  return !_.includes(omit, value);
30
31
  };
31
32
  export const useFilter = data => {
32
- var _settings$selectedObs, _settings$selectedObs2, _settings$selectedObs3, _settings$selectedObs4, _settings$selectedObs7, _settings$selectedObs8;
33
+ var _selectedObs$omit, _selectedObs$bins2;
33
34
  const settings = useSettings();
34
35
  const filterDataDispatch = useFilteredDataDispatch();
36
+ const selectedObs = useSelectedObs();
37
+ const omitCodes = _.map((selectedObs === null || selectedObs === void 0 ? void 0 : selectedObs.omit) || [], o => {
38
+ var _selectedObs$codes;
39
+ return selectedObs === null || selectedObs === void 0 || (_selectedObs$codes = selectedObs.codes) === null || _selectedObs$codes === void 0 ? void 0 : _selectedObs$codes[o];
40
+ });
35
41
  const {
36
42
  obsmData,
37
43
  xData,
@@ -39,26 +45,25 @@ export const useFilter = data => {
39
45
  isPending,
40
46
  serverError
41
47
  } = data;
42
- const isCategorical = ((_settings$selectedObs = settings.selectedObs) === null || _settings$selectedObs === void 0 ? void 0 : _settings$selectedObs.type) === OBS_TYPES.CATEGORICAL || ((_settings$selectedObs2 = settings.selectedObs) === null || _settings$selectedObs2 === void 0 ? void 0 : _settings$selectedObs2.type) === OBS_TYPES.BOOLEAN;
43
- const isContinuous = ((_settings$selectedObs3 = settings.selectedObs) === null || _settings$selectedObs3 === void 0 ? void 0 : _settings$selectedObs3.type) === OBS_TYPES.CONTINUOUS;
44
- const sliceByObs = settings.colorEncoding === COLOR_ENCODINGS.OBS && !!((_settings$selectedObs4 = settings.selectedObs) !== null && _settings$selectedObs4 !== void 0 && _settings$selectedObs4.omit.length) || settings.sliceBy.obs;
48
+ const isCategorical = (selectedObs === null || selectedObs === void 0 ? void 0 : selectedObs.type) === OBS_TYPES.CATEGORICAL || (selectedObs === null || selectedObs === void 0 ? void 0 : selectedObs.type) === OBS_TYPES.BOOLEAN;
49
+ const isContinuous = (selectedObs === null || selectedObs === void 0 ? void 0 : selectedObs.type) === OBS_TYPES.CONTINUOUS;
50
+ const sliceByObs = settings.colorEncoding === COLOR_ENCODINGS.OBS && !!(selectedObs !== null && selectedObs !== void 0 && (_selectedObs$omit = selectedObs.omit) !== null && _selectedObs$omit !== void 0 && _selectedObs$omit.length) || settings.sliceBy.obs;
45
51
  const isInObsSlice = useCallback((index, values) => {
46
52
  let inSlice = true;
47
53
  if (values && sliceByObs) {
48
54
  if (isCategorical) {
49
- var _settings$selectedObs5;
50
- inSlice &= isInValues((_settings$selectedObs5 = settings.selectedObs) === null || _settings$selectedObs5 === void 0 ? void 0 : _settings$selectedObs5.omit, values[index]);
55
+ inSlice &= isInValues(omitCodes, values[index]);
51
56
  } else if (isContinuous) {
52
57
  if (isNaN(values[index])) {
53
- var _settings$selectedObs6;
54
- inSlice &= isInValues((_settings$selectedObs6 = settings.selectedObs) === null || _settings$selectedObs6 === void 0 ? void 0 : _settings$selectedObs6.omit, -1);
58
+ inSlice &= isInValues(omitCodes, -1);
55
59
  } else {
56
- inSlice &= isInBins(values[index], settings.selectedObs.bins.binEdges, _.without(settings.selectedObs.omit, -1));
60
+ var _selectedObs$bins;
61
+ inSlice &= isInBins(values[index], selectedObs === null || selectedObs === void 0 || (_selectedObs$bins = selectedObs.bins) === null || _selectedObs$bins === void 0 ? void 0 : _selectedObs$bins.binEdges, _.without(omitCodes, -1));
57
62
  }
58
63
  }
59
64
  }
60
65
  return inSlice;
61
- }, [(_settings$selectedObs7 = settings.selectedObs) === null || _settings$selectedObs7 === void 0 || (_settings$selectedObs7 = _settings$selectedObs7.bins) === null || _settings$selectedObs7 === void 0 ? void 0 : _settings$selectedObs7.binEdges, (_settings$selectedObs8 = settings.selectedObs) === null || _settings$selectedObs8 === void 0 ? void 0 : _settings$selectedObs8.omit, isCategorical, isContinuous, sliceByObs]);
66
+ }, [sliceByObs, isCategorical, isContinuous, omitCodes, selectedObs === null || selectedObs === void 0 || (_selectedObs$bins2 = selectedObs.bins) === null || _selectedObs$bins2 === void 0 ? void 0 : _selectedObs$bins2.binEdges]);
62
67
  const isInPolygonsSlice = useCallback((index, positions) => {
63
68
  let inSlice = true;
64
69
  if (settings.sliceBy.polygons && positions) {
@@ -0,0 +1,176 @@
1
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
2
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
3
+ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
4
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
5
+ function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
6
+ import { useState, useEffect, useMemo } from "react";
7
+ import _ from "lodash";
8
+ import { useFetch } from "./requests";
9
+ import { useDataset } from "../context/DatasetContext";
10
+ import { useSettings } from "../context/SettingsContext";
11
+ const cleanSettings = settings => {
12
+ // Remove obs and vars from settings that are not in data
13
+
14
+ const selectedObs = settings.selectedObs && settings.data.obs[settings.selectedObs.name] ? settings.selectedObs : null;
15
+ const labelObs = _.filter(settings.labelObs, obsName => settings.data.obs[obsName]);
16
+ const selectedVar = settings.selectedVar && (settings.selectedVar.isSet ? _.every(settings.selectedVar.vars, vv => settings.data.vars[vv.name]) : settings.data.vars[settings.selectedVar.name]) ? settings.selectedVar : null;
17
+ const selectedMultiVar = _.filter(settings.selectedMultiVar, v => {
18
+ if (v.isSet) {
19
+ return _.every(v.vars, vv => settings.data.vars[vv.name]);
20
+ } else {
21
+ return settings.data.vars[v.name];
22
+ }
23
+ });
24
+ const vars = _.filter(settings.vars, v => {
25
+ if (v.isSet) {
26
+ return _.every(v.vars, vv => settings.data.vars[vv.name]);
27
+ } else {
28
+ return settings.data.vars[v.name];
29
+ }
30
+ });
31
+ return _objectSpread(_objectSpread({}, settings), {}, {
32
+ selectedObs: selectedObs,
33
+ labelObs: labelObs,
34
+ selectedVar: selectedVar,
35
+ selectedMultiVar: selectedMultiVar,
36
+ vars: vars
37
+ });
38
+ };
39
+ export const useResolver = initSettings => {
40
+ var _initSettings$selecte;
41
+ const dataset = useDataset();
42
+ const [data, setData] = useState({
43
+ obs: {},
44
+ vars: {}
45
+ });
46
+ const [resolvedObs, setResolvedObs] = useState(false);
47
+ const [resolvedVars, setResolvedVars] = useState(false);
48
+ const [resolvedSettings, setResolvedSettings] = useState(null);
49
+
50
+ // obs
51
+ // all obs should be in initSettings.selectedObs and initSettings.labelObs
52
+ const initObs = _.uniqBy(_.compact([initSettings.selectedObs, ..._.map(initSettings.labelObs, o => ({
53
+ name: o
54
+ }))]), "name");
55
+ const initObsNames = _.map(initObs, o => o.name);
56
+ const [obsParams] = useState({
57
+ url: dataset.url,
58
+ cols: initObsNames,
59
+ obsParams: _.fromPairs(_.map(initObs, o => [o.name, {
60
+ bins: o.bins || {}
61
+ }]))
62
+ });
63
+ const {
64
+ fetchedData: obsData,
65
+ isPending: obsDataPending,
66
+ serverError: obsDataError
67
+ } = useFetch("obs/cols", obsParams, {
68
+ enabled: !!initObsNames.length
69
+ });
70
+
71
+ // vars
72
+ // all vars should be in initSettings.vars from validation
73
+ const initVars = initSettings.vars;
74
+ const initVarsNames = _.flatMap(initVars, v => v.isSet ? _.map(v.vars, vv => vv.name) : v.name);
75
+ const [varParams] = useState({
76
+ url: dataset.url,
77
+ col: dataset.varNamesCol,
78
+ names: initVarsNames
79
+ });
80
+ const {
81
+ fetchedData: varData,
82
+ isPending: varDataPending,
83
+ serverError: varDataError
84
+ } = useFetch("var/cols/names", varParams, {
85
+ enabled: !!varParams.names.length
86
+ });
87
+ useEffect(() => {
88
+ if (!obsDataPending) {
89
+ if (obsDataError) {
90
+ console.error("Error fetching obs data:", obsDataError);
91
+ setResolvedObs(true);
92
+ return;
93
+ }
94
+ if (obsData) {
95
+ setData(d => _objectSpread(_objectSpread({}, d), {}, {
96
+ obs: _.fromPairs(_.map(obsData, o => [o.name, o]))
97
+ }));
98
+ }
99
+ setResolvedObs(true);
100
+ }
101
+ }, [obsData, obsDataError, obsDataPending, (_initSettings$selecte = initSettings.selectedObs) === null || _initSettings$selecte === void 0 ? void 0 : _initSettings$selecte.omit]);
102
+ useEffect(() => {
103
+ if (!varDataPending) {
104
+ if (varDataError) {
105
+ console.error("Error fetching var data:", varDataError);
106
+ setResolvedVars(true);
107
+ return;
108
+ }
109
+ if (varData) {
110
+ setData(d => _objectSpread(_objectSpread({}, d), {}, {
111
+ vars: _.fromPairs(_.map(varData, v => [v.name, v]))
112
+ }));
113
+ }
114
+ setResolvedVars(true);
115
+ }
116
+ }, [initSettings.vars, varData, varDataError, varDataPending]);
117
+ useEffect(() => {
118
+ if (resolvedObs && resolvedVars) {
119
+ const cleanedSettings = cleanSettings(_objectSpread(_objectSpread({}, initSettings), {}, {
120
+ data: data
121
+ }));
122
+ setResolvedSettings(cleanedSettings);
123
+ }
124
+ }, [data, initSettings, resolvedObs, resolvedVars, setResolvedSettings]);
125
+ return resolvedSettings;
126
+ };
127
+ export const useSelectedObs = () => {
128
+ const settings = useSettings();
129
+ return useMemo(() => {
130
+ return settings.selectedObs ? _objectSpread(_objectSpread({}, settings.selectedObs), settings.data.obs[settings.selectedObs.name]) : null;
131
+ }, [settings.data.obs, settings.selectedObs]);
132
+ };
133
+ export const useSelectedVar = () => {
134
+ const settings = useSettings();
135
+ return useMemo(() => {
136
+ if (settings.selectedVar) {
137
+ if (settings.selectedVar.isSet) {
138
+ return _objectSpread(_objectSpread({}, settings.selectedVar), {}, {
139
+ vars: settings.selectedVar.vars.map(v => _objectSpread({}, settings.data.vars[v.name]))
140
+ });
141
+ } else {
142
+ return _objectSpread(_objectSpread({}, settings.selectedVar), settings.data.vars[settings.selectedVar.name]);
143
+ }
144
+ } else {
145
+ return null;
146
+ }
147
+ }, [settings.data.vars, settings.selectedVar]);
148
+ };
149
+ export const useSelectedMultiVar = () => {
150
+ const settings = useSettings();
151
+ return useMemo(() => {
152
+ return _.map(settings.selectedMultiVar, v => {
153
+ if (v.isSet) {
154
+ return _objectSpread(_objectSpread({}, v), {}, {
155
+ vars: v.vars.map(vv => _objectSpread({}, settings.data.vars[vv.name]))
156
+ });
157
+ } else {
158
+ return _objectSpread(_objectSpread({}, v), settings.data.vars[v.name]);
159
+ }
160
+ });
161
+ }, [settings.data.vars, settings.selectedMultiVar]);
162
+ };
163
+ export const useSettingsVars = () => {
164
+ const settings = useSettings();
165
+ return useMemo(() => {
166
+ return _.map(settings.vars, v => {
167
+ if (v.isSet) {
168
+ return _objectSpread(_objectSpread({}, v), {}, {
169
+ vars: v.vars.map(vv => _objectSpread({}, settings.data.vars[vv.name]))
170
+ });
171
+ } else {
172
+ return _objectSpread(_objectSpread({}, v), settings.data.vars[v.name]);
173
+ }
174
+ });
175
+ }, [settings.data.vars, settings.vars]);
176
+ };