@haniffalab/cherita-react 1.3.0-dev.2025-06-06.f1eddad0 → 1.3.1

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