@haniffalab/cherita-react 1.3.0 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) hide show
  1. package/README.md +1 -1
  2. package/dist/cjs/components/controls/Controls.js +38 -30
  3. package/dist/cjs/components/dotplot/Dotplot.js +85 -57
  4. package/dist/cjs/components/dotplot/DotplotControls.js +103 -83
  5. package/dist/cjs/components/full-page/FullPage.js +167 -114
  6. package/dist/cjs/components/full-page/PlotAlert.js +45 -0
  7. package/dist/cjs/components/full-page/PlotTypeSelector.js +102 -0
  8. package/dist/cjs/components/heatmap/Heatmap.js +83 -53
  9. package/dist/cjs/components/heatmap/HeatmapControls.js +6 -3
  10. package/dist/cjs/components/icons/DotPlotIcon.js +64 -0
  11. package/dist/cjs/components/icons/HeatmapIcon.js +45 -0
  12. package/dist/cjs/components/icons/MatrixPlotIcon.1.js +57 -0
  13. package/dist/cjs/components/icons/MatrixPlotIcon.js +59 -0
  14. package/dist/cjs/components/icons/ScatterplotIcon.1.js +164 -0
  15. package/dist/cjs/components/icons/ScatterplotIcon.js +144 -0
  16. package/dist/cjs/components/icons/ViolinPlotIcon.js +42 -0
  17. package/dist/cjs/components/matrixplot/Matrixplot.js +83 -54
  18. package/dist/cjs/components/matrixplot/MatrixplotControls.js +8 -5
  19. package/dist/cjs/components/obs-list/ObsItem.js +305 -216
  20. package/dist/cjs/components/obs-list/ObsList.js +164 -128
  21. package/dist/cjs/components/obs-list/ObsToolbar.js +2 -3
  22. package/dist/cjs/components/obsm-list/ObsmList.js +67 -28
  23. package/dist/cjs/components/offcanvas/index.js +62 -27
  24. package/dist/cjs/components/pseudospatial/Pseudospatial.js +132 -76
  25. package/dist/cjs/components/pseudospatial/PseudospatialToolbar.js +122 -74
  26. package/dist/cjs/components/scatterplot/Scatterplot.js +223 -175
  27. package/dist/cjs/components/scatterplot/ScatterplotControls.js +45 -31
  28. package/dist/cjs/components/scatterplot/SpatialControls.js +143 -116
  29. package/dist/cjs/components/scatterplot/Toolbox.js +41 -30
  30. package/dist/cjs/components/search-bar/SearchBar.js +176 -120
  31. package/dist/cjs/components/search-bar/SearchInfo.js +79 -85
  32. package/dist/cjs/components/search-bar/SearchResults.js +93 -71
  33. package/dist/cjs/components/toolbar/Toolbar.js +111 -0
  34. package/dist/cjs/components/var-list/VarItem.js +131 -103
  35. package/dist/cjs/components/var-list/VarList.js +96 -74
  36. package/dist/cjs/components/var-list/VarListToolbar.js +59 -54
  37. package/dist/cjs/components/var-list/VarSet.js +126 -108
  38. package/dist/cjs/components/violin/Violin.js +124 -81
  39. package/dist/cjs/components/violin/ViolinControls.js +8 -5
  40. package/dist/cjs/constants/colorscales.js +19 -19
  41. package/dist/cjs/constants/constants.js +54 -39
  42. package/dist/cjs/context/DatasetContext.js +27 -17
  43. package/dist/cjs/context/FilterContext.js +11 -9
  44. package/dist/cjs/context/SettingsContext.js +339 -125
  45. package/dist/cjs/context/ZarrDataContext.js +6 -5
  46. package/dist/cjs/helpers/color-helper.js +2 -2
  47. package/dist/cjs/helpers/map-helper.js +2 -1
  48. package/dist/cjs/helpers/zarr-helper.js +3 -3
  49. package/dist/cjs/index.js +15 -21
  50. package/dist/cjs/utils/Filter.js +16 -11
  51. package/dist/cjs/utils/Histogram.js +35 -33
  52. package/dist/cjs/utils/ImageViewer.js +11 -8
  53. package/dist/cjs/utils/Legend.js +37 -30
  54. package/dist/cjs/utils/LoadingIndicators.js +15 -13
  55. package/dist/cjs/utils/Resolver.js +213 -0
  56. package/dist/cjs/utils/Skeleton.js +10 -10
  57. package/dist/cjs/utils/StyledTooltip.js +44 -0
  58. package/dist/cjs/utils/VirtualizedList.js +36 -29
  59. package/dist/cjs/utils/errors.js +15 -15
  60. package/dist/cjs/utils/requests.js +21 -9
  61. package/dist/cjs/utils/search.js +4 -4
  62. package/dist/cjs/utils/string.js +6 -6
  63. package/dist/cjs/utils/zarrData.js +20 -21
  64. package/dist/css/cherita.css +188 -65
  65. package/dist/css/cherita.css.map +1 -1
  66. package/dist/esm/components/controls/Controls.js +43 -35
  67. package/dist/esm/components/dotplot/Dotplot.js +93 -64
  68. package/dist/esm/components/dotplot/DotplotControls.js +106 -85
  69. package/dist/esm/components/full-page/FullPage.js +180 -124
  70. package/dist/esm/components/full-page/PlotAlert.js +39 -0
  71. package/dist/esm/components/full-page/PlotTypeSelector.js +95 -0
  72. package/dist/esm/components/heatmap/Heatmap.js +91 -60
  73. package/dist/esm/components/heatmap/HeatmapControls.js +8 -4
  74. package/dist/esm/components/icons/DotPlotIcon.js +58 -0
  75. package/dist/esm/components/icons/HeatmapIcon.js +39 -0
  76. package/dist/esm/components/icons/MatrixPlotIcon.1.js +51 -0
  77. package/dist/esm/components/icons/MatrixPlotIcon.js +53 -0
  78. package/dist/esm/components/icons/ScatterplotIcon.1.js +158 -0
  79. package/dist/esm/components/icons/ScatterplotIcon.js +138 -0
  80. package/dist/esm/components/icons/ViolinPlotIcon.js +36 -0
  81. package/dist/esm/components/matrixplot/Matrixplot.js +91 -61
  82. package/dist/esm/components/matrixplot/MatrixplotControls.js +10 -6
  83. package/dist/esm/components/obs-list/ObsItem.js +320 -228
  84. package/dist/esm/components/obs-list/ObsList.js +179 -142
  85. package/dist/esm/components/obs-list/ObsToolbar.js +3 -3
  86. package/dist/esm/components/obsm-list/ObsmList.js +71 -32
  87. package/dist/esm/components/offcanvas/index.js +68 -33
  88. package/dist/esm/components/pseudospatial/Pseudospatial.js +145 -88
  89. package/dist/esm/components/pseudospatial/PseudospatialToolbar.js +127 -78
  90. package/dist/esm/components/scatterplot/Scatterplot.js +243 -194
  91. package/dist/esm/components/scatterplot/ScatterplotControls.js +50 -35
  92. package/dist/esm/components/scatterplot/SpatialControls.js +155 -127
  93. package/dist/esm/components/scatterplot/Toolbox.js +44 -32
  94. package/dist/esm/components/search-bar/SearchBar.js +187 -130
  95. package/dist/esm/components/search-bar/SearchInfo.js +86 -91
  96. package/dist/esm/components/search-bar/SearchResults.js +100 -77
  97. package/dist/esm/components/toolbar/Toolbar.js +101 -0
  98. package/dist/esm/components/var-list/VarItem.js +142 -113
  99. package/dist/esm/components/var-list/VarList.js +108 -88
  100. package/dist/esm/components/var-list/VarListToolbar.js +64 -58
  101. package/dist/esm/components/var-list/VarSet.js +134 -115
  102. package/dist/esm/components/violin/Violin.js +135 -91
  103. package/dist/esm/components/violin/ViolinControls.js +10 -6
  104. package/dist/esm/constants/colorscales.js +19 -19
  105. package/dist/esm/constants/constants.js +53 -38
  106. package/dist/esm/context/DatasetContext.js +34 -23
  107. package/dist/esm/context/FilterContext.js +11 -8
  108. package/dist/esm/context/SettingsContext.js +341 -126
  109. package/dist/esm/context/ZarrDataContext.js +8 -6
  110. package/dist/esm/helpers/color-helper.js +5 -5
  111. package/dist/esm/helpers/map-helper.js +4 -3
  112. package/dist/esm/helpers/zarr-helper.js +6 -6
  113. package/dist/esm/index.js +22 -22
  114. package/dist/esm/utils/Filter.js +22 -17
  115. package/dist/esm/utils/Histogram.js +39 -37
  116. package/dist/esm/utils/ImageViewer.js +12 -8
  117. package/dist/esm/utils/Legend.js +44 -36
  118. package/dist/esm/utils/LoadingIndicators.js +16 -13
  119. package/dist/esm/utils/Resolver.js +201 -0
  120. package/dist/esm/utils/Skeleton.js +11 -10
  121. package/dist/esm/utils/StyledTooltip.js +38 -0
  122. package/dist/esm/utils/VirtualizedList.js +37 -29
  123. package/dist/esm/utils/errors.js +15 -15
  124. package/dist/esm/utils/requests.js +24 -12
  125. package/dist/esm/utils/search.js +7 -7
  126. package/dist/esm/utils/string.js +7 -7
  127. package/dist/esm/utils/zarrData.js +27 -28
  128. package/package.json +21 -8
  129. package/scss/cherita-bootstrap.scss +2 -2
  130. package/scss/cherita.scss +65 -17
  131. package/scss/components/accordions.scss +15 -2
  132. package/scss/components/layouts.scss +116 -30
  133. package/scss/components/lists.scss +16 -5
  134. package/scss/components/plotly.scss +40 -23
  135. package/scss/components/plots.scss +14 -1
  136. package/dist/cjs/components/full-page/FullPagePseudospatial.js +0 -157
  137. package/dist/esm/components/full-page/FullPagePseudospatial.js +0 -149
@@ -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,24 +3,36 @@ 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, OverlayTrigger, Tooltip } from "react-bootstrap";
11
- import Plot from "react-plotly.js";
12
- import { 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";
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";
18
23
  export function Violin(_ref) {
19
- var _settings$selectedVar, _settings$selectedVar2, _settings$selectedVar3, _settings$selectedVar4, _settings$selectedObs, _settings$selectedObs2, _settings$selectedObs3;
20
24
  let {
21
- mode = VIOLIN_MODES.MULTIKEY
25
+ mode = VIOLIN_MODES.MULTIKEY,
26
+ showObsBtn = false,
27
+ showVarsBtn = false,
28
+ showCtrlsBtn = false,
29
+ setShowObs,
30
+ setShowVars,
31
+ setShowControls,
32
+ plotType,
33
+ setPlotType
22
34
  } = _ref;
23
- const ENDPOINT = "violin";
35
+ const ENDPOINT = 'violin';
24
36
  const dataset = useDataset();
25
37
  const settings = useSettings();
26
38
  const {
@@ -30,124 +42,156 @@ export function Violin(_ref) {
30
42
  const [data, setData] = useState([]);
31
43
  const [layout, setLayout] = useState({});
32
44
  const [hasSelections, setHasSelections] = useState(false);
33
- const [params, setParams] = useState(_objectSpread({
45
+ const selectedMultiVar = useSelectedMultiVar();
46
+ const selectedVar = useSelectedVar();
47
+ const selectedObs = useSelectedObs();
48
+ const params = useMemo(() => _objectSpread({
34
49
  url: dataset.url,
35
50
  mode: mode,
36
51
  scale: settings.controls.scale.violinplot,
37
52
  varNamesCol: dataset.varNamesCol
38
53
  }, {
39
54
  [VIOLIN_MODES.MULTIKEY]: {
40
- varKeys: settings.selectedMultiVar.map(i => i.isSet ? {
55
+ varKeys: selectedMultiVar.map(i => i.isSet ? {
41
56
  name: i.name,
42
57
  indices: i.vars.map(v => v.index)
43
58
  } : i.index),
44
59
  obsKeys: [] // @TODO: implement
45
60
  },
46
61
  [VIOLIN_MODES.GROUPBY]: {
47
- varKey: (_settings$selectedVar = settings.selectedVar) !== null && _settings$selectedVar !== void 0 && _settings$selectedVar.isSet ? {
48
- name: (_settings$selectedVar2 = settings.selectedVar) === null || _settings$selectedVar2 === void 0 ? void 0 : _settings$selectedVar2.name,
49
- indices: (_settings$selectedVar3 = settings.selectedVar) === null || _settings$selectedVar3 === void 0 ? void 0 : _settings$selectedVar3.vars.map(v => v.index)
50
- } : (_settings$selectedVar4 = settings.selectedVar) === null || _settings$selectedVar4 === void 0 ? void 0 : _settings$selectedVar4.index,
51
- obsCol: settings.selectedObs,
52
- 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 => {
53
- var _settings$selectedObs4;
54
- return (_settings$selectedObs4 = settings.selectedObs) === null || _settings$selectedObs4 === void 0 ? void 0 : _settings$selectedObs4.codesMap[c];
55
- }),
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),
56
68
  obsIndices: isSliced ? [...(obsIndices || [])] : null
57
69
  }
58
- }[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]);
59
71
  // @TODO: set default scale
60
72
 
61
73
  useEffect(() => {
62
74
  if (mode === VIOLIN_MODES.MULTIKEY) {
63
- if (settings.selectedMultiVar.length) {
75
+ if (selectedMultiVar.length) {
64
76
  setHasSelections(true);
65
77
  } else {
66
78
  setHasSelections(false);
67
79
  }
68
- setParams(p => {
69
- return _objectSpread(_objectSpread({}, p), {}, {
70
- url: dataset.url,
71
- mode: mode,
72
- varKeys: settings.selectedMultiVar.map(i => i.isSet ? {
73
- name: i.name,
74
- indices: i.vars.map(v => v.index)
75
- } : i.index),
76
- scale: settings.controls.scale.violinplot,
77
- varNamesCol: dataset.varNamesCol
78
- });
79
- });
80
80
  } else if (mode === VIOLIN_MODES.GROUPBY) {
81
- if (settings.selectedObs && settings.selectedVar) {
81
+ if (selectedObs && selectedVar) {
82
82
  setHasSelections(true);
83
83
  } else {
84
84
  setHasSelections(false);
85
85
  }
86
- setParams(p => {
87
- var _settings$selectedVar5, _settings$selectedVar6, _settings$selectedVar7, _settings$selectedVar8, _settings$selectedObs5, _settings$selectedObs6, _settings$selectedObs7;
88
- return _objectSpread(_objectSpread({}, p), {}, {
89
- url: dataset.url,
90
- mode: mode,
91
- varKey: (_settings$selectedVar5 = settings.selectedVar) !== null && _settings$selectedVar5 !== void 0 && _settings$selectedVar5.isSet ? {
92
- name: (_settings$selectedVar6 = settings.selectedVar) === null || _settings$selectedVar6 === void 0 ? void 0 : _settings$selectedVar6.name,
93
- indices: (_settings$selectedVar7 = settings.selectedVar) === null || _settings$selectedVar7 === void 0 ? void 0 : _settings$selectedVar7.vars.map(v => v.index)
94
- } : (_settings$selectedVar8 = settings.selectedVar) === null || _settings$selectedVar8 === void 0 ? void 0 : _settings$selectedVar8.index,
95
- obsCol: settings.selectedObs,
96
- 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 => {
97
- var _settings$selectedObs8;
98
- return (_settings$selectedObs8 = settings.selectedObs) === null || _settings$selectedObs8 === void 0 ? void 0 : _settings$selectedObs8.codesMap[c];
99
- }),
100
- obsIndices: isSliced ? [...(obsIndices || [])] : null,
101
- scale: settings.controls.scale.violinplot,
102
- varNamesCol: dataset.varNamesCol
103
- });
104
- });
105
86
  }
106
- }, [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]);
107
88
  const {
108
89
  fetchedData,
109
90
  isPending,
110
91
  serverError
111
92
  } = useDebouncedFetch(ENDPOINT, params, 500, {
112
- 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)
113
94
  });
114
95
  useEffect(() => {
115
- if (hasSelections && !isPending && !serverError) {
96
+ if (hasSelections && !!fetchedData && !isPending && !serverError) {
116
97
  setData(fetchedData.data);
117
98
  setLayout(fetchedData.layout);
99
+ } else {
100
+ setData([]);
101
+ setLayout({});
118
102
  }
119
103
  }, [fetchedData, hasSelections, isPending, serverError]);
104
+ const customModeBarButtons = _.compact([showObsBtn && ObsPlotlyToolbar({
105
+ onClick: setShowObs
106
+ }), showVarsBtn && VarPlotlyToolbar({
107
+ onClick: setShowVars
108
+ }), showCtrlsBtn && ControlsPlotlyToolbar({
109
+ onClick: setShowControls
110
+ })]);
111
+ const modeBarButtons = customModeBarButtons.length ? [customModeBarButtons, PLOTLY_MODEBAR_BUTTONS] : [PLOTLY_MODEBAR_BUTTONS];
120
112
  if (!serverError) {
121
113
  if (hasSelections) {
122
- return /*#__PURE__*/React.createElement("div", {
123
- className: "cherita-violin position-relative"
124
- }, isPending && /*#__PURE__*/React.createElement(LoadingSpinner, null), /*#__PURE__*/React.createElement(Plot, {
125
- data: data,
126
- layout: layout,
127
- useResizeHandler: true,
128
- style: {
129
- maxWidth: "100%",
130
- maxHeight: "100%"
131
- }
132
- }), (fetchedData === null || fetchedData === void 0 ? void 0 : fetchedData.resampled) && /*#__PURE__*/React.createElement(Alert, {
133
- variant: "warning"
134
- }, /*#__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, {
135
- placement: "top",
136
- 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.")
137
- }, /*#__PURE__*/React.createElement(FontAwesomeIcon, {
138
- icon: faCircleInfo
139
- }))));
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
+ });
140
159
  }
141
- return /*#__PURE__*/React.createElement("div", {
142
- className: "cherita-violin"
143
- }, mode === VIOLIN_MODES.MULTIKEY && /*#__PURE__*/React.createElement(Alert, {
144
- variant: "light"
145
- }, "Select features"), mode === VIOLIN_MODES.GROUPBY && /*#__PURE__*/React.createElement(Alert, {
146
- variant: "light"
147
- }, "Select categories and a 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
+ });
148
188
  } else {
149
- return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Alert, {
150
- variant: "danger"
151
- }, 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
+ });
152
196
  }
153
197
  }
@@ -1,8 +1,12 @@
1
- import React from "react";
2
- import { Form } from "react-bootstrap";
3
- import { ScaleSelect } from "../controls/Controls";
1
+ import { Form } from 'react-bootstrap';
2
+ import { ScaleSelect } from '../controls/Controls';
3
+ import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
4
4
  export function ViolinControls() {
5
- return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Form, null, /*#__PURE__*/React.createElement(ScaleSelect, {
6
- plot: "violinplot"
7
- })));
5
+ return /*#__PURE__*/_jsx(_Fragment, {
6
+ children: /*#__PURE__*/_jsx(Form, {
7
+ children: /*#__PURE__*/_jsx(ScaleSelect, {
8
+ plot: "violinplot"
9
+ })
10
+ })
11
+ });
8
12
  }