@haniffalab/cherita-react 1.4.1-dev.2025-08-13.6fc43290 → 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.
- package/dist/cjs/components/dotplot/Dotplot.js +12 -16
- package/dist/cjs/components/heatmap/Heatmap.js +11 -16
- package/dist/cjs/components/matrixplot/Matrixplot.js +11 -16
- package/dist/cjs/components/obs-list/ObsItem.js +14 -14
- package/dist/cjs/components/obs-list/ObsList.js +24 -23
- package/dist/cjs/components/pseudospatial/Pseudospatial.js +25 -31
- package/dist/cjs/components/scatterplot/Scatterplot.js +14 -23
- package/dist/cjs/components/scatterplot/ScatterplotControls.js +9 -3
- package/dist/cjs/components/var-list/VarList.js +16 -14
- package/dist/cjs/components/violin/Violin.js +21 -25
- package/dist/cjs/context/DatasetContext.js +4 -4
- package/dist/cjs/context/SettingsContext.js +175 -40
- package/dist/cjs/utils/Filter.js +15 -10
- package/dist/cjs/utils/Resolver.js +188 -0
- package/dist/cjs/utils/zarrData.js +16 -17
- package/dist/esm/components/dotplot/Dotplot.js +12 -16
- package/dist/esm/components/heatmap/Heatmap.js +11 -16
- package/dist/esm/components/matrixplot/Matrixplot.js +11 -16
- package/dist/esm/components/obs-list/ObsItem.js +14 -14
- package/dist/esm/components/obs-list/ObsList.js +24 -23
- package/dist/esm/components/pseudospatial/Pseudospatial.js +25 -31
- package/dist/esm/components/scatterplot/Scatterplot.js +14 -23
- package/dist/esm/components/scatterplot/ScatterplotControls.js +9 -3
- package/dist/esm/components/var-list/VarList.js +16 -14
- package/dist/esm/components/violin/Violin.js +21 -25
- package/dist/esm/context/DatasetContext.js +4 -4
- package/dist/esm/context/SettingsContext.js +176 -41
- package/dist/esm/utils/Filter.js +15 -10
- package/dist/esm/utils/Resolver.js +176 -0
- package/dist/esm/utils/zarrData.js +16 -17
- 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
|
-
|
|
21
|
+
// "obsm_name" (e.g. "X_umap")
|
|
24
22
|
selectedMultiVar: [],
|
|
25
|
-
|
|
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 => {
|
|
@@ -110,6 +131,9 @@ const initializer = _ref => {
|
|
|
110
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-08-13.
|
|
156
|
+
if (!buster || buster !== "1.4.1-dev.2025-08-13.8f63c242") {
|
|
133
157
|
localSettings = {};
|
|
134
158
|
}
|
|
135
|
-
const
|
|
159
|
+
const initSettings = useRef(initializer({
|
|
136
160
|
canOverrideSettings,
|
|
137
161
|
defaultSettings,
|
|
138
162
|
localSettings
|
|
139
|
-
}
|
|
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-08-13.
|
|
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
|
-
|
|
174
|
-
|
|
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:
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
|
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 (
|
|
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:
|
|
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
|
|
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,
|
|
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
|
|
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
|
{
|
package/dist/esm/utils/Filter.js
CHANGED
|
@@ -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
|
|
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 = (
|
|
43
|
-
const isContinuous = (
|
|
44
|
-
const sliceByObs = settings.colorEncoding === COLOR_ENCODINGS.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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
}, [
|
|
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
|
+
};
|