@haniffalab/cherita-react 0.2.0-dev.2024-12-16.f02cfae4 → 0.2.0-dev.2024-12-16.67617f27

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.
@@ -9,6 +9,7 @@ var _lodash = _interopRequireDefault(require("lodash"));
9
9
  var _reactBootstrap = require("react-bootstrap");
10
10
  var _reactPlotly = _interopRequireDefault(require("react-plotly.js"));
11
11
  var _DatasetContext = require("../../context/DatasetContext");
12
+ var _FilterContext = require("../../context/FilterContext");
12
13
  var _LoadingIndicators = require("../../utils/LoadingIndicators");
13
14
  var _requests = require("../../utils/requests");
14
15
  var _jsxRuntime = require("react/jsx-runtime");
@@ -18,6 +19,8 @@ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e;
18
19
  function Dotplot() {
19
20
  const ENDPOINT = "dotplot";
20
21
  const dataset = (0, _DatasetContext.useDataset)();
22
+ const filteredData = (0, _FilterContext.useFilteredData)();
23
+ const isSliced = dataset.sliceBy.obs || dataset.sliceBy.polygons;
21
24
  const dispatch = (0, _DatasetContext.useDatasetDispatch)();
22
25
  const colorscale = (0, _react.useRef)(dataset.controls.colorScale);
23
26
  const [data, setData] = (0, _react.useState)([]);
@@ -31,6 +34,7 @@ function Dotplot() {
31
34
  name: i.name,
32
35
  indices: i.vars.map(v => v.index)
33
36
  } : i.index),
37
+ obsIndices: isSliced ? [...(filteredData.obsIndices || [])] : null,
34
38
  standardScale: dataset.controls.standardScale,
35
39
  meanOnlyExpressed: dataset.controls.meanOnlyExpressed,
36
40
  expressionCutoff: dataset.controls.expressionCutoff,
@@ -54,13 +58,14 @@ function Dotplot() {
54
58
  name: i.name,
55
59
  indices: i.vars.map(v => v.index)
56
60
  } : i.index),
61
+ obsIndices: isSliced ? [...(filteredData.obsIndices || [])] : null,
57
62
  standardScale: dataset.controls.standardScale,
58
63
  meanOnlyExpressed: dataset.controls.meanOnlyExpressed,
59
64
  expressionCutoff: dataset.controls.expressionCutoff,
60
65
  varNamesCol: dataset.varNamesCol
61
66
  };
62
67
  });
63
- }, [dataset.url, dataset.selectedObs, dataset.selectedMultiVar, dataset.controls.standardScale, dataset.controls.meanOnlyExpressed, dataset.controls.expressionCutoff, dataset.varNamesCol]);
68
+ }, [dataset.url, dataset.selectedObs, dataset.selectedMultiVar, dataset.controls.standardScale, dataset.controls.meanOnlyExpressed, dataset.controls.expressionCutoff, dataset.varNamesCol, isSliced, filteredData.obsIndices]);
64
69
  const updateColorscale = (0, _react.useCallback)(colorscale => {
65
70
  setLayout(l => {
66
71
  return {
@@ -4,12 +4,16 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.FullPage = FullPage;
7
+ exports.FullPagePlots = FullPagePlots;
7
8
  exports.FullPagePseudospatial = FullPagePseudospatial;
8
9
  exports.FullPageScatterplot = FullPageScatterplot;
9
10
  var _react = _interopRequireWildcard(require("react"));
10
11
  var _reactBootstrap = require("react-bootstrap");
11
12
  var _constants = require("../../constants/constants");
12
13
  var _DatasetContext = require("../../context/DatasetContext");
14
+ var _Dotplot = require("../dotplot/Dotplot");
15
+ var _Heatmap = require("../heatmap/Heatmap");
16
+ var _Matrixplot = require("../matrixplot/Matrixplot");
13
17
  var _ObsList = require("../obs-list/ObsList");
14
18
  var _offcanvas = require("../offcanvas");
15
19
  var _Pseudospatial = require("../pseudospatial/Pseudospatial");
@@ -17,12 +21,14 @@ var _Scatterplot = require("../scatterplot/Scatterplot");
17
21
  var _ScatterplotControls = require("../scatterplot/ScatterplotControls");
18
22
  var _SearchBar = require("../search-bar/SearchBar");
19
23
  var _VarList = require("../var-list/VarList");
24
+ var _Violin = require("../violin/Violin");
20
25
  var _jsxRuntime = require("react/jsx-runtime");
21
26
  function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
22
27
  function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
23
28
  function FullPage(_ref) {
24
29
  let {
25
30
  children,
31
+ varMode = _constants.SELECTION_MODES.SINGLE,
26
32
  ...props
27
33
  } = _ref;
28
34
  const targetRef = (0, _react.useRef)();
@@ -111,7 +117,7 @@ function FullPage(_ref) {
111
117
  searchDiseases: true,
112
118
  searchVar: true
113
119
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_VarList.VarNamesList, {
114
- mode: _constants.SELECTION_MODES.SINGLE
120
+ mode: varMode
115
121
  })]
116
122
  })
117
123
  })
@@ -174,4 +180,28 @@ function FullPagePseudospatial(props) {
174
180
  })
175
181
  })
176
182
  });
183
+ }
184
+ function FullPagePlots(props) {
185
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(FullPage, {
186
+ ...props,
187
+ varMode: _constants.SELECTION_MODES.MULTIPLE,
188
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
189
+ className: "container-fluid w-100 h-100 d-flex flex-column overflow-y-auto",
190
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
191
+ className: "row flex-grow-1",
192
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Heatmap.Heatmap, {})
193
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
194
+ className: "row flex-grow-1",
195
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Matrixplot.Matrixplot, {})
196
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
197
+ className: "row flex-grow-1",
198
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Dotplot.Dotplot, {})
199
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
200
+ className: "row flex-grow-1",
201
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Violin.Violin, {
202
+ mode: _constants.VIOLIN_MODES.GROUPBY
203
+ })
204
+ })]
205
+ })
206
+ });
177
207
  }
@@ -9,6 +9,7 @@ var _lodash = _interopRequireDefault(require("lodash"));
9
9
  var _reactBootstrap = require("react-bootstrap");
10
10
  var _reactPlotly = _interopRequireDefault(require("react-plotly.js"));
11
11
  var _DatasetContext = require("../../context/DatasetContext");
12
+ var _FilterContext = require("../../context/FilterContext");
12
13
  var _LoadingIndicators = require("../../utils/LoadingIndicators");
13
14
  var _requests = require("../../utils/requests");
14
15
  var _jsxRuntime = require("react/jsx-runtime");
@@ -18,6 +19,8 @@ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e;
18
19
  function Heatmap() {
19
20
  const ENDPOINT = "heatmap";
20
21
  const dataset = (0, _DatasetContext.useDataset)();
22
+ const filteredData = (0, _FilterContext.useFilteredData)();
23
+ const isSliced = dataset.sliceBy.obs || dataset.sliceBy.polygons;
21
24
  const colorscale = (0, _react.useRef)(dataset.controls.colorScale);
22
25
  const [data, setData] = (0, _react.useState)([]);
23
26
  const [layout, setLayout] = (0, _react.useState)({});
@@ -30,6 +33,7 @@ function Heatmap() {
30
33
  name: i.name,
31
34
  indices: i.vars.map(v => v.index)
32
35
  } : i.index),
36
+ obsIndices: isSliced ? [...(filteredData.obsIndices || [])] : null,
33
37
  varNamesCol: dataset.varNamesCol
34
38
  });
35
39
  (0, _react.useEffect)(() => {
@@ -48,10 +52,11 @@ function Heatmap() {
48
52
  name: i.name,
49
53
  indices: i.vars.map(v => v.index)
50
54
  } : i.index),
55
+ obsIndices: isSliced ? [...(filteredData.obsIndices || [])] : null,
51
56
  varNamesCol: dataset.varNamesCol
52
57
  };
53
58
  });
54
- }, [dataset.selectedMultiVar, dataset.selectedObs, dataset.url, dataset.varNamesCol]);
59
+ }, [dataset.selectedMultiVar, dataset.selectedObs, dataset.url, dataset.varNamesCol, filteredData.obsIndices, isSliced]);
55
60
  const updateColorscale = (0, _react.useCallback)(colorscale => {
56
61
  setLayout(l => {
57
62
  return {
@@ -9,6 +9,7 @@ var _lodash = _interopRequireDefault(require("lodash"));
9
9
  var _reactBootstrap = require("react-bootstrap");
10
10
  var _reactPlotly = _interopRequireDefault(require("react-plotly.js"));
11
11
  var _DatasetContext = require("../../context/DatasetContext");
12
+ var _FilterContext = require("../../context/FilterContext");
12
13
  var _LoadingIndicators = require("../../utils/LoadingIndicators");
13
14
  var _requests = require("../../utils/requests");
14
15
  var _jsxRuntime = require("react/jsx-runtime");
@@ -18,6 +19,8 @@ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e;
18
19
  function Matrixplot() {
19
20
  const ENDPOINT = "matrixplot";
20
21
  const dataset = (0, _DatasetContext.useDataset)();
22
+ const filteredData = (0, _FilterContext.useFilteredData)();
23
+ const isSliced = dataset.sliceBy.obs || dataset.sliceBy.polygons;
21
24
  const colorscale = (0, _react.useRef)(dataset.controls.colorScale);
22
25
  const [data, setData] = (0, _react.useState)([]);
23
26
  const [layout, setLayout] = (0, _react.useState)({});
@@ -30,6 +33,7 @@ function Matrixplot() {
30
33
  name: i.name,
31
34
  indices: i.vars.map(v => v.index)
32
35
  } : i.index),
36
+ obsIndices: isSliced ? [...(filteredData.obsIndices || [])] : null,
33
37
  standardScale: dataset.controls.standardScale,
34
38
  varNamesCol: dataset.varNamesCol
35
39
  });
@@ -49,11 +53,12 @@ function Matrixplot() {
49
53
  name: i.name,
50
54
  indices: i.vars.map(v => v.index)
51
55
  } : i.index),
56
+ obsIndices: isSliced ? [...(filteredData.obsIndices || [])] : null,
52
57
  standardScale: dataset.controls.standardScale,
53
58
  varNamesCol: dataset.varNamesCol
54
59
  };
55
60
  });
56
- }, [dataset.controls.standardScale, dataset.selectedMultiVar, dataset.selectedObs, dataset.url, dataset.varNamesCol]);
61
+ }, [dataset.controls.standardScale, dataset.selectedMultiVar, dataset.selectedObs, dataset.url, dataset.varNamesCol, filteredData.obsIndices, isSliced]);
57
62
  const updateColorscale = (0, _react.useCallback)(colorscale => {
58
63
  setLayout(l => {
59
64
  return {
@@ -11,8 +11,11 @@ var _xCharts = require("@mui/x-charts");
11
11
  var _lodash = _interopRequireDefault(require("lodash"));
12
12
  var _reactBootstrap = require("react-bootstrap");
13
13
  var _ObsToolbar = require("./ObsToolbar");
14
+ var _constants = require("../../constants/constants");
14
15
  var _DatasetContext = require("../../context/DatasetContext");
16
+ var _FilterContext = require("../../context/FilterContext");
15
17
  var _colorHelper = require("../../helpers/color-helper");
18
+ var _Histogram = require("../../utils/Histogram");
16
19
  var _LoadingIndicators = require("../../utils/LoadingIndicators");
17
20
  var _requests = require("../../utils/requests");
18
21
  var _string = require("../../utils/string");
@@ -22,8 +25,7 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
22
25
  function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
23
26
  function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
24
27
  const N_BINS = 5;
25
- function binContinuous(data) {
26
- let nBins = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : N_BINS;
28
+ function binContinuous(data, nBins) {
27
29
  const binSize = (data.max - data.min) * (1 / nBins);
28
30
  const thresholds = _lodash.default.range(nBins + 1).map(b => {
29
31
  return data.min + binSize * b;
@@ -40,21 +42,42 @@ function binContinuous(data) {
40
42
  bins: bins
41
43
  };
42
44
  }
43
- function binDiscrete(data) {
44
- let nBins = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : N_BINS;
45
- const binSize = _lodash.default.round(data.n_values * (1 / nBins));
46
- const bins = {
47
- nBins: nBins,
48
- binSize: binSize
49
- };
50
- return {
51
- ...data,
52
- bins: bins
53
- };
54
- }
55
45
  function getContinuousLabel(code, binEdges) {
56
46
  return `[ ${(0, _string.formatNumerical)(binEdges[code][0])}, ${(0, _string.formatNumerical)(binEdges[code][1], _string.FORMATS.EXPONENTIAL)}${code === binEdges.length - 1 ? " ]" : " )"}`;
57
47
  }
48
+ const useObsHistogram = obs => {
49
+ const ENDPOINT = "obs/histograms";
50
+ const dataset = (0, _DatasetContext.useDataset)();
51
+ const filteredData = (0, _FilterContext.useFilteredData)();
52
+ const isSliced = dataset.sliceBy.obs || dataset.sliceBy.polygons;
53
+ const [params, setParams] = (0, _react.useState)({
54
+ url: dataset.url,
55
+ obsCol: _lodash.default.omit(obs, "omit"),
56
+ // avoid re-rendering when toggling unselected obs
57
+ varKey: dataset.selectedVar?.isSet ? {
58
+ name: dataset.selectedVar?.name,
59
+ indices: dataset.selectedVar?.vars.map(v => v.index)
60
+ } : dataset.selectedVar?.index,
61
+ obsIndices: isSliced ? [...(filteredData.obsIndices || [])] : null
62
+ });
63
+ (0, _react.useEffect)(() => {
64
+ setParams(p => {
65
+ return {
66
+ ...p,
67
+ obsCol: _lodash.default.omit(obs, "omit"),
68
+ varKey: dataset.selectedVar?.isSet ? {
69
+ name: dataset.selectedVar?.name,
70
+ indices: dataset.selectedVar?.vars.map(v => v.index)
71
+ } : dataset.selectedVar?.index,
72
+ obsIndices: isSliced ? [...(filteredData.obsIndices || [])] : null
73
+ };
74
+ });
75
+ }, [dataset.selectedVar?.index, dataset.selectedVar?.isSet, dataset.selectedVar?.name, dataset.selectedVar?.vars, filteredData.obsIndices, isSliced, obs]);
76
+ return (0, _requests.useFetch)(ENDPOINT, params, {
77
+ enabled: !!dataset.selectedVar && dataset.colorEncoding === _constants.COLOR_ENCODINGS.VAR,
78
+ refetchOnMount: false
79
+ });
80
+ };
58
81
  function CategoricalItem(_ref) {
59
82
  let {
60
83
  value,
@@ -66,12 +89,18 @@ function CategoricalItem(_ref) {
66
89
  min,
67
90
  max,
68
91
  onChange,
92
+ histogramData = {
93
+ data: null,
94
+ isPending: false,
95
+ altColor: false
96
+ },
69
97
  showColor = true
70
98
  } = _ref;
71
99
  const {
72
100
  getColor
73
101
  } = (0, _colorHelper.useColor)();
74
102
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactBootstrap.ListGroup.Item, {
103
+ className: "obs-item",
75
104
  children: /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
76
105
  className: "d-flex align-items-center",
77
106
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
@@ -85,7 +114,11 @@ function CategoricalItem(_ref) {
85
114
  })
86
115
  }), /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
87
116
  className: "d-flex align-items-center",
88
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
117
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_Histogram.Histogram, {
118
+ data: histogramData.data,
119
+ isPending: histogramData.isPending,
120
+ altColor: histogramData.altColor
121
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
89
122
  className: "pl-1 m-0",
90
123
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_material.Tooltip, {
91
124
  title: `${(0, _string.formatNumerical)(pct, _string.FORMATS.EXPONENTIAL)}%`,
@@ -115,7 +148,7 @@ function CategoricalItem(_ref) {
115
148
  })]
116
149
  })
117
150
  })
118
- }), showColor && /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
151
+ }), showColor ? /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
119
152
  className: "pl-1",
120
153
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)("svg", {
121
154
  xmlns: "http://www.w3.org/2000/svg",
@@ -139,7 +172,7 @@ function CategoricalItem(_ref) {
139
172
  })})`
140
173
  })
141
174
  })
142
- })]
175
+ }) : null]
143
176
  })]
144
177
  })
145
178
  }, value);
@@ -160,6 +193,8 @@ function CategoricalObs(_ref2) {
160
193
  const totalCounts = _lodash.default.sum(_lodash.default.values(obs.value_counts));
161
194
  const min = _lodash.default.min(_lodash.default.values(obs.codes));
162
195
  const max = _lodash.default.max(_lodash.default.values(obs.codes));
196
+ const isSliced = dataset.sliceBy.obs || dataset.sliceBy.polygons;
197
+ const obsHistograms = useObsHistogram(obs);
163
198
  (0, _react.useEffect)(() => {
164
199
  if (dataset.selectedObs?.name === obs.name) {
165
200
  const selectedObsData = _lodash.default.omit(dataset.selectedObs, ["omit"]);
@@ -178,16 +213,25 @@ function CategoricalObs(_ref2) {
178
213
  }
179
214
  }
180
215
  }, [dataset.selectedObs, dispatch, obs, obs.name, updateObs]);
181
- const getDataAtIndex = index => {
216
+ const getDataAtIndex = (0, _react.useCallback)(index => {
182
217
  return {
183
218
  value: obs.values[index],
184
219
  code: obs.codes[obs.values[index]],
185
220
  value_counts: obs.value_counts[obs.values[index]],
186
221
  pct: obs.value_counts[obs.values[index]] / totalCounts * 100,
187
222
  isOmitted: _lodash.default.includes(obs.omit, obs.codes[obs.values[index]]),
188
- label: obs.values[index]
223
+ label: obs.values[index],
224
+ histogramData: dataset.colorEncoding === _constants.COLOR_ENCODINGS.VAR ? {
225
+ data: obsHistograms.fetchedData?.[obs.values[index]],
226
+ isPending: obsHistograms.isPending,
227
+ altColor: isSliced
228
+ } : {
229
+ data: null,
230
+ isPending: false
231
+ }
189
232
  };
190
- };
233
+ }, [dataset.colorEncoding, isSliced, obs.codes, obs.omit, obs.value_counts, obs.values, obsHistograms.fetchedData, obsHistograms.isPending, totalCounts]);
234
+ showColor &= dataset.colorEncoding === _constants.COLOR_ENCODINGS.OBS;
191
235
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactBootstrap.ListGroup, {
192
236
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactBootstrap.ListGroup.Item, {
193
237
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_ObsToolbar.ObsToolbar, {
@@ -312,7 +356,7 @@ function ContinuousObs(_ref4) {
312
356
  const ENDPOINT = "obs/bins";
313
357
  const dataset = (0, _DatasetContext.useDataset)();
314
358
  const dispatch = (0, _DatasetContext.useDatasetDispatch)();
315
- const binnedObs = binContinuous(obs);
359
+ const binnedObs = binContinuous(obs, _lodash.default.min([N_BINS, obs.n_unique]));
316
360
  const params = {
317
361
  url: dataset.url,
318
362
  obsCol: binnedObs.name,
@@ -25,6 +25,9 @@ function ObsColsList(_ref) {
25
25
  const dispatch = (0, _DatasetContext.useDatasetDispatch)();
26
26
  const [obsCols, setObsCols] = (0, _react.useState)(null);
27
27
  const [active, setActive] = (0, _react.useState)(dataset.selectedObs?.name);
28
+ const [expandedItems, setExpandedItems] = (0, _react.useState)(active ? {
29
+ [active]: true
30
+ } : {});
28
31
  const [params, setParams] = (0, _react.useState)({
29
32
  url: dataset.url
30
33
  });
@@ -79,6 +82,18 @@ function ObsColsList(_ref) {
79
82
  };
80
83
  });
81
84
  };
85
+ const handleAccordionToggle = itemName => {
86
+ _lodash.default.delay(
87
+ // to avoid contents of accordion disappearing while closing
88
+ () => {
89
+ setExpandedItems(prev => {
90
+ return {
91
+ ...prev,
92
+ [itemName]: !prev[itemName]
93
+ };
94
+ });
95
+ }, expandedItems[itemName] ? 250 : 0);
96
+ };
82
97
  const toggleAll = item => {
83
98
  const omit = item.omit.length ? [] : _lodash.default.map(item.values, v => item.codes[v]);
84
99
  setObsCols(o => {
@@ -168,9 +183,10 @@ function ObsColsList(_ref) {
168
183
  eventKey: item.name,
169
184
  className: active === item.name && dataset.colorEncoding === _constants.COLOR_ENCODINGS.OBS && "cherita-accordion-active",
170
185
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactBootstrap.Accordion.Header, {
186
+ onClick: () => handleAccordionToggle(item.name),
171
187
  children: item.name
172
188
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactBootstrap.Accordion.Body, {
173
- children: item.type === _constants.OBS_TYPES.CATEGORICAL || item.type === _constants.OBS_TYPES.BOOLEAN ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_ObsItem.CategoricalObs, {
189
+ children: expandedItems[item.name] && (item.type === _constants.OBS_TYPES.CATEGORICAL || item.type === _constants.OBS_TYPES.BOOLEAN ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_ObsItem.CategoricalObs, {
174
190
  obs: item,
175
191
  updateObs: updateObs,
176
192
  toggleAll: () => toggleAll(item),
@@ -187,7 +203,7 @@ function ObsColsList(_ref) {
187
203
  toggleLabel: () => toggleLabel(item),
188
204
  toggleSlice: () => toggleSlice(item),
189
205
  toggleColor: () => toggleColor(item)
190
- }, item.name)
206
+ }, item.name))
191
207
  })]
192
208
  }, item.name);
193
209
  });
@@ -198,7 +214,7 @@ function ObsColsList(_ref) {
198
214
  className: "list-group overflow-auto h-100",
199
215
  children: [isPending && /*#__PURE__*/(0, _jsxRuntime.jsx)(_LoadingIndicators.LoadingSpinner, {}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactBootstrap.Accordion, {
200
216
  flush: true,
201
- defaultActiveKey: active,
217
+ defaultActiveKey: [active],
202
218
  alwaysOpen: true,
203
219
  children: obsList
204
220
  })]
@@ -12,6 +12,7 @@ var _reactPlotly = _interopRequireDefault(require("react-plotly.js"));
12
12
  var _PseudospatialToolbar = require("./PseudospatialToolbar");
13
13
  var _constants = require("../../constants/constants");
14
14
  var _DatasetContext = require("../../context/DatasetContext");
15
+ var _FilterContext = require("../../context/FilterContext");
15
16
  var _colorHelper = require("../../helpers/color-helper");
16
17
  var _ImageViewer = require("../../utils/ImageViewer");
17
18
  var _Legend = require("../../utils/Legend");
@@ -24,16 +25,19 @@ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e;
24
25
  function usePseudospatialData(plotType) {
25
26
  const ENDPOINT = "pseudospatial";
26
27
  const dataset = (0, _DatasetContext.useDataset)();
28
+ const filteredData = (0, _FilterContext.useFilteredData)();
29
+ const isSliced = dataset.sliceBy.obs || dataset.sliceBy.polygons;
27
30
  const baseParams = (0, _react.useMemo)(() => {
28
31
  return {
29
32
  url: dataset.url,
30
33
  maskSet: dataset.pseudospatial.maskSet,
31
34
  maskValues: dataset.pseudospatial.maskValues,
35
+ obsIndices: isSliced ? [...(filteredData.obsIndices || [])] : null,
32
36
  varNamesCol: dataset.varNamesCol,
33
37
  showColorbar: false,
34
38
  format: "json"
35
39
  };
36
- }, [dataset.url, dataset.pseudospatial.maskSet, dataset.pseudospatial.maskValues, dataset.varNamesCol]);
40
+ }, [dataset.url, dataset.pseudospatial.maskSet, dataset.pseudospatial.maskValues, dataset.varNamesCol, isSliced, filteredData.obsIndices]);
37
41
  const getPlotParams = (0, _react.useCallback)(() => {
38
42
  if (plotType === _constants.PSEUDOSPATIAL_PLOT_TYPES.GENE) {
39
43
  return {
@@ -59,7 +59,9 @@ function MaskSet() {
59
59
  fetchedData,
60
60
  isPending,
61
61
  serverError
62
- } = (0, _requests.useFetch)(ENDPOINT, params);
62
+ } = (0, _requests.useFetch)(ENDPOINT, params, {
63
+ refetchOnMount: false
64
+ });
63
65
  (0, _react.useEffect)(() => {
64
66
  if (!isPending && !serverError) {
65
67
  setMaskSets(fetchedData);
@@ -11,16 +11,15 @@ var _freeSolidSvgIcons = require("@fortawesome/free-solid-svg-icons");
11
11
  var _reactFontawesome = require("@fortawesome/react-fontawesome");
12
12
  var _editModes = require("@nebula.gl/edit-modes");
13
13
  var _layers2 = require("@nebula.gl/layers");
14
- var _turf = require("@turf/turf");
15
14
  var _lodash = _interopRequireDefault(require("lodash"));
16
15
  var _reactBootstrap = require("react-bootstrap");
17
16
  var _SpatialControls = require("./SpatialControls");
18
17
  var _Toolbox = require("./Toolbox");
19
18
  var _constants = require("../../constants/constants");
20
19
  var _DatasetContext = require("../../context/DatasetContext");
21
- var _FilterContext = require("../../context/FilterContext");
22
20
  var _colorHelper = require("../../helpers/color-helper");
23
21
  var _mapHelper = require("../../helpers/map-helper");
22
+ var _Filter = require("../../utils/Filter");
24
23
  var _Legend = require("../../utils/Legend");
25
24
  var _LoadingIndicators = require("../../utils/LoadingIndicators");
26
25
  var _string = require("../../utils/string");
@@ -38,14 +37,12 @@ const INITIAL_VIEW_STATE = {
38
37
  pitch: 0,
39
38
  bearing: 0
40
39
  };
41
- const EPSILON = 1e-6;
42
40
  function Scatterplot(_ref) {
43
41
  let {
44
42
  radius = 30
45
43
  } = _ref;
46
44
  const dataset = (0, _DatasetContext.useDataset)();
47
45
  const dispatch = (0, _DatasetContext.useDatasetDispatch)();
48
- const filterDispatch = (0, _FilterContext.useFilteredDataDispatch)();
49
46
  const {
50
47
  getColor
51
48
  } = (0, _colorHelper.useColor)();
@@ -72,6 +69,12 @@ function Scatterplot(_ref) {
72
69
  const labelObsData = (0, _zarrData.useLabelObsData)();
73
70
  // @TODO: assert length of obsmData, xData, obsData is equal
74
71
 
72
+ const {
73
+ filteredIndices,
74
+ valueMin,
75
+ valueMax,
76
+ slicedLength
77
+ } = (0, _Filter.useFilter)(data, features);
75
78
  (0, _react.useEffect)(() => {
76
79
  if (!obsmData.isPending && !obsmData.serverError) {
77
80
  setIsRendering(true);
@@ -187,101 +190,6 @@ function Scatterplot(_ref) {
187
190
  return false;
188
191
  }
189
192
  }, [dataset.colorEncoding, dataset.selectedObs?.type]);
190
- const isInBins = (v, binEdges, indices) => {
191
- const lastEdge = _lodash.default.last(binEdges);
192
- const allButLastEdges = _lodash.default.initial(binEdges);
193
- // add epsilon to last edge to include the last value
194
- const modifiedBinEdges = [...allButLastEdges, [lastEdge[0], lastEdge[1] + EPSILON]];
195
- const binIndices = _lodash.default.difference(_lodash.default.range(binEdges.length), indices);
196
- const ranges = _lodash.default.at(modifiedBinEdges, binIndices);
197
- return _lodash.default.some(ranges, range => _lodash.default.inRange(v, ...range));
198
- };
199
- const isInSlice = (0, _react.useCallback)((index, values, positions) => {
200
- let inSlice = true;
201
- if (isCategorical && values) {
202
- inSlice &= !_lodash.default.includes(dataset.selectedObs?.omit, values[index]);
203
- } else if ((dataset.sliceBy.obs || dataset.colorEncoding === _constants.COLOR_ENCODINGS.OBS && dataset.selectedObs?.type === _constants.OBS_TYPES.CONTINUOUS) && !!dataset.selectedObs?.omit.length && values) {
204
- if (dataset.selectedObs.type === _constants.OBS_TYPES.CATEGORICAL) {
205
- inSlice &= !_lodash.default.includes(dataset.selectedObs.omit, values[index]);
206
- } else if (dataset.selectedObs.type === _constants.OBS_TYPES.CONTINUOUS) {
207
- if (isNaN(values[index])) {
208
- inSlice &= !_lodash.default.includes(dataset.selectedObs.omit, -1);
209
- } else {
210
- inSlice &= isInBins(values[index], dataset.selectedObs.bins.binEdges, _lodash.default.without(dataset.selectedObs.omit, -1));
211
- }
212
- }
213
- }
214
- if (dataset.sliceBy.polygons && positions) {
215
- inSlice &= _lodash.default.some(features?.features, (_f, i) => {
216
- return (0, _turf.booleanPointInPolygon)((0, _turf.point)([positions[index][0], positions[index][1]]), features.features[i]);
217
- });
218
- }
219
- return inSlice;
220
- }, [dataset.colorEncoding, dataset.selectedObs?.bins?.binEdges, dataset.selectedObs?.omit, dataset.selectedObs?.type, dataset.sliceBy.obs, dataset.sliceBy.polygons, features.features, isCategorical]);
221
-
222
- // @TODO: abstract filtering out of this component, maybe in FilterContext ?
223
- const {
224
- filteredIndices,
225
- valueMin,
226
- valueMax,
227
- slicedLength
228
- } = (0, _react.useMemo)(() => {
229
- if (dataset.colorEncoding === _constants.COLOR_ENCODINGS.VAR) {
230
- const {
231
- filtered,
232
- filteredIndices
233
- } = _lodash.default.reduce(data.values, (acc, v, i) => {
234
- if (isInSlice(i, data.sliceValues, data.positions)) {
235
- acc.filtered.push(v);
236
- acc.filteredIndices.add(i);
237
- }
238
- return acc;
239
- }, {
240
- filtered: [],
241
- filteredIndices: new Set()
242
- });
243
- return {
244
- filteredIndices: filteredIndices,
245
- valueMin: _lodash.default.min(filtered),
246
- valueMax: _lodash.default.max(filtered),
247
- slicedLength: filtered.length
248
- };
249
- } else if (dataset.colorEncoding === _constants.COLOR_ENCODINGS.OBS) {
250
- const isContinuous = dataset.selectedObs?.type === _constants.OBS_TYPES.CONTINUOUS;
251
- const {
252
- filtered,
253
- filteredIndices
254
- } = _lodash.default.reduce(data.values, (acc, v, i) => {
255
- if (isInSlice(i, data.values, data.positions)) {
256
- acc.filtered.push(v);
257
- acc.filteredIndices.add(i);
258
- }
259
- return acc;
260
- }, {
261
- filtered: [],
262
- filteredIndices: new Set()
263
- });
264
- return {
265
- filteredIndices: filteredIndices,
266
- valueMin: _lodash.default.min(isContinuous ? filtered : data.values),
267
- valueMax: _lodash.default.max(isContinuous ? filtered : data.values),
268
- slicedLength: filtered.length
269
- };
270
- } else {
271
- return {
272
- filteredIndices: null,
273
- valueMin: _lodash.default.min(data.values),
274
- valueMax: _lodash.default.max(data.values),
275
- slicedLength: data.values.length
276
- };
277
- }
278
- }, [data.positions, data.sliceValues, data.values, dataset.colorEncoding, dataset.selectedObs?.type, isInSlice]);
279
- (0, _react.useEffect)(() => {
280
- filterDispatch({
281
- type: "set.obs.indices",
282
- indices: dataset.sliceBy.obs || dataset.sliceBy.polygons ? filteredIndices : null
283
- });
284
- }, [dataset.sliceBy.obs, dataset.sliceBy.polygons, filterDispatch, filteredIndices]);
285
193
  (0, _react.useEffect)(() => {
286
194
  dispatch({
287
195
  type: "set.controls.valueRange",