@haniffalab/cherita-react 1.3.0 → 1.3.1-dev.2025-10-29.6de4119f

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