@haniffalab/cherita-react 1.4.1 → 1.4.2-dev.2025-10-29.e8bbb191

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 +100 -74
  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 +258 -210
  20. package/dist/cjs/components/obs-list/ObsList.js +161 -133
  21. package/dist/cjs/components/obs-list/ObsToolbar.js +2 -3
  22. package/dist/cjs/components/obsm-list/ObsmList.js +53 -38
  23. package/dist/cjs/components/offcanvas/index.js +61 -31
  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 +127 -99
  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 +168 -121
  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 +115 -88
  35. package/dist/cjs/components/var-list/VarList.js +85 -69
  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 -107
  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 +47 -47
  42. package/dist/cjs/context/DatasetContext.js +24 -16
  43. package/dist/cjs/context/FilterContext.js +11 -9
  44. package/dist/cjs/context/SettingsContext.js +255 -89
  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 +34 -27
  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 +64 -42
  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 +120 -93
  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 +273 -222
  82. package/dist/esm/components/obs-list/ObsList.js +176 -147
  83. package/dist/esm/components/obs-list/ObsToolbar.js +3 -3
  84. package/dist/esm/components/obsm-list/ObsmList.js +60 -44
  85. package/dist/esm/components/offcanvas/index.js +67 -37
  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 +148 -119
  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 +180 -132
  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 +126 -98
  97. package/dist/esm/components/var-list/VarList.js +99 -82
  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 -118
  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 +47 -47
  104. package/dist/esm/context/DatasetContext.js +31 -22
  105. package/dist/esm/context/FilterContext.js +11 -8
  106. package/dist/esm/context/SettingsContext.js +257 -90
  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 +35 -27
  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 -9
  127. package/scss/cherita-bootstrap.scss +2 -2
  128. package/scss/cherita.scss +43 -17
  129. package/scss/components/accordions.scss +4 -1
  130. package/scss/components/layouts.scss +15 -33
  131. package/scss/components/lists.scss +8 -4
  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
@@ -1,18 +1,18 @@
1
- import React, { useState } from "react";
2
- import { faChevronDown, faChevronUp, faCircleInfo, faDroplet, faPlus, faTrash } from "@fortawesome/free-solid-svg-icons";
3
- import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
4
- import _ from "lodash";
5
- import { Button, Collapse, ListGroup, OverlayTrigger, Tooltip } from "react-bootstrap";
6
- import { SelectionItem } from "./VarItem";
7
- import { COLOR_ENCODINGS, SELECTION_MODES } from "../../constants/constants";
8
- import { useSettings, useSettingsDispatch } from "../../context/SettingsContext";
9
- import { SearchModal } from "../search-bar/SearchBar";
1
+ import { useState } from 'react';
2
+ import { faChevronDown, faChevronUp, faCircleInfo, faDroplet, faPlus, faTrash } from '@fortawesome/free-solid-svg-icons';
3
+ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
4
+ import _ from 'lodash';
5
+ import { Button, Collapse, ListGroup, OverlayTrigger, Tooltip } from 'react-bootstrap';
6
+ import { SelectionItem } from './VarItem';
7
+ import { COLOR_ENCODINGS, SELECTION_MODES } from '../../constants/constants';
8
+ import { useSettings, useSettingsDispatch } from '../../context/SettingsContext';
9
+ import { SearchModal } from '../search-bar/SearchBar';
10
10
 
11
11
  // @TODO: add button to score genes and plot
12
-
12
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
13
13
  const addVarToSet = (dispatch, set, v) => {
14
14
  dispatch({
15
- type: "add.varSet.var",
15
+ type: 'add.varSet.var',
16
16
  varSet: set,
17
17
  var: v
18
18
  });
@@ -28,100 +28,119 @@ function SelectionSet(_ref) {
28
28
  } = _ref;
29
29
  const [openSet, setOpenSet] = useState(false);
30
30
  const [showModal, setShowModal] = useState(false);
31
- const [searchText, setSearchText] = useState("");
31
+ const [searchText, setSearchText] = useState('');
32
32
  const varList = set.vars.length ? _.map(set.vars, v => {
33
- return /*#__PURE__*/React.createElement(ListGroup.Item, {
34
- key: v.name
35
- }, /*#__PURE__*/React.createElement(SelectionItem, {
36
- item: v,
37
- showSetColorEncoding: false,
38
- removeVar: () => removeSetVar(v)
39
- }));
40
- }) : /*#__PURE__*/React.createElement(ListGroup.Item, null, /*#__PURE__*/React.createElement("div", {
41
- className: "text-muted"
42
- }, "No features in this set"));
43
- return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
44
- className: "d-flex justify-content-between cursor-pointer",
45
- onClick: () => {
46
- setOpenSet(o => !o);
47
- }
48
- }, /*#__PURE__*/React.createElement("div", {
49
- className: "d-flex justify-content-between align-items-center w-100"
50
- }, /*#__PURE__*/React.createElement("div", {
51
- className: "ellipsis-text",
52
- title: set.name
53
- }, set.name), /*#__PURE__*/React.createElement("div", {
54
- className: "d-flex align-items-center gap-1"
55
- }, /*#__PURE__*/React.createElement(OverlayTrigger, {
56
- placement: "top",
57
- overlay: /*#__PURE__*/React.createElement(Tooltip, null, "This set represents the mean value of its features")
58
- }, /*#__PURE__*/React.createElement(FontAwesomeIcon, {
59
- icon: faCircleInfo
60
- })), /*#__PURE__*/React.createElement(Button, {
61
- type: "button",
62
- variant: "outline-primary",
63
- className: "m-0 p-0 px-1",
64
- disabled: !set.vars.length,
65
- title: "Open set"
66
- }, /*#__PURE__*/React.createElement(FontAwesomeIcon, {
67
- icon: openSet ? faChevronUp : faChevronDown
68
- })), /*#__PURE__*/React.createElement(Button, {
69
- type: "button",
70
- variant: "outline-primary",
71
- className: "m-0 p-0 px-1",
72
- onClick: e => {
73
- e.stopPropagation();
74
- setShowModal(true);
75
- },
76
- title: "Add to set"
77
- }, /*#__PURE__*/React.createElement(FontAwesomeIcon, {
78
- icon: faPlus
79
- })), /*#__PURE__*/React.createElement(Button, {
80
- type: "button",
81
- variant: isActive ? "primary" : "outline-primary",
82
- className: "m-0 p-0 px-1",
83
- onClick: e => {
84
- e.stopPropagation();
85
- selectSet();
86
- },
87
- disabled: !set.vars.length,
88
- title: "Set as color encoding"
89
- }, /*#__PURE__*/React.createElement(FontAwesomeIcon, {
90
- icon: faDroplet
91
- }), isMultiple && /*#__PURE__*/React.createElement(FontAwesomeIcon, {
92
- icon: faPlus,
93
- size: "xs",
94
- className: "ps-xs-1"
95
- })), /*#__PURE__*/React.createElement(Button, {
96
- type: "button",
97
- className: "m-0 p-0 px-1",
98
- variant: "outline-secondary",
99
- title: "Remove from list",
100
- onClick: e => {
101
- e.stopPropagation();
102
- removeSet();
103
- }
104
- }, /*#__PURE__*/React.createElement(FontAwesomeIcon, {
105
- icon: faTrash
106
- }))))), /*#__PURE__*/React.createElement(Collapse, {
107
- in: openSet
108
- }, /*#__PURE__*/React.createElement("div", {
109
- className: "mt-2"
110
- }, /*#__PURE__*/React.createElement(ListGroup, {
111
- variant: "flush",
112
- className: "cherita-list var-set-list"
113
- }, varList))), /*#__PURE__*/React.createElement(SearchModal, {
114
- show: showModal,
115
- handleClose: () => setShowModal(false),
116
- text: searchText,
117
- setText: setSearchText,
118
- displayText: "features",
119
- handleSelect: (d, i) => {
120
- addVarToSet(d, set, i);
121
- },
122
- searchVar: true,
123
- searchDiseases: false
124
- }));
33
+ return /*#__PURE__*/_jsx(ListGroup.Item, {
34
+ children: /*#__PURE__*/_jsx(SelectionItem, {
35
+ item: v,
36
+ showSetColorEncoding: false,
37
+ removeVar: () => removeSetVar(v)
38
+ })
39
+ }, v.name);
40
+ }) : /*#__PURE__*/_jsx(ListGroup.Item, {
41
+ children: /*#__PURE__*/_jsx("div", {
42
+ className: "text-muted",
43
+ children: "No features in this set"
44
+ })
45
+ });
46
+ return /*#__PURE__*/_jsxs(_Fragment, {
47
+ children: [/*#__PURE__*/_jsx("div", {
48
+ className: "d-flex justify-content-between cursor-pointer",
49
+ onClick: () => {
50
+ setOpenSet(o => !o);
51
+ },
52
+ children: /*#__PURE__*/_jsxs("div", {
53
+ className: "d-flex justify-content-between align-items-center w-100",
54
+ children: [/*#__PURE__*/_jsx("div", {
55
+ className: "ellipsis-text",
56
+ title: set.name,
57
+ children: set.name
58
+ }), /*#__PURE__*/_jsxs("div", {
59
+ className: "d-flex align-items-center gap-1",
60
+ children: [/*#__PURE__*/_jsx(OverlayTrigger, {
61
+ placement: "top",
62
+ overlay: /*#__PURE__*/_jsx(Tooltip, {
63
+ children: "This set represents the mean value of its features"
64
+ }),
65
+ children: /*#__PURE__*/_jsx(FontAwesomeIcon, {
66
+ icon: faCircleInfo
67
+ })
68
+ }), /*#__PURE__*/_jsx(Button, {
69
+ type: "button",
70
+ variant: "outline-primary",
71
+ className: "m-0 p-0 px-1",
72
+ disabled: !set.vars.length,
73
+ title: "Open set",
74
+ children: /*#__PURE__*/_jsx(FontAwesomeIcon, {
75
+ icon: openSet ? faChevronUp : faChevronDown
76
+ })
77
+ }), /*#__PURE__*/_jsx(Button, {
78
+ type: "button",
79
+ variant: "outline-primary",
80
+ className: "m-0 p-0 px-1",
81
+ onClick: e => {
82
+ e.stopPropagation();
83
+ setShowModal(true);
84
+ },
85
+ title: "Add to set",
86
+ children: /*#__PURE__*/_jsx(FontAwesomeIcon, {
87
+ icon: faPlus
88
+ })
89
+ }), /*#__PURE__*/_jsxs(Button, {
90
+ type: "button",
91
+ variant: isActive ? 'primary' : 'outline-primary',
92
+ className: "m-0 p-0 px-1",
93
+ onClick: e => {
94
+ e.stopPropagation();
95
+ selectSet();
96
+ },
97
+ disabled: !set.vars.length,
98
+ title: "Set as color encoding",
99
+ children: [/*#__PURE__*/_jsx(FontAwesomeIcon, {
100
+ icon: faDroplet
101
+ }), isMultiple && /*#__PURE__*/_jsx(FontAwesomeIcon, {
102
+ icon: faPlus,
103
+ size: "xs",
104
+ className: "ps-xs-1"
105
+ })]
106
+ }), /*#__PURE__*/_jsx(Button, {
107
+ type: "button",
108
+ className: "m-0 p-0 px-1",
109
+ variant: "outline-secondary",
110
+ title: "Remove from list",
111
+ onClick: e => {
112
+ e.stopPropagation();
113
+ removeSet();
114
+ },
115
+ children: /*#__PURE__*/_jsx(FontAwesomeIcon, {
116
+ icon: faTrash
117
+ })
118
+ })]
119
+ })]
120
+ })
121
+ }), /*#__PURE__*/_jsx(Collapse, {
122
+ in: openSet,
123
+ children: /*#__PURE__*/_jsx("div", {
124
+ className: "mt-2",
125
+ children: /*#__PURE__*/_jsx(ListGroup, {
126
+ variant: "flush",
127
+ className: "cherita-list var-set-list",
128
+ children: varList
129
+ })
130
+ })
131
+ }), /*#__PURE__*/_jsx(SearchModal, {
132
+ show: showModal,
133
+ handleClose: () => setShowModal(false),
134
+ text: searchText,
135
+ setText: setSearchText,
136
+ displayText: 'features',
137
+ handleSelect: (d, i) => {
138
+ addVarToSet(d, set, i);
139
+ },
140
+ searchVar: true,
141
+ searchDiseases: false
142
+ })]
143
+ });
125
144
  }
126
145
  export function VarSet(_ref2) {
127
146
  let {
@@ -134,16 +153,16 @@ export function VarSet(_ref2) {
134
153
  const selectSet = () => {
135
154
  if (mode === SELECTION_MODES.SINGLE) {
136
155
  dispatch({
137
- type: "select.var",
156
+ type: 'select.var',
138
157
  var: set
139
158
  });
140
159
  dispatch({
141
- type: "set.colorEncoding",
142
- value: "var"
160
+ type: 'set.colorEncoding',
161
+ value: 'var'
143
162
  });
144
163
  } else if (mode === SELECTION_MODES.MULTIPLE) {
145
164
  dispatch({
146
- type: "select.multivar",
165
+ type: 'select.multivar',
147
166
  var: set
148
167
  });
149
168
  }
@@ -152,37 +171,37 @@ export function VarSet(_ref2) {
152
171
  if (mode === SELECTION_MODES.SINGLE) {
153
172
  if (active === set.name) {
154
173
  dispatch({
155
- type: "reset.var"
174
+ type: 'reset.var'
156
175
  });
157
176
  }
158
177
  } else if (mode === SELECTION_MODES.MULTIPLE) {
159
178
  if (active.includes(set.name)) {
160
179
  dispatch({
161
- type: "deselect.multivar",
180
+ type: 'deselect.multivar',
162
181
  var: set
163
182
  });
164
183
  }
165
184
  }
166
185
  dispatch({
167
- type: "remove.var",
186
+ type: 'remove.var',
168
187
  var: set
169
188
  });
170
189
  };
171
190
  const removeSetVar = v => {
172
191
  dispatch({
173
- type: "remove.varSet.var",
192
+ type: 'remove.varSet.var',
174
193
  varSet: set,
175
194
  var: v
176
195
  });
177
196
  };
178
197
  const toggleSet = () => {
179
198
  dispatch({
180
- type: "toggle.multivar",
199
+ type: 'toggle.multivar',
181
200
  var: set
182
201
  });
183
202
  };
184
203
  if (set && mode === SELECTION_MODES.SINGLE) {
185
- return /*#__PURE__*/React.createElement(SelectionSet, {
204
+ return /*#__PURE__*/_jsx(SelectionSet, {
186
205
  set: set,
187
206
  isActive: settings.colorEncoding === COLOR_ENCODINGS.VAR && active === set.name,
188
207
  selectSet: selectSet,
@@ -190,7 +209,7 @@ export function VarSet(_ref2) {
190
209
  removeSetVar: v => removeSetVar(v)
191
210
  });
192
211
  } else if (mode === SELECTION_MODES.MULTIPLE) {
193
- return /*#__PURE__*/React.createElement(SelectionSet, {
212
+ return /*#__PURE__*/_jsx(SelectionSet, {
194
213
  set: set,
195
214
  isActive: _.includes(active, set.name),
196
215
  selectSet: toggleSet,
@@ -3,21 +3,24 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
3
3
  function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
4
4
  function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
5
5
  function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
6
- import React, { useEffect, useState } from "react";
7
- import { faCircleInfo } from "@fortawesome/free-solid-svg-icons";
8
- import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
9
- import _ from "lodash";
10
- import { Alert, Button, OverlayTrigger, Tooltip } from "react-bootstrap";
11
- import Plot from "react-plotly.js";
12
- import { PLOTLY_MODEBAR_BUTTONS, VIOLIN_MODES } from "../../constants/constants";
13
- import { useDataset } from "../../context/DatasetContext";
14
- import { useFilteredData } from "../../context/FilterContext";
15
- import { useSettings } from "../../context/SettingsContext";
16
- import { LoadingSpinner } from "../../utils/LoadingIndicators";
17
- import { useDebouncedFetch } from "../../utils/requests";
18
- import { ControlsPlotlyToolbar, ObsPlotlyToolbar, VarPlotlyToolbar } from "../toolbar/Toolbar";
6
+ import { useEffect, useMemo, useState } from 'react';
7
+ import { faCircleInfo } from '@fortawesome/free-solid-svg-icons';
8
+ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
9
+ import _ from 'lodash';
10
+ import { Badge, Button } from 'react-bootstrap';
11
+ import Plot from 'react-plotly.js';
12
+ import { PLOTLY_MODEBAR_BUTTONS, VIOLIN_MODES } from '../../constants/constants';
13
+ import { useDataset } from '../../context/DatasetContext';
14
+ import { useFilteredData } from '../../context/FilterContext';
15
+ import { useSettings } from '../../context/SettingsContext';
16
+ import { LoadingSpinner } from '../../utils/LoadingIndicators';
17
+ import { useDebouncedFetch } from '../../utils/requests';
18
+ import { useSelectedMultiVar, useSelectedObs, useSelectedVar } from '../../utils/Resolver';
19
+ import { StyledTooltip } from '../../utils/StyledTooltip';
20
+ import { PlotAlert } from '../full-page/PlotAlert';
21
+ import { ControlsPlotlyToolbar, ObsPlotlyToolbar, VarPlotlyToolbar } from '../toolbar/Toolbar';
22
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
19
23
  export function Violin(_ref) {
20
- var _settings$selectedVar, _settings$selectedVar2, _settings$selectedVar3, _settings$selectedVar4, _settings$selectedObs, _settings$selectedObs2, _settings$selectedObs3;
21
24
  let {
22
25
  mode = VIOLIN_MODES.MULTIKEY,
23
26
  showObsBtn = false,
@@ -25,9 +28,11 @@ export function Violin(_ref) {
25
28
  showCtrlsBtn = false,
26
29
  setShowObs,
27
30
  setShowVars,
28
- setShowControls
31
+ setShowControls,
32
+ plotType,
33
+ setPlotType
29
34
  } = _ref;
30
- const ENDPOINT = "violin";
35
+ const ENDPOINT = 'violin';
31
36
  const dataset = useDataset();
32
37
  const settings = useSettings();
33
38
  const {
@@ -37,91 +42,63 @@ export function Violin(_ref) {
37
42
  const [data, setData] = useState([]);
38
43
  const [layout, setLayout] = useState({});
39
44
  const [hasSelections, setHasSelections] = useState(false);
40
- const [params, setParams] = useState(_objectSpread({
45
+ const selectedMultiVar = useSelectedMultiVar();
46
+ const selectedVar = useSelectedVar();
47
+ const selectedObs = useSelectedObs();
48
+ const params = useMemo(() => _objectSpread({
41
49
  url: dataset.url,
42
50
  mode: mode,
43
51
  scale: settings.controls.scale.violinplot,
44
52
  varNamesCol: dataset.varNamesCol
45
53
  }, {
46
54
  [VIOLIN_MODES.MULTIKEY]: {
47
- varKeys: settings.selectedMultiVar.map(i => i.isSet ? {
55
+ varKeys: selectedMultiVar.map(i => i.isSet ? {
48
56
  name: i.name,
49
57
  indices: i.vars.map(v => v.index)
50
58
  } : i.index),
51
59
  obsKeys: [] // @TODO: implement
52
60
  },
53
61
  [VIOLIN_MODES.GROUPBY]: {
54
- varKey: (_settings$selectedVar = settings.selectedVar) !== null && _settings$selectedVar !== void 0 && _settings$selectedVar.isSet ? {
55
- name: (_settings$selectedVar2 = settings.selectedVar) === null || _settings$selectedVar2 === void 0 ? void 0 : _settings$selectedVar2.name,
56
- indices: (_settings$selectedVar3 = settings.selectedVar) === null || _settings$selectedVar3 === void 0 ? void 0 : _settings$selectedVar3.vars.map(v => v.index)
57
- } : (_settings$selectedVar4 = settings.selectedVar) === null || _settings$selectedVar4 === void 0 ? void 0 : _settings$selectedVar4.index,
58
- obsCol: settings.selectedObs,
59
- obsValues: !((_settings$selectedObs = settings.selectedObs) !== null && _settings$selectedObs !== void 0 && _settings$selectedObs.omit.length) ? null : _.difference(_.values((_settings$selectedObs2 = settings.selectedObs) === null || _settings$selectedObs2 === void 0 ? void 0 : _settings$selectedObs2.codes), (_settings$selectedObs3 = settings.selectedObs) === null || _settings$selectedObs3 === void 0 ? void 0 : _settings$selectedObs3.omit).map(c => {
60
- var _settings$selectedObs4;
61
- return (_settings$selectedObs4 = settings.selectedObs) === null || _settings$selectedObs4 === void 0 ? void 0 : _settings$selectedObs4.codesMap[c];
62
- }),
62
+ varKey: selectedVar !== null && selectedVar !== void 0 && selectedVar.isSet ? {
63
+ name: selectedVar === null || selectedVar === void 0 ? void 0 : selectedVar.name,
64
+ indices: selectedVar === null || selectedVar === void 0 ? void 0 : selectedVar.vars.map(v => v.index)
65
+ } : selectedVar === null || selectedVar === void 0 ? void 0 : selectedVar.index,
66
+ obsCol: selectedObs,
67
+ obsValues: !(selectedObs !== null && selectedObs !== void 0 && selectedObs.omit.length) ? null : _.difference(selectedObs === null || selectedObs === void 0 ? void 0 : selectedObs.values, selectedObs === null || selectedObs === void 0 ? void 0 : selectedObs.omit),
63
68
  obsIndices: isSliced ? [...(obsIndices || [])] : null
64
69
  }
65
- }[mode]));
70
+ }[mode]), [dataset.url, dataset.varNamesCol, isSliced, mode, obsIndices, selectedMultiVar, selectedObs, selectedVar === null || selectedVar === void 0 ? void 0 : selectedVar.index, selectedVar === null || selectedVar === void 0 ? void 0 : selectedVar.isSet, selectedVar === null || selectedVar === void 0 ? void 0 : selectedVar.name, selectedVar === null || selectedVar === void 0 ? void 0 : selectedVar.vars, settings.controls.scale.violinplot]);
66
71
  // @TODO: set default scale
67
72
 
68
73
  useEffect(() => {
69
74
  if (mode === VIOLIN_MODES.MULTIKEY) {
70
- if (settings.selectedMultiVar.length) {
75
+ if (selectedMultiVar.length) {
71
76
  setHasSelections(true);
72
77
  } else {
73
78
  setHasSelections(false);
74
79
  }
75
- setParams(p => {
76
- return _objectSpread(_objectSpread({}, p), {}, {
77
- url: dataset.url,
78
- mode: mode,
79
- varKeys: settings.selectedMultiVar.map(i => i.isSet ? {
80
- name: i.name,
81
- indices: i.vars.map(v => v.index)
82
- } : i.index),
83
- scale: settings.controls.scale.violinplot,
84
- varNamesCol: dataset.varNamesCol
85
- });
86
- });
87
80
  } else if (mode === VIOLIN_MODES.GROUPBY) {
88
- if (settings.selectedObs && settings.selectedVar) {
81
+ if (selectedObs && selectedVar) {
89
82
  setHasSelections(true);
90
83
  } else {
91
84
  setHasSelections(false);
92
85
  }
93
- setParams(p => {
94
- var _settings$selectedVar5, _settings$selectedVar6, _settings$selectedVar7, _settings$selectedVar8, _settings$selectedObs5, _settings$selectedObs6, _settings$selectedObs7;
95
- return _objectSpread(_objectSpread({}, p), {}, {
96
- url: dataset.url,
97
- mode: mode,
98
- varKey: (_settings$selectedVar5 = settings.selectedVar) !== null && _settings$selectedVar5 !== void 0 && _settings$selectedVar5.isSet ? {
99
- name: (_settings$selectedVar6 = settings.selectedVar) === null || _settings$selectedVar6 === void 0 ? void 0 : _settings$selectedVar6.name,
100
- indices: (_settings$selectedVar7 = settings.selectedVar) === null || _settings$selectedVar7 === void 0 ? void 0 : _settings$selectedVar7.vars.map(v => v.index)
101
- } : (_settings$selectedVar8 = settings.selectedVar) === null || _settings$selectedVar8 === void 0 ? void 0 : _settings$selectedVar8.index,
102
- obsCol: settings.selectedObs,
103
- obsValues: !((_settings$selectedObs5 = settings.selectedObs) !== null && _settings$selectedObs5 !== void 0 && _settings$selectedObs5.omit.length) ? null : _.difference(_.values((_settings$selectedObs6 = settings.selectedObs) === null || _settings$selectedObs6 === void 0 ? void 0 : _settings$selectedObs6.codes), (_settings$selectedObs7 = settings.selectedObs) === null || _settings$selectedObs7 === void 0 ? void 0 : _settings$selectedObs7.omit).map(c => {
104
- var _settings$selectedObs8;
105
- return (_settings$selectedObs8 = settings.selectedObs) === null || _settings$selectedObs8 === void 0 ? void 0 : _settings$selectedObs8.codesMap[c];
106
- }),
107
- obsIndices: isSliced ? [...(obsIndices || [])] : null,
108
- scale: settings.controls.scale.violinplot,
109
- varNamesCol: dataset.varNamesCol
110
- });
111
- });
112
86
  }
113
- }, [settings.controls.scale.violinplot, settings.selectedMultiVar, settings.selectedObs, settings.selectedVar, dataset.url, dataset.varNamesCol, obsIndices, isSliced, mode]);
87
+ }, [settings.controls.scale.violinplot, selectedMultiVar, selectedObs, selectedVar, dataset.url, dataset.varNamesCol, obsIndices, isSliced, mode]);
114
88
  const {
115
89
  fetchedData,
116
90
  isPending,
117
91
  serverError
118
92
  } = useDebouncedFetch(ENDPOINT, params, 500, {
119
- enabled: mode === VIOLIN_MODES.MULTIKEY && (!!params.varKeys.length || !!params.obsKeys.length) || mode === VIOLIN_MODES.GROUPBY && !!params.varKey && !!params.obsCol
93
+ isEnabled: mode === VIOLIN_MODES.MULTIKEY && (params => !!params.varKeys.length || !!params.obsKeys.length) || mode === VIOLIN_MODES.GROUPBY && (params => !!params.varKey && !!params.obsCol)
120
94
  });
121
95
  useEffect(() => {
122
- if (hasSelections && !isPending && !serverError) {
96
+ if (hasSelections && !!fetchedData && !isPending && !serverError) {
123
97
  setData(fetchedData.data);
124
98
  setLayout(fetchedData.layout);
99
+ } else {
100
+ setData([]);
101
+ setLayout({});
125
102
  }
126
103
  }, [fetchedData, hasSelections, isPending, serverError]);
127
104
  const customModeBarButtons = _.compact([showObsBtn && ObsPlotlyToolbar({
@@ -134,61 +111,87 @@ export function Violin(_ref) {
134
111
  const modeBarButtons = customModeBarButtons.length ? [customModeBarButtons, PLOTLY_MODEBAR_BUTTONS] : [PLOTLY_MODEBAR_BUTTONS];
135
112
  if (!serverError) {
136
113
  if (hasSelections) {
137
- return /*#__PURE__*/React.createElement("div", {
138
- className: "cherita-plot cherita-violin"
139
- }, isPending && /*#__PURE__*/React.createElement(LoadingSpinner, null), /*#__PURE__*/React.createElement("div", {
140
- className: "d-flex flex-column h-100"
141
- }, /*#__PURE__*/React.createElement("div", {
142
- className: "flex-grow-1 position-relative",
143
- style: {
144
- minHeight: "0"
145
- }
146
- }, /*#__PURE__*/React.createElement(Plot, {
147
- data: data,
148
- layout: layout,
149
- useResizeHandler: true,
150
- style: {
151
- width: "100%",
152
- height: "100%"
153
- },
154
- config: {
155
- displaylogo: false,
156
- modeBarButtons: modeBarButtons
157
- }
158
- })), (fetchedData === null || fetchedData === void 0 ? void 0 : fetchedData.resampled) && /*#__PURE__*/React.createElement("div", {
159
- className: "flex-shrink-0"
160
- }, /*#__PURE__*/React.createElement(Alert, {
161
- variant: "warning",
162
- className: "mb-1"
163
- }, /*#__PURE__*/React.createElement("b", null, "Warning:"), " For performance reasons this plot was generated with resampled data. It will not be exactly the same as one produced with the entire dataset. \xA0", /*#__PURE__*/React.createElement(OverlayTrigger, {
164
- placement: "top",
165
- overlay: /*#__PURE__*/React.createElement(Tooltip, null, "Resampled to 100K values following a Monte Carlo style approach to help ensure resampled data is a good representation of the original dataset's distribution.")
166
- }, /*#__PURE__*/React.createElement(FontAwesomeIcon, {
167
- icon: faCircleInfo
168
- }))))));
114
+ return /*#__PURE__*/_jsxs("div", {
115
+ className: "cherita-plot cherita-violin",
116
+ children: [isPending && /*#__PURE__*/_jsx(LoadingSpinner, {}), /*#__PURE__*/_jsxs("div", {
117
+ className: "d-flex flex-column h-100",
118
+ children: [/*#__PURE__*/_jsx("div", {
119
+ className: "flex-grow-1 position-relative",
120
+ style: {
121
+ minHeight: '0'
122
+ },
123
+ children: /*#__PURE__*/_jsx(Plot, {
124
+ data: data,
125
+ layout: layout,
126
+ useResizeHandler: true,
127
+ style: {
128
+ width: '100%',
129
+ height: '100%'
130
+ },
131
+ config: {
132
+ displaylogo: false,
133
+ modeBarButtons: modeBarButtons
134
+ }
135
+ })
136
+ }), (fetchedData === null || fetchedData === void 0 ? void 0 : fetchedData.resampled) && /*#__PURE__*/_jsx("div", {
137
+ className: "resampled-tooltip-container",
138
+ children: /*#__PURE__*/_jsx(StyledTooltip, {
139
+ title: /*#__PURE__*/_jsxs(_Fragment, {
140
+ children: [/*#__PURE__*/_jsx("strong", {
141
+ children: "Note:"
142
+ }), " This plot uses resampled data to improve performance, so values may differ slightly from the full dataset. The data were resampled to exactly 100,000 values using a Monte Carlo\u2013style approach to provide a representative view of the full distribution while reducing processing time."]
143
+ }),
144
+ placement: "bottom",
145
+ children: /*#__PURE__*/_jsxs(Badge, {
146
+ bg: "info",
147
+ children: [/*#__PURE__*/_jsx(FontAwesomeIcon, {
148
+ className: "fs-6",
149
+ icon: faCircleInfo
150
+ }), /*#__PURE__*/_jsx("span", {
151
+ className: "d-none d-lg-inline ms-2 fs-6 text-uppercase",
152
+ children: "Resampled"
153
+ })]
154
+ })
155
+ })
156
+ })]
157
+ })]
158
+ });
169
159
  }
170
- return /*#__PURE__*/React.createElement("div", {
171
- className: "cherita-violin"
172
- }, mode === VIOLIN_MODES.MULTIKEY && /*#__PURE__*/React.createElement(Alert, {
173
- variant: "light"
174
- }, "Select", " ", showVarsBtn ? /*#__PURE__*/React.createElement(Button, {
175
- variant: "link",
176
- className: "border-0 p-0 align-baseline",
177
- onClick: setShowVars
178
- }, "features") : "features"), mode === VIOLIN_MODES.GROUPBY && /*#__PURE__*/React.createElement(Alert, {
179
- variant: "light"
180
- }, "Select", " ", showObsBtn ? /*#__PURE__*/React.createElement(Button, {
181
- variant: "link",
182
- className: "border-0 p-0 align-baseline",
183
- onClick: setShowObs
184
- }, "categories") : "categories", " ", "and a", " ", showVarsBtn ? /*#__PURE__*/React.createElement(Button, {
185
- variant: "link",
186
- className: "border-0 p-0 align-baseline",
187
- onClick: setShowVars
188
- }, "feature") : "feature"));
160
+ return /*#__PURE__*/_jsxs(PlotAlert, {
161
+ variant: "info",
162
+ heading: "Set up your violin plot",
163
+ plotType: plotType,
164
+ setPlotType: setPlotType,
165
+ children: [mode === VIOLIN_MODES.MULTIKEY && /*#__PURE__*/_jsxs("p", {
166
+ className: "p-0 m-0",
167
+ children: ["Select one or more", ' ', showVarsBtn ? /*#__PURE__*/_jsx(Button, {
168
+ variant: "link",
169
+ className: "border-0 p-0 align-baseline",
170
+ onClick: setShowVars,
171
+ children: "features"
172
+ }) : 'features', ' ', "to display their expression distributions across all observations."]
173
+ }), mode === VIOLIN_MODES.GROUPBY && /*#__PURE__*/_jsxs("p", {
174
+ className: "p-0 m-0",
175
+ children: ["Select a", ' ', showObsBtn ? /*#__PURE__*/_jsx(Button, {
176
+ variant: "link",
177
+ className: "border-0 p-0 align-baseline",
178
+ onClick: setShowObs,
179
+ children: "category"
180
+ }) : 'category', ' ', "to group observations, and choose a", ' ', showVarsBtn ? /*#__PURE__*/_jsx(Button, {
181
+ variant: "link",
182
+ className: "border-0 p-0 align-baseline",
183
+ onClick: setShowVars,
184
+ children: "feature"
185
+ }) : 'feature', ' ', "to view its distribution within each group."]
186
+ })]
187
+ });
189
188
  } else {
190
- return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Alert, {
191
- variant: "danger"
192
- }, serverError.message));
189
+ return /*#__PURE__*/_jsx(PlotAlert, {
190
+ variant: "danger",
191
+ heading: "Error displaying the violin plot",
192
+ plotType: plotType,
193
+ setPlotType: setPlotType,
194
+ children: serverError.message || 'An unexpected error occurred while generating the plot.'
195
+ });
193
196
  }
194
197
  }