@haniffalab/cherita-react 1.3.0 → 1.3.1-dev.2025-10-29.def77f5f

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 (137) hide show
  1. package/README.md +1 -1
  2. package/dist/cjs/components/controls/Controls.js +38 -30
  3. package/dist/cjs/components/dotplot/Dotplot.js +85 -57
  4. package/dist/cjs/components/dotplot/DotplotControls.js +103 -83
  5. package/dist/cjs/components/full-page/FullPage.js +167 -114
  6. package/dist/cjs/components/full-page/PlotAlert.js +45 -0
  7. package/dist/cjs/components/full-page/PlotTypeSelector.js +102 -0
  8. package/dist/cjs/components/heatmap/Heatmap.js +83 -53
  9. package/dist/cjs/components/heatmap/HeatmapControls.js +6 -3
  10. package/dist/cjs/components/icons/DotPlotIcon.js +64 -0
  11. package/dist/cjs/components/icons/HeatmapIcon.js +45 -0
  12. package/dist/cjs/components/icons/MatrixPlotIcon.1.js +57 -0
  13. package/dist/cjs/components/icons/MatrixPlotIcon.js +59 -0
  14. package/dist/cjs/components/icons/ScatterplotIcon.1.js +164 -0
  15. package/dist/cjs/components/icons/ScatterplotIcon.js +144 -0
  16. package/dist/cjs/components/icons/ViolinPlotIcon.js +42 -0
  17. package/dist/cjs/components/matrixplot/Matrixplot.js +83 -54
  18. package/dist/cjs/components/matrixplot/MatrixplotControls.js +8 -5
  19. package/dist/cjs/components/obs-list/ObsItem.js +305 -216
  20. package/dist/cjs/components/obs-list/ObsList.js +164 -128
  21. package/dist/cjs/components/obs-list/ObsToolbar.js +2 -3
  22. package/dist/cjs/components/obsm-list/ObsmList.js +67 -28
  23. package/dist/cjs/components/offcanvas/index.js +62 -27
  24. package/dist/cjs/components/pseudospatial/Pseudospatial.js +132 -76
  25. package/dist/cjs/components/pseudospatial/PseudospatialToolbar.js +122 -74
  26. package/dist/cjs/components/scatterplot/Scatterplot.js +223 -175
  27. package/dist/cjs/components/scatterplot/ScatterplotControls.js +45 -31
  28. package/dist/cjs/components/scatterplot/SpatialControls.js +143 -116
  29. package/dist/cjs/components/scatterplot/Toolbox.js +41 -30
  30. package/dist/cjs/components/search-bar/SearchBar.js +176 -120
  31. package/dist/cjs/components/search-bar/SearchInfo.js +79 -85
  32. package/dist/cjs/components/search-bar/SearchResults.js +93 -71
  33. package/dist/cjs/components/toolbar/Toolbar.js +111 -0
  34. package/dist/cjs/components/var-list/VarItem.js +131 -103
  35. package/dist/cjs/components/var-list/VarList.js +96 -74
  36. package/dist/cjs/components/var-list/VarListToolbar.js +59 -54
  37. package/dist/cjs/components/var-list/VarSet.js +126 -108
  38. package/dist/cjs/components/violin/Violin.js +124 -81
  39. package/dist/cjs/components/violin/ViolinControls.js +8 -5
  40. package/dist/cjs/constants/colorscales.js +19 -19
  41. package/dist/cjs/constants/constants.js +54 -39
  42. package/dist/cjs/context/DatasetContext.js +27 -17
  43. package/dist/cjs/context/FilterContext.js +11 -9
  44. package/dist/cjs/context/SettingsContext.js +339 -125
  45. package/dist/cjs/context/ZarrDataContext.js +6 -5
  46. package/dist/cjs/helpers/color-helper.js +2 -2
  47. package/dist/cjs/helpers/map-helper.js +2 -1
  48. package/dist/cjs/helpers/zarr-helper.js +3 -3
  49. package/dist/cjs/index.js +15 -21
  50. package/dist/cjs/utils/Filter.js +16 -11
  51. package/dist/cjs/utils/Histogram.js +35 -33
  52. package/dist/cjs/utils/ImageViewer.js +11 -8
  53. package/dist/cjs/utils/Legend.js +37 -30
  54. package/dist/cjs/utils/LoadingIndicators.js +15 -13
  55. package/dist/cjs/utils/Resolver.js +213 -0
  56. package/dist/cjs/utils/Skeleton.js +10 -10
  57. package/dist/cjs/utils/StyledTooltip.js +44 -0
  58. package/dist/cjs/utils/VirtualizedList.js +36 -29
  59. package/dist/cjs/utils/errors.js +15 -15
  60. package/dist/cjs/utils/requests.js +21 -9
  61. package/dist/cjs/utils/search.js +4 -4
  62. package/dist/cjs/utils/string.js +6 -6
  63. package/dist/cjs/utils/zarrData.js +20 -21
  64. package/dist/css/cherita.css +188 -65
  65. package/dist/css/cherita.css.map +1 -1
  66. package/dist/esm/components/controls/Controls.js +43 -35
  67. package/dist/esm/components/dotplot/Dotplot.js +93 -64
  68. package/dist/esm/components/dotplot/DotplotControls.js +106 -85
  69. package/dist/esm/components/full-page/FullPage.js +180 -124
  70. package/dist/esm/components/full-page/PlotAlert.js +39 -0
  71. package/dist/esm/components/full-page/PlotTypeSelector.js +95 -0
  72. package/dist/esm/components/heatmap/Heatmap.js +91 -60
  73. package/dist/esm/components/heatmap/HeatmapControls.js +8 -4
  74. package/dist/esm/components/icons/DotPlotIcon.js +58 -0
  75. package/dist/esm/components/icons/HeatmapIcon.js +39 -0
  76. package/dist/esm/components/icons/MatrixPlotIcon.1.js +51 -0
  77. package/dist/esm/components/icons/MatrixPlotIcon.js +53 -0
  78. package/dist/esm/components/icons/ScatterplotIcon.1.js +158 -0
  79. package/dist/esm/components/icons/ScatterplotIcon.js +138 -0
  80. package/dist/esm/components/icons/ViolinPlotIcon.js +36 -0
  81. package/dist/esm/components/matrixplot/Matrixplot.js +91 -61
  82. package/dist/esm/components/matrixplot/MatrixplotControls.js +10 -6
  83. package/dist/esm/components/obs-list/ObsItem.js +320 -228
  84. package/dist/esm/components/obs-list/ObsList.js +179 -142
  85. package/dist/esm/components/obs-list/ObsToolbar.js +3 -3
  86. package/dist/esm/components/obsm-list/ObsmList.js +71 -32
  87. package/dist/esm/components/offcanvas/index.js +68 -33
  88. package/dist/esm/components/pseudospatial/Pseudospatial.js +145 -88
  89. package/dist/esm/components/pseudospatial/PseudospatialToolbar.js +127 -78
  90. package/dist/esm/components/scatterplot/Scatterplot.js +243 -194
  91. package/dist/esm/components/scatterplot/ScatterplotControls.js +50 -35
  92. package/dist/esm/components/scatterplot/SpatialControls.js +155 -127
  93. package/dist/esm/components/scatterplot/Toolbox.js +44 -32
  94. package/dist/esm/components/search-bar/SearchBar.js +187 -130
  95. package/dist/esm/components/search-bar/SearchInfo.js +86 -91
  96. package/dist/esm/components/search-bar/SearchResults.js +100 -77
  97. package/dist/esm/components/toolbar/Toolbar.js +101 -0
  98. package/dist/esm/components/var-list/VarItem.js +142 -113
  99. package/dist/esm/components/var-list/VarList.js +108 -88
  100. package/dist/esm/components/var-list/VarListToolbar.js +64 -58
  101. package/dist/esm/components/var-list/VarSet.js +134 -115
  102. package/dist/esm/components/violin/Violin.js +135 -91
  103. package/dist/esm/components/violin/ViolinControls.js +10 -6
  104. package/dist/esm/constants/colorscales.js +19 -19
  105. package/dist/esm/constants/constants.js +53 -38
  106. package/dist/esm/context/DatasetContext.js +34 -23
  107. package/dist/esm/context/FilterContext.js +11 -8
  108. package/dist/esm/context/SettingsContext.js +341 -126
  109. package/dist/esm/context/ZarrDataContext.js +8 -6
  110. package/dist/esm/helpers/color-helper.js +5 -5
  111. package/dist/esm/helpers/map-helper.js +4 -3
  112. package/dist/esm/helpers/zarr-helper.js +6 -6
  113. package/dist/esm/index.js +22 -22
  114. package/dist/esm/utils/Filter.js +22 -17
  115. package/dist/esm/utils/Histogram.js +39 -37
  116. package/dist/esm/utils/ImageViewer.js +12 -8
  117. package/dist/esm/utils/Legend.js +44 -36
  118. package/dist/esm/utils/LoadingIndicators.js +16 -13
  119. package/dist/esm/utils/Resolver.js +201 -0
  120. package/dist/esm/utils/Skeleton.js +11 -10
  121. package/dist/esm/utils/StyledTooltip.js +38 -0
  122. package/dist/esm/utils/VirtualizedList.js +37 -29
  123. package/dist/esm/utils/errors.js +15 -15
  124. package/dist/esm/utils/requests.js +24 -12
  125. package/dist/esm/utils/search.js +7 -7
  126. package/dist/esm/utils/string.js +7 -7
  127. package/dist/esm/utils/zarrData.js +27 -28
  128. package/package.json +24 -10
  129. package/scss/cherita-bootstrap.scss +2 -2
  130. package/scss/cherita.scss +65 -17
  131. package/scss/components/accordions.scss +15 -2
  132. package/scss/components/layouts.scss +116 -30
  133. package/scss/components/lists.scss +16 -5
  134. package/scss/components/plotly.scss +40 -23
  135. package/scss/components/plots.scss +14 -1
  136. package/dist/cjs/components/full-page/FullPagePseudospatial.js +0 -157
  137. package/dist/esm/components/full-page/FullPagePseudospatial.js +0 -149
@@ -1,31 +1,41 @@
1
+ const _excluded = ["buster", "timestamp"];
1
2
  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
3
  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
4
  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
5
  function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
5
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); }
6
- import React, { createContext, useContext, useEffect, useReducer } from "react";
7
- import _ from "lodash";
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";
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
+ 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 { createContext, useContext, useEffect, useReducer, useRef } from 'react';
10
+ import _ from 'lodash';
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';
13
+ import { jsx as _jsx } from "react/jsx-runtime";
9
14
  export const SettingsContext = /*#__PURE__*/createContext(null);
10
15
  export const SettingsDispatchContext = /*#__PURE__*/createContext(null);
11
16
  const initialSettings = {
12
17
  selectedObs: null,
18
+ // { name: "obs_name", omit: ["obs_item"], bins: {} }
13
19
  selectedVar: null,
20
+ // { name: "var_name", isSet: false } or { name: "var_set_name", isSet: true, vars: [{ name: "var1" }, { name: "var2" }] }
14
21
  selectedObsm: null,
15
- selectedMultiObs: [],
22
+ // "obsm_name" (e.g. "X_umap")
16
23
  selectedMultiVar: [],
17
- colorEncoding: null,
24
+ // [{ name: "var_name", isSet: false }, { name: "var_set_name", isSet: true, vars: [{ name: "var1" }, { name: "var2" }] }]
18
25
  labelObs: [],
26
+ // [ "obs_name1", "obs_name2" ]
19
27
  vars: [],
28
+ // [{ name: "var_name", isSet: false }, { name: "var_set_name", isSet: true, vars: [{ name: "var1" }, { name: "var2" }] }]
29
+ colorEncoding: null,
20
30
  sliceBy: {
21
31
  obs: false,
22
32
  polygons: false
23
33
  },
24
34
  polygons: {},
25
35
  controls: {
26
- colorScale: "Viridis",
27
- valueRange: [0, 1],
36
+ colorScale: 'Viridis',
28
37
  range: [0, 1],
38
+ // normalized
29
39
  colorAxis: {
30
40
  dmin: 0,
31
41
  dmax: 1,
@@ -53,16 +63,86 @@ const initialSettings = {
53
63
  pseudospatial: {
54
64
  maskSet: null,
55
65
  maskValues: null,
56
- categoricalMode: PSEUDOSPATIAL_CATEGORICAL_MODES.ACROSS.value
66
+ categoricalMode: PSEUDOSPATIAL_CATEGORICAL_MODES.ACROSS.value,
67
+ refImg: {
68
+ visible: false,
69
+ opacity: 1
70
+ }
71
+ },
72
+ // dataset resolved values
73
+ data: {
74
+ // store resolved obs and vars from selectedObs, selectedVar, selectedMultiVar, vars, labelObs
75
+ // keys to be removed when not in any selection
76
+ obs: {},
77
+ vars: {},
78
+ // store maskSets and values
79
+ pseudospatial: {}
57
80
  }
58
81
  };
82
+
83
+ // validate on initialization and reducer
84
+ const validateSettings = settings => {
85
+ var _settings$selectedObs;
86
+ // make sure selectedVar is in vars
87
+ if (settings.selectedVar) {
88
+ const inVars = _.some(settings.vars, v => v.name === settings.selectedVar.name);
89
+ if (!inVars) {
90
+ settings.vars = [...settings.vars, settings.selectedVar];
91
+ }
92
+ }
93
+
94
+ // make sure selectedMultiVar are in vars
95
+ if (settings.selectedMultiVar) {
96
+ const notInVars = _.differenceBy(settings.selectedMultiVar, settings.vars, 'name');
97
+ if (notInVars.length) {
98
+ settings.vars = [...settings.vars, ...notInVars];
99
+ }
100
+ }
101
+
102
+ // make sure there's a selectedVar if colorEncoding is VAR
103
+ if (settings.colorEncoding === COLOR_ENCODINGS.VAR) {
104
+ if (!settings.selectedVar) {
105
+ settings.colorEncoding = null;
106
+ } else if (settings.selectedVar.isSet && !settings.selectedVar.vars.length) {
107
+ settings.selectedVar = null;
108
+ settings.colorEncoding = null;
109
+ }
110
+ }
111
+
112
+ // make sure there's a selectedObs if colorEncoding is OBS
113
+ if (settings.colorEncoding === COLOR_ENCODINGS.OBS) {
114
+ if (!settings.selectedObs) {
115
+ settings.colorEncoding = null;
116
+ }
117
+ }
118
+
119
+ // pseudospatial
120
+ if (!settings.pseudospatial.maskSet && settings.pseudospatial.maskValues) {
121
+ settings.pseudospatial.maskValues = null;
122
+ }
123
+
124
+ // Keep only obs in use (selectedObs, labelObs) in data.obs
125
+ const obsNames = _.uniq(_.compact([(_settings$selectedObs = settings.selectedObs) === null || _settings$selectedObs === void 0 ? void 0 : _settings$selectedObs.name, ...settings.labelObs]));
126
+ const intersectionObs = _.intersection(_.keys(settings.data.obs), obsNames);
127
+ settings.data.obs = _.pick(settings.data.obs, intersectionObs);
128
+
129
+ // Keep only vars in use (settings.vars) in data.vars
130
+ const varNames = _.flatMap(settings.vars, v => v.isSet ? _.map(v.vars, vv => vv.name) : v.name);
131
+ const intersectionVars = _.intersection(_.keys(settings.data.vars), varNames);
132
+ settings.data.vars = _.pick(settings.data.vars, intersectionVars);
133
+ return settings;
134
+ };
59
135
  const initializer = _ref => {
60
136
  let {
61
137
  canOverrideSettings,
62
138
  defaultSettings,
63
139
  localSettings
64
140
  } = _ref;
65
- return canOverrideSettings ? _.assign({}, initialSettings, defaultSettings, localSettings) : _.assign({}, initialSettings, defaultSettings);
141
+ const mergedSettings = canOverrideSettings ? _.defaultsDeep({}, localSettings, defaultSettings, initialSettings) : _.defaultsDeep({}, defaultSettings, initialSettings);
142
+ return validateSettings(mergedSettings);
143
+ };
144
+ const validate = settings => {
145
+ return settings ? validateSettings(settings) : null;
66
146
  };
67
147
  export function SettingsProvider(_ref2) {
68
148
  let {
@@ -74,30 +154,59 @@ export function SettingsProvider(_ref2) {
74
154
  const DATASET_STORAGE_KEY = "".concat(LOCAL_STORAGE_KEY, "-").concat(dataset_url);
75
155
  // Use localStorage directly instead of useLocalStorage due to unnecessary re-renders
76
156
  // https://github.com/uidotdev/usehooks/issues/157
77
- const localSettings = JSON.parse(localStorage.getItem(DATASET_STORAGE_KEY)) || {};
78
- const [settings, dispatch] = useReducer(settingsReducer, {
157
+ let _ref3 = JSON.parse(localStorage.getItem(DATASET_STORAGE_KEY)) || {},
158
+ {
159
+ buster,
160
+ timestamp
161
+ } = _ref3,
162
+ localSettings = _objectWithoutProperties(_ref3, _excluded);
163
+
164
+ // If the buster is not set or does not match the current package version,
165
+ // reset localSettings to avoid stale data
166
+ if (!buster || buster !== "1.3.1-dev.2025-10-29.def77f5f") {
167
+ localSettings = {};
168
+ }
169
+ const initSettings = useRef(initializer({
79
170
  canOverrideSettings,
80
171
  defaultSettings,
81
172
  localSettings
82
- }, initializer);
173
+ }));
174
+ const resolvedSettings = useResolver(initSettings.current);
175
+ const [settings, dispatch] = useReducer(settingsReducer, resolvedSettings, validate);
176
+ useEffect(() => {
177
+ // If resolvedSettings is null, do not update settings
178
+ if (resolvedSettings) {
179
+ const validatedSettings = validateSettings(resolvedSettings);
180
+ console.log('Initial settings:', validatedSettings);
181
+ dispatch({
182
+ type: 'init',
183
+ settings: validatedSettings
184
+ });
185
+ }
186
+ }, [resolvedSettings]);
83
187
  useEffect(() => {
84
- if (canOverrideSettings) {
188
+ if (canOverrideSettings && settings) {
85
189
  try {
86
- localStorage.setItem(DATASET_STORAGE_KEY, JSON.stringify(settings));
190
+ localStorage.setItem(DATASET_STORAGE_KEY, JSON.stringify(_objectSpread({
191
+ buster: "1.3.1-dev.2025-10-29.def77f5f" || '0.0.0',
192
+ timestamp: Date.now()
193
+ }, _.omit(settings, 'data'))));
87
194
  } catch (err) {
88
- if (err.code === 22 || err.code === 1014 || err.name === "QuotaExceededError" || err.name === "NS_ERROR_DOM_QUOTA_REACHED") {
89
- console.err("Browser storage quota exceeded");
195
+ if (err.code === 22 || err.code === 1014 || err.name === 'QuotaExceededError' || err.name === 'NS_ERROR_DOM_QUOTA_REACHED') {
196
+ console.err('Browser storage quota exceeded');
90
197
  } else {
91
198
  console.err(err);
92
199
  }
93
200
  }
94
201
  }
95
202
  }, [DATASET_STORAGE_KEY, canOverrideSettings, settings]);
96
- return /*#__PURE__*/React.createElement(SettingsContext.Provider, {
97
- value: settings
98
- }, /*#__PURE__*/React.createElement(SettingsDispatchContext.Provider, {
99
- value: dispatch
100
- }, children));
203
+ return /*#__PURE__*/_jsx(SettingsContext.Provider, {
204
+ value: settings,
205
+ children: /*#__PURE__*/_jsx(SettingsDispatchContext.Provider, {
206
+ value: dispatch,
207
+ children: settings && children
208
+ })
209
+ });
101
210
  }
102
211
  export function useSettings() {
103
212
  return useContext(SettingsContext);
@@ -105,13 +214,70 @@ export function useSettings() {
105
214
  export function useSettingsDispatch() {
106
215
  return useContext(SettingsDispatchContext);
107
216
  }
217
+ const OBS_DATA_KEYS = ['name', 'type',
218
+ // categorical and numerical
219
+ 'codes', 'codesMap', 'values', 'n_values', 'value_counts',
220
+ // numerical
221
+ 'bins', 'min', 'max', 'mean', 'median', 'n_unique'];
222
+ const splitObs = obs => {
223
+ if (!obs) return {
224
+ settings: null,
225
+ data: {}
226
+ };
227
+ const settings = _.pick(obs, ['name', 'omit', 'bins']);
228
+ const data = obs ? {
229
+ [obs.name]: _.pick(obs, OBS_DATA_KEYS)
230
+ } : {};
231
+ return {
232
+ settings,
233
+ data
234
+ };
235
+ };
236
+ const splitVar = v => {
237
+ if (!v) return {
238
+ settings: null,
239
+ data: {}
240
+ };
241
+ let settings, data;
242
+ if (v.isSet) {
243
+ settings = _objectSpread(_objectSpread({}, _.pick(v, ['name', 'isSet'])), {}, {
244
+ vars: _.map(v.vars, vv => ({
245
+ name: vv.name
246
+ }))
247
+ });
248
+ data = _.fromPairs(_.map(v.vars, vv => [vv.name, _.pick(vv, ['name', 'index', 'matrix_index'])]));
249
+ } else {
250
+ settings = _.pick(v, ['name', 'isSet']);
251
+ data = {
252
+ [v.name]: _.pick(v, ['name', 'index', 'matrix_index'])
253
+ };
254
+ }
255
+ return {
256
+ settings,
257
+ data
258
+ };
259
+ };
108
260
  function settingsReducer(settings, action) {
109
261
  switch (action.type) {
110
- case "select.obs":
262
+ case 'init':
263
+ {
264
+ return action.settings;
265
+ }
266
+ case 'select.obs':
111
267
  {
112
268
  var _action$obs;
113
- return _objectSpread(_objectSpread({}, settings), {}, {
114
- selectedObs: action.obs,
269
+ const {
270
+ settings: obsSettings,
271
+ data: obsData
272
+ } = splitObs(action.obs);
273
+ return _objectSpread(_objectSpread(_objectSpread({}, settings), action.obs ? {
274
+ selectedObs: obsSettings,
275
+ data: _objectSpread(_objectSpread({}, settings.data), {}, {
276
+ obs: _objectSpread(_objectSpread({}, settings.data.obs), obsData)
277
+ })
278
+ } : {
279
+ selectedObs: null
280
+ }), {}, {
115
281
  controls: _objectSpread(_objectSpread({}, settings.controls), {}, {
116
282
  range: ((_action$obs = action.obs) === null || _action$obs === void 0 ? void 0 : _action$obs.type) === OBS_TYPES.CATEGORICAL ? [0, 1] : settings.controls.range
117
283
  }),
@@ -121,108 +287,124 @@ function settingsReducer(settings, action) {
121
287
  })
122
288
  });
123
289
  }
124
- case "select.obsm":
290
+ case 'select.obsm':
125
291
  {
126
292
  return _objectSpread(_objectSpread({}, settings), {}, {
127
293
  selectedObsm: action.obsm
128
294
  });
129
295
  }
130
- case "select.var":
296
+ case 'select.var':
131
297
  {
132
- if (settings.vars.find(v => _.isEqual(v, action.var))) {
133
- return _objectSpread(_objectSpread({}, settings), {}, {
134
- selectedVar: action.var
135
- });
136
- } else {
137
- return _objectSpread(_objectSpread({}, settings), {}, {
138
- selectedVar: action.var,
139
- vars: [...settings.vars, action.var]
140
- });
141
- }
298
+ const {
299
+ settings: varSettings,
300
+ data: varData
301
+ } = splitVar(action.var);
302
+ return validateSettings(_objectSpread(_objectSpread({}, settings), {}, {
303
+ selectedVar: varSettings,
304
+ data: _objectSpread(_objectSpread({}, settings.data), {}, {
305
+ vars: _objectSpread(_objectSpread({}, settings.data.vars), varData)
306
+ })
307
+ }));
142
308
  }
143
- case "select.multivar":
309
+ case 'select.multivar':
144
310
  {
145
- const vars = settings.vars.find(v => _.isEqual(v, action.var)) ? settings.vars : [...settings.vars, action.var];
146
- if (settings.selectedMultiVar.find(v => _.isEqual(v, action.var))) {
147
- return _objectSpread(_objectSpread({}, settings), {}, {
148
- vars: vars
149
- });
311
+ const inMultiVar = settings.selectedMultiVar.some(v => v.name === action.var.name);
312
+ if (inMultiVar) {
313
+ return validateSettings(_objectSpread({}, settings));
150
314
  } else {
151
- return _objectSpread(_objectSpread({}, settings), {}, {
152
- selectedMultiVar: [...settings.selectedMultiVar, action.var],
153
- vars: vars
154
- });
315
+ const {
316
+ settings: varSettings,
317
+ data: varData
318
+ } = splitVar(action.var);
319
+ return validateSettings(_objectSpread(_objectSpread({}, settings), {}, {
320
+ selectedMultiVar: [...settings.selectedMultiVar, varSettings],
321
+ data: _objectSpread(_objectSpread({}, settings.data), {}, {
322
+ vars: _objectSpread(_objectSpread({}, settings.data.vars), varData)
323
+ })
324
+ }));
155
325
  }
156
326
  }
157
- case "deselect.multivar":
327
+ case 'deselect.multivar':
158
328
  {
159
- return _objectSpread(_objectSpread({}, settings), {}, {
329
+ return validateSettings(_objectSpread(_objectSpread({}, settings), {}, {
160
330
  selectedMultiVar: settings.selectedMultiVar.filter(v => v !== action.var.name)
161
- });
331
+ }));
162
332
  }
163
- case "toggle.multivar":
333
+ case 'toggle.multivar':
164
334
  {
165
335
  const inMultiVar = settings.selectedMultiVar.some(v => v.name === action.var.name);
166
336
  if (inMultiVar) {
167
- return _objectSpread(_objectSpread({}, settings), {}, {
337
+ return validateSettings(_objectSpread(_objectSpread({}, settings), {}, {
168
338
  selectedMultiVar: settings.selectedMultiVar.filter(v => v.name !== action.var.name)
169
- });
339
+ }));
170
340
  } else {
171
- return _objectSpread(_objectSpread({}, settings), {}, {
172
- selectedMultiVar: [...settings.selectedMultiVar, action.var]
173
- });
341
+ const {
342
+ settings: varSettings,
343
+ data: varData
344
+ } = splitVar(action.var);
345
+ return validateSettings(_objectSpread(_objectSpread({}, settings), {}, {
346
+ selectedMultiVar: [...settings.selectedMultiVar, varSettings],
347
+ data: _objectSpread(_objectSpread({}, settings.data), {}, {
348
+ vars: _objectSpread(_objectSpread({}, settings.data.vars), varData)
349
+ })
350
+ }));
174
351
  }
175
352
  }
176
- case "set.colorEncoding":
353
+ case 'set.colorEncoding':
177
354
  {
178
- return _objectSpread(_objectSpread({}, settings), {}, {
355
+ return validateSettings(_objectSpread(_objectSpread({}, settings), {}, {
179
356
  colorEncoding: action.value
180
- });
357
+ }));
181
358
  }
182
- case "reset.vars":
359
+ case 'reset.vars':
183
360
  {
184
- return _objectSpread(_objectSpread({}, settings), {}, {
361
+ return validateSettings(_objectSpread(_objectSpread({}, settings), {}, {
185
362
  vars: [],
186
363
  selectedVar: null,
187
364
  selectedMultiVar: []
188
- });
365
+ }));
189
366
  }
190
- case "reset.multiVar":
367
+ case 'reset.multiVar':
191
368
  {
192
- return _objectSpread(_objectSpread({}, settings), {}, {
193
- selectedMultiVar: [],
194
- colorEncoding: settings.colorEncoding === COLOR_ENCODINGS.VAR ? null : settings.colorEncoding
195
- });
369
+ return validateSettings(_objectSpread(_objectSpread({}, settings), {}, {
370
+ selectedMultiVar: []
371
+ }));
196
372
  }
197
- case "reset.var":
373
+ case 'reset.var':
198
374
  {
199
- return _objectSpread(_objectSpread({}, settings), {}, {
200
- selectedVar: null,
201
- colorEncoding: settings.colorEncoding === COLOR_ENCODINGS.VAR ? null : settings.colorEncoding
202
- });
375
+ return validateSettings(_objectSpread(_objectSpread({}, settings), {}, {
376
+ selectedVar: null
377
+ }));
203
378
  }
204
- case "add.var":
379
+ case 'add.var':
205
380
  {
206
381
  if (settings.vars.find(v => v.name === action.var.name)) {
207
382
  return settings;
208
383
  } else {
384
+ const {
385
+ settings: varSettings,
386
+ data: varData
387
+ } = splitVar(action.var);
209
388
  return _objectSpread(_objectSpread({}, settings), {}, {
210
- vars: [...settings.vars, action.var]
389
+ vars: [...settings.vars, varSettings],
390
+ data: _objectSpread(_objectSpread({}, settings.data), {}, {
391
+ vars: _objectSpread(_objectSpread({}, settings.data.vars), varData)
392
+ })
211
393
  });
212
394
  }
213
395
  }
214
- case "remove.var":
396
+ case 'remove.var':
215
397
  {
216
398
  var _settings$selectedVar;
217
399
  const selectedVar = ((_settings$selectedVar = settings.selectedVar) === null || _settings$selectedVar === void 0 ? void 0 : _settings$selectedVar.name) === action.var.name ? null : settings.selectedVar;
218
400
  const selectedMultiVar = settings.selectedMultiVar.filter(v => v.name !== action.var.name);
219
- return _objectSpread(_objectSpread({}, settings), {}, {
401
+ return validateSettings(_objectSpread(_objectSpread({}, settings), {}, {
220
402
  vars: settings.vars.filter(a => a.name !== action.var.name),
221
403
  selectedVar: selectedVar,
222
404
  selectedMultiVar: selectedMultiVar
223
- });
405
+ }));
224
406
  }
225
- case "add.varSet.var":
407
+ case 'add.varSet.var':
226
408
  {
227
409
  const varSet = settings.vars.find(s => s.isSet && s.name === action.varSet.name);
228
410
  if (!varSet) {
@@ -232,7 +414,11 @@ function settingsReducer(settings, action) {
232
414
  return settings;
233
415
  } else {
234
416
  var _settings$selectedVar2;
235
- const varSetVars = [...varSet.vars, action.var];
417
+ const {
418
+ settings: varSettings,
419
+ data: varData
420
+ } = splitVar(action.var);
421
+ const varSetVars = [...varSet.vars, varSettings];
236
422
  const vars = settings.vars.map(v => {
237
423
  if (v.name === varSet.name) {
238
424
  return _objectSpread(_objectSpread({}, v), {}, {
@@ -254,14 +440,17 @@ function settingsReducer(settings, action) {
254
440
  return v;
255
441
  }
256
442
  });
257
- return _objectSpread(_objectSpread({}, settings), {}, {
443
+ return validateSettings(_objectSpread(_objectSpread({}, settings), {}, {
258
444
  vars: vars,
259
445
  selectedVar: selectedVar,
260
- selectedMultiVar: selectedMultiVar
261
- });
446
+ selectedMultiVar: selectedMultiVar,
447
+ data: _objectSpread(_objectSpread({}, settings.data), {}, {
448
+ vars: _objectSpread(_objectSpread({}, settings.data.vars), varData)
449
+ })
450
+ }));
262
451
  }
263
452
  }
264
- case "remove.varSet.var":
453
+ case 'remove.varSet.var':
265
454
  {
266
455
  const varSet = settings.vars.find(s => s.isSet && s.name === action.varSet.name);
267
456
  if (!varSet) {
@@ -285,11 +474,11 @@ function settingsReducer(settings, action) {
285
474
  var _settings$selectedVar3;
286
475
  const selectedVar = ((_settings$selectedVar3 = settings.selectedVar) === null || _settings$selectedVar3 === void 0 ? void 0 : _settings$selectedVar3.name) === action.varSet.name ? null : settings.selectedVar;
287
476
  const selectedMultiVar = settings.selectedMultiVar.filter(v => v.name !== action.varSet.name);
288
- return _objectSpread(_objectSpread({}, settings), {}, {
477
+ return validateSettings(_objectSpread(_objectSpread({}, settings), {}, {
289
478
  vars: vars,
290
479
  selectedVar: selectedVar,
291
480
  selectedMultiVar: selectedMultiVar
292
- });
481
+ }));
293
482
  } else {
294
483
  var _settings$selectedVar4;
295
484
  // Update selected if varSet is selected
@@ -305,15 +494,15 @@ function settingsReducer(settings, action) {
305
494
  return v;
306
495
  }
307
496
  });
308
- return _objectSpread(_objectSpread({}, settings), {}, {
497
+ return validateSettings(_objectSpread(_objectSpread({}, settings), {}, {
309
498
  vars: vars,
310
499
  selectedVar: selectedVar,
311
500
  selectedMultiVar: selectedMultiVar
312
- });
501
+ }));
313
502
  }
314
503
  }
315
504
  }
316
- case "set.controls.colorScale":
505
+ case 'set.controls.colorScale':
317
506
  {
318
507
  return _objectSpread(_objectSpread({}, settings), {}, {
319
508
  controls: _objectSpread(_objectSpread({}, settings.controls), {}, {
@@ -321,15 +510,7 @@ function settingsReducer(settings, action) {
321
510
  })
322
511
  });
323
512
  }
324
- case "set.controls.valueRange":
325
- {
326
- return _objectSpread(_objectSpread({}, settings), {}, {
327
- controls: _objectSpread(_objectSpread({}, settings.controls), {}, {
328
- valueRange: action.valueRange
329
- })
330
- });
331
- }
332
- case "set.controls.range":
513
+ case 'set.controls.range':
333
514
  {
334
515
  return _objectSpread(_objectSpread({}, settings), {}, {
335
516
  controls: _objectSpread(_objectSpread({}, settings.controls), {}, {
@@ -337,7 +518,7 @@ function settingsReducer(settings, action) {
337
518
  })
338
519
  });
339
520
  }
340
- case "set.controls.colorAxis":
521
+ case 'set.controls.colorAxis':
341
522
  {
342
523
  return _objectSpread(_objectSpread({}, settings), {}, {
343
524
  controls: _objectSpread(_objectSpread({}, settings.controls), {}, {
@@ -345,7 +526,7 @@ function settingsReducer(settings, action) {
345
526
  })
346
527
  });
347
528
  }
348
- case "set.controls.colorAxis.crange":
529
+ case 'set.controls.colorAxis.crange':
349
530
  {
350
531
  return _objectSpread(_objectSpread({}, settings), {}, {
351
532
  controls: _objectSpread(_objectSpread({}, settings.controls), {}, {
@@ -356,7 +537,7 @@ function settingsReducer(settings, action) {
356
537
  })
357
538
  });
358
539
  }
359
- case "set.controls.colorAxis.cmin":
540
+ case 'set.controls.colorAxis.cmin':
360
541
  {
361
542
  return _objectSpread(_objectSpread({}, settings), {}, {
362
543
  controls: _objectSpread(_objectSpread({}, settings.controls), {}, {
@@ -366,7 +547,7 @@ function settingsReducer(settings, action) {
366
547
  })
367
548
  });
368
549
  }
369
- case "set.controls.colorAxis.cmax":
550
+ case 'set.controls.colorAxis.cmax':
370
551
  {
371
552
  return _objectSpread(_objectSpread({}, settings), {}, {
372
553
  controls: _objectSpread(_objectSpread({}, settings.controls), {}, {
@@ -376,7 +557,7 @@ function settingsReducer(settings, action) {
376
557
  })
377
558
  });
378
559
  }
379
- case "set.controls.scale":
560
+ case 'set.controls.scale':
380
561
  {
381
562
  return _objectSpread(_objectSpread({}, settings), {}, {
382
563
  controls: _objectSpread(_objectSpread({}, settings.controls), {}, {
@@ -386,7 +567,7 @@ function settingsReducer(settings, action) {
386
567
  })
387
568
  });
388
569
  }
389
- case "set.controls.meanOnlyExpressed":
570
+ case 'set.controls.meanOnlyExpressed':
390
571
  {
391
572
  return _objectSpread(_objectSpread({}, settings), {}, {
392
573
  controls: _objectSpread(_objectSpread({}, settings.controls), {}, {
@@ -394,7 +575,7 @@ function settingsReducer(settings, action) {
394
575
  })
395
576
  });
396
577
  }
397
- case "set.controls.expressionCutoff":
578
+ case 'set.controls.expressionCutoff':
398
579
  {
399
580
  return _objectSpread(_objectSpread({}, settings), {}, {
400
581
  controls: _objectSpread(_objectSpread({}, settings.controls), {}, {
@@ -402,24 +583,31 @@ function settingsReducer(settings, action) {
402
583
  })
403
584
  });
404
585
  }
405
- case "toggle.slice.obs":
586
+ case 'toggle.slice.obs':
406
587
  {
407
- if (_.isEqual(settings.selectedObs, action.obs)) {
588
+ if (settings.selectedObs && settings.selectedObs.name === action.obs.name) {
408
589
  return _objectSpread(_objectSpread({}, settings), {}, {
409
590
  sliceBy: _objectSpread(_objectSpread({}, settings.sliceBy), {}, {
410
591
  obs: !settings.sliceBy.obs
411
592
  })
412
593
  });
413
594
  } else {
595
+ const {
596
+ settings: obsSettings,
597
+ data: obsData
598
+ } = splitObs(action.obs);
414
599
  return _objectSpread(_objectSpread({}, settings), {}, {
415
- selectedObs: action.obs,
600
+ selectedObs: obsSettings,
601
+ data: _objectSpread(_objectSpread({}, settings.data), {}, {
602
+ obs: _objectSpread(_objectSpread({}, settings.data.obs), obsData)
603
+ }),
416
604
  sliceBy: _objectSpread(_objectSpread({}, settings.sliceBy), {}, {
417
605
  obs: true
418
606
  })
419
607
  });
420
608
  }
421
609
  }
422
- case "toggle.slice.polygons":
610
+ case 'toggle.slice.polygons':
423
611
  {
424
612
  return _objectSpread(_objectSpread({}, settings), {}, {
425
613
  sliceBy: _objectSpread(_objectSpread({}, settings.sliceBy), {}, {
@@ -427,7 +615,7 @@ function settingsReducer(settings, action) {
427
615
  })
428
616
  });
429
617
  }
430
- case "disable.slice.polygons":
618
+ case 'disable.slice.polygons':
431
619
  {
432
620
  return _objectSpread(_objectSpread({}, settings), {}, {
433
621
  sliceBy: _objectSpread(_objectSpread({}, settings.sliceBy), {}, {
@@ -435,29 +623,36 @@ function settingsReducer(settings, action) {
435
623
  })
436
624
  });
437
625
  }
438
- case "add.label.obs":
626
+ case 'add.label.obs':
439
627
  {
440
- if (settings.labelObs.find(i => _.isEqual(i, action.obs))) {
628
+ if (_.includes(settings.labelObs, action.obs.name)) {
441
629
  return settings;
442
630
  } else {
631
+ const {
632
+ settings: obsSettings,
633
+ data: obsData
634
+ } = splitObs(action.obs);
443
635
  return _objectSpread(_objectSpread({}, settings), {}, {
444
- labelObs: [...settings.labelObs, action.obs]
636
+ labelObs: [...settings.labelObs, obsSettings.name],
637
+ data: _objectSpread(_objectSpread({}, settings.data), {}, {
638
+ obs: _objectSpread(_objectSpread({}, settings.data.obs), obsData)
639
+ })
445
640
  });
446
641
  }
447
642
  }
448
- case "remove.label.obs":
643
+ case 'remove.label.obs':
449
644
  {
450
- return _objectSpread(_objectSpread({}, settings), {}, {
451
- labelObs: settings.labelObs.filter(a => a.name !== action.obsName)
452
- });
645
+ return validateSettings(_objectSpread(_objectSpread({}, settings), {}, {
646
+ labelObs: settings.labelObs.filter(a => a !== action.obsName)
647
+ }));
453
648
  }
454
- case "reset.label.obs":
649
+ case 'reset.label.obs':
455
650
  {
456
- return _objectSpread(_objectSpread({}, settings), {}, {
651
+ return validateSettings(_objectSpread(_objectSpread({}, settings), {}, {
457
652
  labelObs: []
458
- });
653
+ }));
459
654
  }
460
- case "set.varSort":
655
+ case 'set.varSort':
461
656
  {
462
657
  return _objectSpread(_objectSpread({}, settings), {}, {
463
658
  varSort: _objectSpread(_objectSpread({}, settings.varSort), {}, {
@@ -468,7 +663,7 @@ function settingsReducer(settings, action) {
468
663
  })
469
664
  });
470
665
  }
471
- case "set.varSort.sort":
666
+ case 'set.varSort.sort':
472
667
  {
473
668
  return _objectSpread(_objectSpread({}, settings), {}, {
474
669
  varSort: _objectSpread(_objectSpread({}, settings.varSort), {}, {
@@ -478,7 +673,7 @@ function settingsReducer(settings, action) {
478
673
  })
479
674
  });
480
675
  }
481
- case "set.varSort.sortOrder":
676
+ case 'set.varSort.sortOrder':
482
677
  {
483
678
  return _objectSpread(_objectSpread({}, settings), {}, {
484
679
  varSort: _objectSpread(_objectSpread({}, settings.varSort), {}, {
@@ -488,7 +683,7 @@ function settingsReducer(settings, action) {
488
683
  })
489
684
  });
490
685
  }
491
- case "set.polygons":
686
+ case 'set.polygons':
492
687
  {
493
688
  return _objectSpread(_objectSpread({}, settings), {}, {
494
689
  polygons: _objectSpread(_objectSpread({}, settings.polygons), {}, {
@@ -496,7 +691,7 @@ function settingsReducer(settings, action) {
496
691
  })
497
692
  });
498
693
  }
499
- case "set.pseudospatial.maskSet":
694
+ case 'set.pseudospatial.maskSet':
500
695
  {
501
696
  return _objectSpread(_objectSpread({}, settings), {}, {
502
697
  pseudospatial: _objectSpread(_objectSpread({}, settings.pseudospatial), {}, {
@@ -504,7 +699,7 @@ function settingsReducer(settings, action) {
504
699
  })
505
700
  });
506
701
  }
507
- case "set.pseudospatial.maskValues":
702
+ case 'set.pseudospatial.maskValues':
508
703
  {
509
704
  return _objectSpread(_objectSpread({}, settings), {}, {
510
705
  pseudospatial: _objectSpread(_objectSpread({}, settings.pseudospatial), {}, {
@@ -512,7 +707,7 @@ function settingsReducer(settings, action) {
512
707
  })
513
708
  });
514
709
  }
515
- case "set.pseudospatial.categoricalMode":
710
+ case 'set.pseudospatial.categoricalMode':
516
711
  {
517
712
  return _objectSpread(_objectSpread({}, settings), {}, {
518
713
  pseudospatial: _objectSpread(_objectSpread({}, settings.pseudospatial), {}, {
@@ -520,9 +715,29 @@ function settingsReducer(settings, action) {
520
715
  })
521
716
  });
522
717
  }
718
+ case 'toggle.pseudospatial.refImg.visible':
719
+ {
720
+ return _objectSpread(_objectSpread({}, settings), {}, {
721
+ pseudospatial: _objectSpread(_objectSpread({}, settings.pseudospatial), {}, {
722
+ refImg: _objectSpread(_objectSpread({}, settings.pseudospatial.refImg), {}, {
723
+ visible: !settings.pseudospatial.refImg.visible
724
+ })
725
+ })
726
+ });
727
+ }
728
+ case 'set.pseudospatial.refImg.opacity':
729
+ {
730
+ return _objectSpread(_objectSpread({}, settings), {}, {
731
+ pseudospatial: _objectSpread(_objectSpread({}, settings.pseudospatial), {}, {
732
+ refImg: _objectSpread(_objectSpread({}, settings.pseudospatial.refImg), {}, {
733
+ opacity: action.opacity
734
+ })
735
+ })
736
+ });
737
+ }
523
738
  default:
524
739
  {
525
- throw Error("Unknown action: " + action.type);
740
+ throw Error('Unknown action: ' + action.type);
526
741
  }
527
742
  }
528
743
  }