@haniffalab/cherita-react 0.2.0-dev.2024-12-16.ab9c5057 → 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.
Files changed (32) hide show
  1. package/dist/components/dotplot/Dotplot.js +6 -1
  2. package/dist/components/full-page/FullPage.js +81 -7
  3. package/dist/components/heatmap/Heatmap.js +6 -1
  4. package/dist/components/matrixplot/Matrixplot.js +6 -1
  5. package/dist/components/obs-list/ObsItem.js +74 -24
  6. package/dist/components/obs-list/ObsList.js +27 -5
  7. package/dist/components/pseudospatial/Pseudospatial.js +219 -0
  8. package/dist/components/pseudospatial/PseudospatialControls.js +12 -0
  9. package/dist/components/pseudospatial/PseudospatialToolbar.js +157 -0
  10. package/dist/components/scatterplot/Scatterplot.js +100 -166
  11. package/dist/components/var-list/VarItem.js +35 -53
  12. package/dist/components/var-list/VarList.js +4 -2
  13. package/dist/components/var-list/VarSet.js +1 -0
  14. package/dist/components/violin/Violin.js +7 -2
  15. package/dist/constants/constants.js +17 -1
  16. package/dist/context/DatasetContext.js +40 -2
  17. package/dist/css/cherita.css +44 -0
  18. package/dist/css/cherita.css.map +1 -1
  19. package/dist/helpers/color-helper.js +12 -8
  20. package/dist/helpers/zarr-helper.js +2 -0
  21. package/dist/index.js +25 -0
  22. package/dist/utils/Filter.js +129 -0
  23. package/dist/utils/Histogram.js +54 -0
  24. package/dist/utils/ImageViewer.js +40 -0
  25. package/dist/{components/scatterplot → utils}/Legend.js +12 -7
  26. package/dist/utils/VirtualizedList.js +2 -2
  27. package/dist/utils/requests.js +8 -2
  28. package/dist/utils/search.js +4 -2
  29. package/dist/utils/string.js +7 -3
  30. package/package.json +2 -2
  31. package/scss/cherita.scss +44 -0
  32. package/dist/App.scss +0 -270
@@ -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,20 +4,33 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.FullPage = FullPage;
7
+ exports.FullPagePlots = FullPagePlots;
8
+ exports.FullPagePseudospatial = FullPagePseudospatial;
9
+ exports.FullPageScatterplot = FullPageScatterplot;
7
10
  var _react = _interopRequireWildcard(require("react"));
8
11
  var _reactBootstrap = require("react-bootstrap");
9
12
  var _constants = require("../../constants/constants");
10
13
  var _DatasetContext = require("../../context/DatasetContext");
14
+ var _Dotplot = require("../dotplot/Dotplot");
15
+ var _Heatmap = require("../heatmap/Heatmap");
16
+ var _Matrixplot = require("../matrixplot/Matrixplot");
11
17
  var _ObsList = require("../obs-list/ObsList");
12
18
  var _offcanvas = require("../offcanvas");
19
+ var _Pseudospatial = require("../pseudospatial/Pseudospatial");
13
20
  var _Scatterplot = require("../scatterplot/Scatterplot");
14
21
  var _ScatterplotControls = require("../scatterplot/ScatterplotControls");
15
22
  var _SearchBar = require("../search-bar/SearchBar");
16
23
  var _VarList = require("../var-list/VarList");
24
+ var _Violin = require("../violin/Violin");
17
25
  var _jsxRuntime = require("react/jsx-runtime");
18
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); }
19
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; }
20
- function FullPage(props) {
28
+ function FullPage(_ref) {
29
+ let {
30
+ children,
31
+ varMode = _constants.SELECTION_MODES.SINGLE,
32
+ ...props
33
+ } = _ref;
21
34
  const targetRef = (0, _react.useRef)();
22
35
  const [showObs, setShowObs] = (0, _react.useState)(false);
23
36
  const [showObsm, setShowObsm] = (0, _react.useState)(false);
@@ -94,19 +107,17 @@ function FullPage(props) {
94
107
  })]
95
108
  })
96
109
  })
97
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
98
- className: "cherita-container-scatterplot",
99
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Scatterplot.Scatterplot, {})
100
- })]
110
+ }), children]
101
111
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
102
112
  className: "cherita-app-var",
103
113
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactBootstrap.Card, {
104
114
  className: "cherita-app-features",
105
115
  children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactBootstrap.Card.Body, {
106
116
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_SearchBar.SearchBar, {
107
- searchDiseases: true
117
+ searchDiseases: true,
118
+ searchVar: true
108
119
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_VarList.VarNamesList, {
109
- mode: _constants.SELECTION_MODES.SINGLE
120
+ mode: varMode
110
121
  })]
111
122
  })
112
123
  })
@@ -130,4 +141,67 @@ function FullPage(props) {
130
141
  })
131
142
  })
132
143
  });
144
+ }
145
+ function FullPageScatterplot(props) {
146
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(FullPage, {
147
+ ...props,
148
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Scatterplot.Scatterplot, {})
149
+ });
150
+ }
151
+ function FullPagePseudospatial(props) {
152
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(FullPage, {
153
+ ...props,
154
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
155
+ className: "container-fluid h-100",
156
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
157
+ className: "row",
158
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
159
+ className: "col-12 col-lg-7",
160
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Scatterplot.Scatterplot, {})
161
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
162
+ className: "col-12 col-lg-5",
163
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
164
+ className: "container-fluid h-100 d-flex align-itemms-center justify-content-center",
165
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
166
+ className: "row w-100 py-3",
167
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
168
+ className: "col-12",
169
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
170
+ className: "p-2",
171
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Pseudospatial.Pseudospatial, {})
172
+ })
173
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
174
+ className: "col-12",
175
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Pseudospatial.PseudospatialImage, {})
176
+ })]
177
+ })
178
+ })
179
+ })]
180
+ })
181
+ })
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
+ });
133
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",
@@ -128,12 +161,18 @@ function CategoricalItem(_ref) {
128
161
  y: "0",
129
162
  width: "10",
130
163
  height: "10",
131
- fill: `rgb(${getColor((code - min) / (max - min), true, isOmitted, {
132
- alpha: 1
133
- }, "obs")})`
164
+ fill: `rgb(${getColor({
165
+ value: (code - min) / (max - min),
166
+ categorical: true,
167
+ grayOut: isOmitted,
168
+ grayParams: {
169
+ alpha: 1
170
+ },
171
+ colorEncoding: "obs"
172
+ })})`
134
173
  })
135
174
  })
136
- })]
175
+ }) : null]
137
176
  })]
138
177
  })
139
178
  }, value);
@@ -154,6 +193,8 @@ function CategoricalObs(_ref2) {
154
193
  const totalCounts = _lodash.default.sum(_lodash.default.values(obs.value_counts));
155
194
  const min = _lodash.default.min(_lodash.default.values(obs.codes));
156
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);
157
198
  (0, _react.useEffect)(() => {
158
199
  if (dataset.selectedObs?.name === obs.name) {
159
200
  const selectedObsData = _lodash.default.omit(dataset.selectedObs, ["omit"]);
@@ -172,16 +213,25 @@ function CategoricalObs(_ref2) {
172
213
  }
173
214
  }
174
215
  }, [dataset.selectedObs, dispatch, obs, obs.name, updateObs]);
175
- const getDataAtIndex = index => {
216
+ const getDataAtIndex = (0, _react.useCallback)(index => {
176
217
  return {
177
218
  value: obs.values[index],
178
219
  code: obs.codes[obs.values[index]],
179
220
  value_counts: obs.value_counts[obs.values[index]],
180
221
  pct: obs.value_counts[obs.values[index]] / totalCounts * 100,
181
222
  isOmitted: _lodash.default.includes(obs.omit, obs.codes[obs.values[index]]),
182
- 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
+ }
183
232
  };
184
- };
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;
185
235
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactBootstrap.ListGroup, {
186
236
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactBootstrap.ListGroup.Item, {
187
237
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_ObsToolbar.ObsToolbar, {
@@ -306,7 +356,7 @@ function ContinuousObs(_ref4) {
306
356
  const ENDPOINT = "obs/bins";
307
357
  const dataset = (0, _DatasetContext.useDataset)();
308
358
  const dispatch = (0, _DatasetContext.useDatasetDispatch)();
309
- const binnedObs = binContinuous(obs);
359
+ const binnedObs = binContinuous(obs, _lodash.default.min([N_BINS, obs.n_unique]));
310
360
  const params = {
311
361
  url: dataset.url,
312
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
  });
@@ -45,7 +48,13 @@ function ObsColsList(_ref) {
45
48
  });
46
49
  (0, _react.useEffect)(() => {
47
50
  if (!isPending && !serverError) {
48
- setObsCols(_lodash.default.keyBy(_lodash.default.map(fetchedData, d => {
51
+ let filteredData = fetchedData;
52
+ if (dataset.obsCols) {
53
+ filteredData = _lodash.default.filter(filteredData, d => {
54
+ return _lodash.default.includes(dataset.obsCols, d.name);
55
+ });
56
+ }
57
+ setObsCols(_lodash.default.keyBy(_lodash.default.map(filteredData, d => {
49
58
  return {
50
59
  ...d,
51
60
  codesMap: _lodash.default.invert(d.codes),
@@ -53,7 +62,7 @@ function ObsColsList(_ref) {
53
62
  };
54
63
  }), "name"));
55
64
  }
56
- }, [fetchedData, isPending, serverError]);
65
+ }, [dataset.obsCols, fetchedData, isPending, serverError]);
57
66
 
58
67
  // @TODO: fix re-rendering performance issue
59
68
  (0, _react.useEffect)(() => {
@@ -73,6 +82,18 @@ function ObsColsList(_ref) {
73
82
  };
74
83
  });
75
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
+ };
76
97
  const toggleAll = item => {
77
98
  const omit = item.omit.length ? [] : _lodash.default.map(item.values, v => item.codes[v]);
78
99
  setObsCols(o => {
@@ -162,9 +183,10 @@ function ObsColsList(_ref) {
162
183
  eventKey: item.name,
163
184
  className: active === item.name && dataset.colorEncoding === _constants.COLOR_ENCODINGS.OBS && "cherita-accordion-active",
164
185
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactBootstrap.Accordion.Header, {
186
+ onClick: () => handleAccordionToggle(item.name),
165
187
  children: item.name
166
188
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactBootstrap.Accordion.Body, {
167
- 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, {
168
190
  obs: item,
169
191
  updateObs: updateObs,
170
192
  toggleAll: () => toggleAll(item),
@@ -181,7 +203,7 @@ function ObsColsList(_ref) {
181
203
  toggleLabel: () => toggleLabel(item),
182
204
  toggleSlice: () => toggleSlice(item),
183
205
  toggleColor: () => toggleColor(item)
184
- }, item.name)
206
+ }, item.name))
185
207
  })]
186
208
  }, item.name);
187
209
  });
@@ -192,7 +214,7 @@ function ObsColsList(_ref) {
192
214
  className: "list-group overflow-auto h-100",
193
215
  children: [isPending && /*#__PURE__*/(0, _jsxRuntime.jsx)(_LoadingIndicators.LoadingSpinner, {}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactBootstrap.Accordion, {
194
216
  flush: true,
195
- defaultActiveKey: active,
217
+ defaultActiveKey: [active],
196
218
  alwaysOpen: true,
197
219
  children: obsList
198
220
  })]