@haniffalab/cherita-react 1.5.0 → 2.0.0
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.
- package/dist/cjs/components/dotplot/Dotplot.js +24 -19
- package/dist/cjs/components/heatmap/Heatmap.js +24 -19
- package/dist/cjs/components/matrixplot/Matrixplot.js +24 -19
- package/dist/cjs/components/obs-list/ObsItem.js +2 -2
- package/dist/cjs/components/offcanvas/{index.js → OffCanvas.js} +34 -1
- package/dist/cjs/components/{full-page → plot}/PlotAlert.js +1 -1
- package/dist/cjs/components/scatterplot/Scatterplot.js +57 -32
- package/dist/cjs/components/scatterplot/ScatterplotControls.js +74 -28
- package/dist/cjs/components/scatterplot/SpatialControls.js +37 -24
- package/dist/cjs/components/search-bar/SearchBar.js +9 -4
- package/dist/cjs/components/search-bar/SearchInfo.js +68 -25
- package/dist/cjs/components/search-bar/SearchResults.js +56 -47
- package/dist/cjs/components/toolbar/Toolbar.js +47 -42
- package/dist/cjs/components/var-list/VarList.js +18 -12
- package/dist/cjs/components/var-list/VarSet.js +1 -1
- package/dist/cjs/components/violin/Violin.js +26 -21
- package/dist/cjs/context/DatasetContext.js +10 -2
- package/dist/cjs/context/SettingsContext.js +19 -5
- package/dist/cjs/helpers/zarr-helper.js +20 -6
- package/dist/cjs/index.js +16 -23
- package/dist/cjs/utils/Skeleton.js +38 -2
- package/dist/cjs/utils/Slider.js +61 -0
- package/dist/cjs/utils/VirtualizedTable.js +97 -0
- package/dist/cjs/utils/parquetData.js +60 -0
- package/dist/cjs/utils/useNCBIData.js +35 -0
- package/dist/cjs/utils/usePlotVisibility.js +21 -0
- package/dist/cjs/utils/zarrData.js +51 -2
- package/dist/cjs/{components/plot/Plot.js → views/ObservationFeature/EmbeddedPlot.js} +41 -37
- package/dist/cjs/{components/full-page/FullPage.js → views/ObservationFeature/StandardView.js} +40 -49
- package/dist/cjs/views/ObservationFeature/index.js +12 -0
- package/dist/cjs/views/PerturbationMap/EmbeddedPlot.js +56 -0
- package/dist/cjs/views/PerturbationMap/ObsExplorer.js +299 -0
- package/dist/cjs/{apps/perturbgen/PerturbGen.js → views/PerturbationMap/StandardView.js} +19 -27
- package/dist/cjs/views/PerturbationMap/index.js +12 -0
- package/dist/css/cherita.css +16 -7
- package/dist/css/cherita.css.map +1 -1
- package/dist/esm/components/dotplot/Dotplot.js +25 -20
- package/dist/esm/components/heatmap/Heatmap.js +25 -20
- package/dist/esm/components/matrixplot/Matrixplot.js +25 -20
- package/dist/esm/components/obs-list/ObsItem.js +2 -2
- package/dist/esm/components/offcanvas/{index.js → OffCanvas.js} +33 -1
- package/dist/esm/components/{full-page → plot}/PlotAlert.js +1 -1
- package/dist/esm/components/scatterplot/Scatterplot.js +57 -32
- package/dist/esm/components/scatterplot/ScatterplotControls.js +74 -28
- package/dist/esm/components/scatterplot/SpatialControls.js +37 -24
- package/dist/esm/components/search-bar/SearchBar.js +9 -4
- package/dist/esm/components/search-bar/SearchInfo.js +69 -26
- package/dist/esm/components/search-bar/SearchResults.js +56 -47
- package/dist/esm/components/toolbar/Toolbar.js +44 -39
- package/dist/esm/components/var-list/VarList.js +18 -12
- package/dist/esm/components/var-list/VarSet.js +1 -1
- package/dist/esm/components/violin/Violin.js +27 -22
- package/dist/esm/context/DatasetContext.js +10 -2
- package/dist/esm/context/SettingsContext.js +19 -5
- package/dist/esm/helpers/zarr-helper.js +19 -5
- package/dist/esm/index.js +4 -5
- package/dist/esm/utils/Skeleton.js +35 -1
- package/dist/esm/utils/Slider.js +54 -0
- package/dist/esm/utils/VirtualizedTable.js +89 -0
- package/dist/esm/utils/parquetData.js +51 -0
- package/dist/esm/utils/useNCBIData.js +28 -0
- package/dist/esm/utils/usePlotVisibility.js +14 -0
- package/dist/esm/utils/zarrData.js +48 -0
- package/dist/esm/{components/plot/Plot.js → views/ObservationFeature/EmbeddedPlot.js} +37 -33
- package/dist/esm/{components/full-page/FullPage.js → views/ObservationFeature/StandardView.js} +35 -44
- package/dist/esm/views/ObservationFeature/index.js +6 -0
- package/dist/esm/views/PerturbationMap/EmbeddedPlot.js +50 -0
- package/dist/esm/views/PerturbationMap/ObsExplorer.js +292 -0
- package/dist/esm/{apps/perturbgen/PerturbGen.js → views/PerturbationMap/StandardView.js} +15 -23
- package/dist/esm/views/PerturbationMap/index.js +6 -0
- package/package.json +8 -4
- package/scss/cherita.scss +1 -1
- package/scss/components/layouts.scss +0 -1
- package/scss/components/lists.scss +1 -1
- package/scss/components/plotly.scss +10 -1
- package/scss/components/plots.scss +7 -4
- package/dist/cjs/apps/perturbgen/ObsExplorer.js +0 -153
- package/dist/esm/apps/perturbgen/ObsExplorer.js +0 -147
- /package/dist/cjs/components/{full-page → plot}/PlotTypeSelector.js +0 -0
- /package/dist/esm/components/{full-page → plot}/PlotTypeSelector.js +0 -0
|
@@ -6,16 +6,19 @@ function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e =
|
|
|
6
6
|
import { useState, useEffect } from 'react';
|
|
7
7
|
import { faPlus } from '@fortawesome/free-solid-svg-icons';
|
|
8
8
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
9
|
+
import Tooltip from '@mui/material/Tooltip';
|
|
9
10
|
import _ from 'lodash';
|
|
10
11
|
import { Button, ListGroup } from 'react-bootstrap';
|
|
11
12
|
import { VAR_SORT } from '../../constants/constants';
|
|
12
13
|
import { useDataset } from '../../context/DatasetContext';
|
|
13
14
|
import { useSettings, useSettingsDispatch } from '../../context/SettingsContext';
|
|
14
15
|
import { useFetch } from '../../utils/requests';
|
|
16
|
+
import { useNCBIData } from '../../utils/useNCBIData';
|
|
15
17
|
import { VarDiseaseInfo } from '../var-list/VarItem';
|
|
16
18
|
import { sortMeans, useVarMean } from '../var-list/VarList';
|
|
17
|
-
import { jsx as _jsx,
|
|
19
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
18
20
|
export function VarInfo(_ref) {
|
|
21
|
+
var _ncbiData$reports;
|
|
19
22
|
let {
|
|
20
23
|
varItem
|
|
21
24
|
} = _ref;
|
|
@@ -32,6 +35,14 @@ export function VarInfo(_ref) {
|
|
|
32
35
|
});
|
|
33
36
|
});
|
|
34
37
|
}, [varItem.name]);
|
|
38
|
+
const {
|
|
39
|
+
fetchedData: ncbiData,
|
|
40
|
+
isPending: isNCBIPending,
|
|
41
|
+
serverError: ncbiError
|
|
42
|
+
} = useNCBIData({
|
|
43
|
+
symbol: varItem.name
|
|
44
|
+
});
|
|
45
|
+
const geneDescription = ncbiData === null || ncbiData === void 0 || (_ncbiData$reports = ncbiData.reports) === null || _ncbiData$reports === void 0 || (_ncbiData$reports = _ncbiData$reports[0]) === null || _ncbiData$reports === void 0 || (_ncbiData$reports = _ncbiData$reports.gene) === null || _ncbiData$reports === void 0 || (_ncbiData$reports = _ncbiData$reports.summary) === null || _ncbiData$reports === void 0 || (_ncbiData$reports = _ncbiData$reports[0]) === null || _ncbiData$reports === void 0 ? void 0 : _ncbiData$reports.description;
|
|
35
46
|
const {
|
|
36
47
|
fetchedData,
|
|
37
48
|
isPending,
|
|
@@ -42,13 +53,42 @@ export function VarInfo(_ref) {
|
|
|
42
53
|
});
|
|
43
54
|
const hasDiseaseInfo = !isPending && !serverError && !!(fetchedData !== null && fetchedData !== void 0 && fetchedData.length);
|
|
44
55
|
return /*#__PURE__*/_jsxs("div", {
|
|
45
|
-
children: [/*#__PURE__*/_jsx("
|
|
56
|
+
children: [/*#__PURE__*/_jsx("h2", {
|
|
46
57
|
children: varItem.name
|
|
58
|
+
}), isNCBIPending && /*#__PURE__*/_jsx("p", {
|
|
59
|
+
className: "text-muted small",
|
|
60
|
+
children: "Loading gene description\u2026"
|
|
61
|
+
}), !isNCBIPending && !ncbiError && geneDescription && /*#__PURE__*/_jsxs(_Fragment, {
|
|
62
|
+
children: [/*#__PURE__*/_jsx("p", {
|
|
63
|
+
className: "small",
|
|
64
|
+
children: geneDescription
|
|
65
|
+
}), /*#__PURE__*/_jsxs("p", {
|
|
66
|
+
className: "text-muted small",
|
|
67
|
+
children: ["Data fetched from", ' ', /*#__PURE__*/_jsx("a", {
|
|
68
|
+
href: "https://www.ncbi.nlm.nih.gov/datasets/docs/v2/api/rest-api/",
|
|
69
|
+
target: "_blank",
|
|
70
|
+
rel: "noreferrer",
|
|
71
|
+
children: "NCBI API"
|
|
72
|
+
}), ' · ', /*#__PURE__*/_jsx("a", {
|
|
73
|
+
href: "https://www.ncbi.nlm.nih.gov/gene/?term=".concat(encodeURIComponent(varItem.name)),
|
|
74
|
+
target: "_blank",
|
|
75
|
+
rel: "noreferrer",
|
|
76
|
+
children: "Gene page"
|
|
77
|
+
})]
|
|
78
|
+
})]
|
|
47
79
|
}), !!dataset.diseaseDatasets.length && isPending && /*#__PURE__*/_jsx("p", {
|
|
48
80
|
children: "Loading..."
|
|
49
81
|
}), hasDiseaseInfo && /*#__PURE__*/_jsxs(_Fragment, {
|
|
50
|
-
children: [/*#__PURE__*/_jsx("
|
|
51
|
-
|
|
82
|
+
children: [/*#__PURE__*/_jsx("h5", {
|
|
83
|
+
className: "fw-bold mb-2",
|
|
84
|
+
children: /*#__PURE__*/_jsx(Tooltip, {
|
|
85
|
+
title: /*#__PURE__*/_jsx(_Fragment, {
|
|
86
|
+
children: "Reported and inferred diseases associated with this gene, including supporting metadata."
|
|
87
|
+
}),
|
|
88
|
+
placement: "left",
|
|
89
|
+
arrow: true,
|
|
90
|
+
children: "Associated Diseases"
|
|
91
|
+
})
|
|
52
92
|
}), /*#__PURE__*/_jsx(VarDiseaseInfo, {
|
|
53
93
|
data: fetchedData
|
|
54
94
|
})]
|
|
@@ -104,29 +144,32 @@ export function DiseaseInfo(_ref2) {
|
|
|
104
144
|
}
|
|
105
145
|
}, [settings.varSort.disease.sort, settings.varSort.disease.sortOrder, diseaseVars, varMeans.fetchedData, varMeans.isPending, varMeans.serverError]);
|
|
106
146
|
const diseaseVarList = _.map(sortedDiseaseVars, v => {
|
|
107
|
-
return /*#__PURE__*/_jsx(
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
children:
|
|
111
|
-
className: "d-flex align-items-center
|
|
112
|
-
children: /*#__PURE__*/_jsx(
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
147
|
+
return /*#__PURE__*/_jsx("div", {
|
|
148
|
+
className: "virtualized-list-wrapper",
|
|
149
|
+
children: /*#__PURE__*/_jsx(ListGroup.Item, {
|
|
150
|
+
children: /*#__PURE__*/_jsxs("div", {
|
|
151
|
+
className: "d-flex justify-content-between align-items-center w-100",
|
|
152
|
+
children: [v.name, /*#__PURE__*/_jsx("div", {
|
|
153
|
+
className: "d-flex align-items-center gap-1",
|
|
154
|
+
children: /*#__PURE__*/_jsx(Button, {
|
|
155
|
+
type: "button",
|
|
156
|
+
className: "m-0 p-0 px-1",
|
|
157
|
+
variant: "outline-secondary",
|
|
158
|
+
title: "Add to list",
|
|
159
|
+
onClick: () => {
|
|
160
|
+
handleSelect(dispatch, {
|
|
161
|
+
name: v.name,
|
|
162
|
+
index: v.index,
|
|
163
|
+
matrix_index: v.matrix_index
|
|
164
|
+
});
|
|
165
|
+
},
|
|
166
|
+
children: /*#__PURE__*/_jsx(FontAwesomeIcon, {
|
|
167
|
+
icon: faPlus
|
|
168
|
+
})
|
|
126
169
|
})
|
|
127
|
-
})
|
|
128
|
-
})
|
|
129
|
-
})
|
|
170
|
+
})]
|
|
171
|
+
})
|
|
172
|
+
}, v.gene_id)
|
|
130
173
|
}, v.gene_id);
|
|
131
174
|
});
|
|
132
175
|
const isPending = diseaseData.isPending || varMeans.isPending && settings.varSort.disease.sort === VAR_SORT.MATRIX;
|
|
@@ -93,7 +93,7 @@ export function VarSearchResults(props) {
|
|
|
93
93
|
searchHook: useVarSearch,
|
|
94
94
|
emptyLabel: "Search features",
|
|
95
95
|
itemRenderer: _ref2 => {
|
|
96
|
-
var _item$index;
|
|
96
|
+
var _item$index, _item$index2;
|
|
97
97
|
let {
|
|
98
98
|
item,
|
|
99
99
|
dispatch,
|
|
@@ -102,25 +102,28 @@ export function VarSearchResults(props) {
|
|
|
102
102
|
setSelectedResult,
|
|
103
103
|
isStale
|
|
104
104
|
} = _ref2;
|
|
105
|
-
return /*#__PURE__*/_jsx(
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
children:
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
105
|
+
return /*#__PURE__*/_jsx("div", {
|
|
106
|
+
className: "virtualized-list-wrapper",
|
|
107
|
+
children: /*#__PURE__*/_jsx(ListGroup.Item, {
|
|
108
|
+
onClick: () => setSelectedResult(item),
|
|
109
|
+
active: (selectedResult === null || selectedResult === void 0 ? void 0 : selectedResult.index) === item.index,
|
|
110
|
+
children: /*#__PURE__*/_jsxs("div", {
|
|
111
|
+
className: "d-flex justify-content-between align-items-center w-100",
|
|
112
|
+
children: [/*#__PURE__*/_jsx("div", {
|
|
113
|
+
children: item.name
|
|
114
|
+
}), /*#__PURE__*/_jsx(Button, {
|
|
115
|
+
type: "button",
|
|
116
|
+
className: "m-0 p-0 px-1",
|
|
117
|
+
variant: "outline-secondary",
|
|
118
|
+
title: "Add to list",
|
|
119
|
+
disabled: isStale,
|
|
120
|
+
onClick: () => handleSelect(dispatch, item),
|
|
121
|
+
children: /*#__PURE__*/_jsx(FontAwesomeIcon, {
|
|
122
|
+
icon: faPlus
|
|
123
|
+
})
|
|
124
|
+
})]
|
|
125
|
+
})
|
|
126
|
+
}, (_item$index2 = item.index) !== null && _item$index2 !== void 0 ? _item$index2 : item.name)
|
|
124
127
|
}, (_item$index = item.index) !== null && _item$index !== void 0 ? _item$index : item.name);
|
|
125
128
|
}
|
|
126
129
|
}));
|
|
@@ -145,25 +148,28 @@ export function ObsSearchResults(props) {
|
|
|
145
148
|
});
|
|
146
149
|
if (closeModal) closeModal();
|
|
147
150
|
};
|
|
148
|
-
return /*#__PURE__*/_jsx(
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
children:
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
151
|
+
return /*#__PURE__*/_jsx("div", {
|
|
152
|
+
className: "virtualized-list-wrapper",
|
|
153
|
+
children: /*#__PURE__*/_jsx(ListGroup.Item, {
|
|
154
|
+
onClick: () => setSelectedResult(item),
|
|
155
|
+
active: (selectedResult === null || selectedResult === void 0 ? void 0 : selectedResult.matrix_index) === item.matrix_index,
|
|
156
|
+
children: /*#__PURE__*/_jsxs("div", {
|
|
157
|
+
className: "d-flex justify-content-between align-items-center w-100",
|
|
158
|
+
children: [/*#__PURE__*/_jsx("div", {
|
|
159
|
+
children: item.name
|
|
160
|
+
}), /*#__PURE__*/_jsx(Button, {
|
|
161
|
+
type: "button",
|
|
162
|
+
className: "m-0 p-0 px-1",
|
|
163
|
+
variant: "outline-secondary",
|
|
164
|
+
title: "Add to list",
|
|
165
|
+
disabled: isStale,
|
|
166
|
+
onClick: () => onObsSelect(dispatch, item, props.handleClose),
|
|
167
|
+
children: /*#__PURE__*/_jsx(FontAwesomeIcon, {
|
|
168
|
+
icon: faPlus
|
|
169
|
+
})
|
|
170
|
+
})]
|
|
171
|
+
})
|
|
172
|
+
}, item.matrix_index)
|
|
167
173
|
}, item.matrix_index);
|
|
168
174
|
}
|
|
169
175
|
}));
|
|
@@ -175,21 +181,24 @@ export function DiseasesSearchResults(props) {
|
|
|
175
181
|
overscan: 250,
|
|
176
182
|
estimateSize: () => 32,
|
|
177
183
|
itemRenderer: _ref4 => {
|
|
178
|
-
var _item$id;
|
|
184
|
+
var _item$id, _item$id2;
|
|
179
185
|
let {
|
|
180
186
|
item,
|
|
181
187
|
setSelectedResult,
|
|
182
188
|
selectedResult
|
|
183
189
|
} = _ref4;
|
|
184
|
-
return /*#__PURE__*/_jsx(
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
190
|
+
return /*#__PURE__*/_jsx("div", {
|
|
191
|
+
className: "virtualized-list-wrapper",
|
|
192
|
+
children: /*#__PURE__*/_jsx(ListGroup.Item, {
|
|
193
|
+
onClick: () => setSelectedResult(item),
|
|
194
|
+
active: (selectedResult === null || selectedResult === void 0 ? void 0 : selectedResult.id) === item.id,
|
|
189
195
|
children: /*#__PURE__*/_jsx("div", {
|
|
190
|
-
|
|
196
|
+
className: "d-flex justify-content-between align-items-center w-100",
|
|
197
|
+
children: /*#__PURE__*/_jsx("div", {
|
|
198
|
+
children: item.disease_name
|
|
199
|
+
})
|
|
191
200
|
})
|
|
192
|
-
})
|
|
201
|
+
}, (_item$id2 = item.id) !== null && _item$id2 !== void 0 ? _item$id2 : item.name)
|
|
193
202
|
}, (_item$id = item.id) !== null && _item$id !== void 0 ? _item$id : item.name);
|
|
194
203
|
}
|
|
195
204
|
}));
|
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
import { faList, faSearch, faSliders } from '@fortawesome/free-solid-svg-icons';
|
|
2
2
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
3
|
-
import { Container, Nav, Navbar } from 'react-bootstrap';
|
|
3
|
+
import { Container, Nav, Navbar, Button, ButtonGroup } from 'react-bootstrap';
|
|
4
|
+
import usePlotVisibility from '../../utils/usePlotVisibility';
|
|
4
5
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
5
6
|
export const Toolbar = _ref => {
|
|
6
7
|
let {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
setShowVars,
|
|
12
|
-
setShowControls
|
|
8
|
+
setShowCategories,
|
|
9
|
+
setShowSearch,
|
|
10
|
+
setShowControls,
|
|
11
|
+
Fullscreen
|
|
13
12
|
} = _ref;
|
|
13
|
+
const {
|
|
14
|
+
showCategoriesBtn,
|
|
15
|
+
showSearchBtn
|
|
16
|
+
} = usePlotVisibility(isFullscreen);
|
|
14
17
|
return /*#__PURE__*/_jsx(Navbar, {
|
|
15
18
|
expand: "md",
|
|
16
19
|
bg: "primary",
|
|
@@ -24,25 +27,25 @@ export const Toolbar = _ref => {
|
|
|
24
27
|
id: "navbarScroll",
|
|
25
28
|
children: /*#__PURE__*/_jsxs(Nav, {
|
|
26
29
|
navbarScroll: true,
|
|
27
|
-
children: [
|
|
30
|
+
children: [showCategoriesBtn && /*#__PURE__*/_jsx(Nav.Item, {
|
|
28
31
|
className: "me-2",
|
|
29
32
|
children: /*#__PURE__*/_jsxs(Nav.Link, {
|
|
30
|
-
onClick: () =>
|
|
33
|
+
onClick: () => setShowCategories(true),
|
|
31
34
|
children: [/*#__PURE__*/_jsx(FontAwesomeIcon, {
|
|
32
35
|
icon: faList,
|
|
33
36
|
className: "me-2"
|
|
34
37
|
}), "Explore Categories"]
|
|
35
38
|
})
|
|
36
|
-
}),
|
|
39
|
+
}), showSearchBtn && /*#__PURE__*/_jsx(Nav.Item, {
|
|
37
40
|
className: "me-2",
|
|
38
41
|
children: /*#__PURE__*/_jsxs(Nav.Link, {
|
|
39
|
-
onClick: () =>
|
|
42
|
+
onClick: () => setShowSearch(true),
|
|
40
43
|
children: [/*#__PURE__*/_jsx(FontAwesomeIcon, {
|
|
41
44
|
icon: faSearch,
|
|
42
45
|
className: "me-2"
|
|
43
46
|
}), "Search Genes"]
|
|
44
47
|
})
|
|
45
|
-
}),
|
|
48
|
+
}), /*#__PURE__*/_jsx(Nav.Item, {
|
|
46
49
|
className: "me-2",
|
|
47
50
|
children: /*#__PURE__*/_jsxs(Nav.Link, {
|
|
48
51
|
onClick: () => setShowControls(true),
|
|
@@ -51,44 +54,46 @@ export const Toolbar = _ref => {
|
|
|
51
54
|
className: "me-2"
|
|
52
55
|
}), "Controls"]
|
|
53
56
|
})
|
|
54
|
-
})]
|
|
57
|
+
}), ' ']
|
|
55
58
|
})
|
|
56
59
|
})]
|
|
57
60
|
})
|
|
58
61
|
});
|
|
59
62
|
};
|
|
60
|
-
export const
|
|
63
|
+
export const PlotlyToolbar = _ref2 => {
|
|
61
64
|
let {
|
|
62
|
-
|
|
65
|
+
setShowCategories,
|
|
66
|
+
setShowSearch,
|
|
67
|
+
isFullscreen
|
|
63
68
|
} = _ref2;
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
69
|
+
const {
|
|
70
|
+
showCategoriesBtn,
|
|
71
|
+
showSearchBtn
|
|
72
|
+
} = usePlotVisibility(isFullscreen);
|
|
73
|
+
return /*#__PURE__*/_jsxs(ButtonGroup, {
|
|
74
|
+
children: [showCategoriesBtn && /*#__PURE__*/_jsxs(Button, {
|
|
75
|
+
variant: "primary",
|
|
76
|
+
onClick: () => setShowCategories(true),
|
|
77
|
+
title: "Explore Categories",
|
|
78
|
+
children: [/*#__PURE__*/_jsx(FontAwesomeIcon, {
|
|
79
|
+
icon: faList,
|
|
80
|
+
className: "me-1"
|
|
81
|
+
}), "Categories"]
|
|
82
|
+
}), showSearchBtn && /*#__PURE__*/_jsxs(Button, {
|
|
83
|
+
variant: "primary",
|
|
84
|
+
onClick: () => setShowSearch(true),
|
|
85
|
+
title: "Search Genes",
|
|
86
|
+
children: [/*#__PURE__*/_jsx(FontAwesomeIcon, {
|
|
87
|
+
icon: faSearch,
|
|
88
|
+
className: "me-1"
|
|
89
|
+
}), "Genes"]
|
|
90
|
+
})]
|
|
91
|
+
});
|
|
73
92
|
};
|
|
74
|
-
export const
|
|
93
|
+
export const PlotlyModebarControls = _ref3 => {
|
|
75
94
|
let {
|
|
76
95
|
onClick
|
|
77
96
|
} = _ref3;
|
|
78
|
-
return {
|
|
79
|
-
name: 'Features',
|
|
80
|
-
icon: {
|
|
81
|
-
width: 512,
|
|
82
|
-
height: 512,
|
|
83
|
-
path: faSearch.icon[4]
|
|
84
|
-
},
|
|
85
|
-
click: onClick
|
|
86
|
-
};
|
|
87
|
-
};
|
|
88
|
-
export const ControlsPlotlyToolbar = _ref4 => {
|
|
89
|
-
let {
|
|
90
|
-
onClick
|
|
91
|
-
} = _ref4;
|
|
92
97
|
return {
|
|
93
98
|
name: 'Controls',
|
|
94
99
|
icon: {
|
|
@@ -96,21 +96,27 @@ export function VarNamesList(_ref) {
|
|
|
96
96
|
}
|
|
97
97
|
}, [settings.varSort.var.sort, settings.varSort.var.sortOrder, varMeans.isPending, varMeans.serverError, varMeans.fetchedData, settingsVars]);
|
|
98
98
|
const makeListItem = item => {
|
|
99
|
-
return /*#__PURE__*/_jsx(
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
99
|
+
return /*#__PURE__*/_jsx("div", {
|
|
100
|
+
className: "virtualized-list-wrapper",
|
|
101
|
+
children: /*#__PURE__*/_jsx(ListGroup.Item, {
|
|
102
|
+
children: /*#__PURE__*/_jsx(VarItem, {
|
|
103
|
+
item: item,
|
|
104
|
+
active: active,
|
|
105
|
+
mode: mode
|
|
106
|
+
})
|
|
107
|
+
}, item.matrix_index)
|
|
105
108
|
}, item.matrix_index);
|
|
106
109
|
};
|
|
107
110
|
const makeSetListItem = set => {
|
|
108
|
-
return /*#__PURE__*/_jsx(
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
111
|
+
return /*#__PURE__*/_jsx("div", {
|
|
112
|
+
className: "virtualized-list-wrapper",
|
|
113
|
+
children: /*#__PURE__*/_jsx(ListGroup.Item, {
|
|
114
|
+
children: /*#__PURE__*/_jsx(VarSet, {
|
|
115
|
+
set: set,
|
|
116
|
+
active: active,
|
|
117
|
+
mode: mode
|
|
118
|
+
})
|
|
119
|
+
}, set.name)
|
|
114
120
|
}, set.name);
|
|
115
121
|
};
|
|
116
122
|
const varList = _.map(sortedVars, item => {
|
|
@@ -3,10 +3,10 @@ import { faCheck, faChevronDown, faChevronUp, faCircleInfo, faDroplet, faPlus, f
|
|
|
3
3
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
4
4
|
import _ from 'lodash';
|
|
5
5
|
import { Button, Collapse, ListGroup, OverlayTrigger, Tooltip } from 'react-bootstrap';
|
|
6
|
+
import { SelectionItem } from './VarItem';
|
|
6
7
|
import { COLOR_ENCODINGS, SELECTION_MODES } from '../../constants/constants';
|
|
7
8
|
import { useSettings, useSettingsDispatch } from '../../context/SettingsContext';
|
|
8
9
|
import { SearchModal } from '../search-bar/SearchBar';
|
|
9
|
-
import { SelectionItem } from './VarItem';
|
|
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";
|
|
@@ -17,20 +17,19 @@ import { LoadingSpinner } from '../../utils/LoadingIndicators';
|
|
|
17
17
|
import { useDebouncedFetch } from '../../utils/requests';
|
|
18
18
|
import { useSelectedMultiVar, useSelectedObs, useSelectedVar } from '../../utils/Resolver';
|
|
19
19
|
import { StyledTooltip } from '../../utils/StyledTooltip';
|
|
20
|
-
import
|
|
21
|
-
import {
|
|
20
|
+
import usePlotVisibility from '../../utils/usePlotVisibility';
|
|
21
|
+
import { PlotAlert } from '../plot/PlotAlert';
|
|
22
|
+
import { PlotlyToolbar, PlotlyModebarControls } from '../toolbar/Toolbar';
|
|
22
23
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
23
24
|
export function Violin(_ref) {
|
|
24
25
|
let {
|
|
25
26
|
mode = VIOLIN_MODES.MULTIKEY,
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
showCtrlsBtn = false,
|
|
29
|
-
setShowObs,
|
|
30
|
-
setShowVars,
|
|
27
|
+
setShowCategories,
|
|
28
|
+
setShowSearch,
|
|
31
29
|
setShowControls,
|
|
32
30
|
plotType,
|
|
33
|
-
setPlotType
|
|
31
|
+
setPlotType,
|
|
32
|
+
isFullscreen = false
|
|
34
33
|
} = _ref;
|
|
35
34
|
const ENDPOINT = 'violin';
|
|
36
35
|
const dataset = useDataset();
|
|
@@ -45,6 +44,10 @@ export function Violin(_ref) {
|
|
|
45
44
|
const selectedMultiVar = useSelectedMultiVar();
|
|
46
45
|
const selectedVar = useSelectedVar();
|
|
47
46
|
const selectedObs = useSelectedObs();
|
|
47
|
+
const {
|
|
48
|
+
showCategoriesBtn,
|
|
49
|
+
showSearchBtn
|
|
50
|
+
} = usePlotVisibility(isFullscreen);
|
|
48
51
|
const params = useMemo(() => {
|
|
49
52
|
var _selectedObs$omit;
|
|
50
53
|
return _objectSpread({
|
|
@@ -104,19 +107,21 @@ export function Violin(_ref) {
|
|
|
104
107
|
setLayout({});
|
|
105
108
|
}
|
|
106
109
|
}, [fetchedData, hasSelections, isPending, serverError]);
|
|
107
|
-
const
|
|
108
|
-
onClick: setShowObs
|
|
109
|
-
}), showVarsBtn && VarPlotlyToolbar({
|
|
110
|
-
onClick: setShowVars
|
|
111
|
-
}), showCtrlsBtn && ControlsPlotlyToolbar({
|
|
110
|
+
const modeBarButtons = [_.compact([PlotlyModebarControls({
|
|
112
111
|
onClick: setShowControls
|
|
113
|
-
})]);
|
|
114
|
-
const modeBarButtons = customModeBarButtons.length ? [customModeBarButtons, PLOTLY_MODEBAR_BUTTONS] : [PLOTLY_MODEBAR_BUTTONS];
|
|
112
|
+
}), ...PLOTLY_MODEBAR_BUTTONS])];
|
|
115
113
|
if (!serverError) {
|
|
116
114
|
if (hasSelections) {
|
|
117
115
|
return /*#__PURE__*/_jsxs("div", {
|
|
118
116
|
className: "cherita-plot cherita-violin",
|
|
119
|
-
children: [
|
|
117
|
+
children: [/*#__PURE__*/_jsx("div", {
|
|
118
|
+
className: "plotly-toolbar",
|
|
119
|
+
children: /*#__PURE__*/_jsx(PlotlyToolbar, {
|
|
120
|
+
setShowCategories: setShowCategories,
|
|
121
|
+
setShowSearch: setShowSearch,
|
|
122
|
+
isFullscreen: isFullscreen
|
|
123
|
+
})
|
|
124
|
+
}), isPending && /*#__PURE__*/_jsx(LoadingSpinner, {}), /*#__PURE__*/_jsxs("div", {
|
|
120
125
|
className: "d-flex flex-column h-100",
|
|
121
126
|
children: [/*#__PURE__*/_jsx("div", {
|
|
122
127
|
className: "flex-grow-1 position-relative",
|
|
@@ -167,23 +172,23 @@ export function Violin(_ref) {
|
|
|
167
172
|
setPlotType: setPlotType,
|
|
168
173
|
children: [mode === VIOLIN_MODES.MULTIKEY && /*#__PURE__*/_jsxs("p", {
|
|
169
174
|
className: "p-0 m-0",
|
|
170
|
-
children: ["Select one or more", ' ',
|
|
175
|
+
children: ["Select one or more", ' ', showSearchBtn ? /*#__PURE__*/_jsx(Button, {
|
|
171
176
|
variant: "link",
|
|
172
177
|
className: "border-0 p-0 align-baseline",
|
|
173
|
-
onClick:
|
|
178
|
+
onClick: setShowSearch,
|
|
174
179
|
children: "features"
|
|
175
180
|
}) : 'features', ' ', "to display their expression distributions across all observations."]
|
|
176
181
|
}), mode === VIOLIN_MODES.GROUPBY && /*#__PURE__*/_jsxs("p", {
|
|
177
182
|
className: "p-0 m-0",
|
|
178
|
-
children: ["Select a", ' ',
|
|
183
|
+
children: ["Select a", ' ', showCategoriesBtn ? /*#__PURE__*/_jsx(Button, {
|
|
179
184
|
variant: "link",
|
|
180
185
|
className: "border-0 p-0 align-baseline",
|
|
181
|
-
onClick:
|
|
186
|
+
onClick: setShowCategories,
|
|
182
187
|
children: "category"
|
|
183
|
-
}) : 'category', ' ', "to group observations, and choose a", ' ',
|
|
188
|
+
}) : 'category', ' ', "to group observations, and choose a", ' ', showSearchBtn ? /*#__PURE__*/_jsx(Button, {
|
|
184
189
|
variant: "link",
|
|
185
190
|
className: "border-0 p-0 align-baseline",
|
|
186
|
-
onClick:
|
|
191
|
+
onClick: setShowSearch,
|
|
187
192
|
children: "feature"
|
|
188
193
|
}) : 'feature', ' ', "to view its distribution within each group."]
|
|
189
194
|
})]
|
|
@@ -51,7 +51,7 @@ const persistOptions = {
|
|
|
51
51
|
return false;
|
|
52
52
|
}
|
|
53
53
|
},
|
|
54
|
-
buster: "
|
|
54
|
+
buster: "2.0.0" || '0.0.0'
|
|
55
55
|
// @TODO: add maxAge and api version numbers as buster
|
|
56
56
|
};
|
|
57
57
|
const initialDataset = {
|
|
@@ -64,7 +64,15 @@ const initialDataset = {
|
|
|
64
64
|
defaultSettings: {},
|
|
65
65
|
canOverrideSettings: true,
|
|
66
66
|
useUnsColors: false,
|
|
67
|
-
isPseudospatial: false
|
|
67
|
+
isPseudospatial: false,
|
|
68
|
+
obsExplorer: {
|
|
69
|
+
obsCols: [],
|
|
70
|
+
symbolCol: null,
|
|
71
|
+
// obs col with gene symbols to query NCBI for additional info in ObsExplorer
|
|
72
|
+
dataUrl: null,
|
|
73
|
+
// for additional data in a remote .parquet file
|
|
74
|
+
dataFilterCols: null // map of obs cols to filter data in .parquet file
|
|
75
|
+
}
|
|
68
76
|
};
|
|
69
77
|
export function DatasetProvider(_ref2) {
|
|
70
78
|
let {
|
|
@@ -16,7 +16,6 @@ export const SettingsDispatchContext = /*#__PURE__*/createContext(null);
|
|
|
16
16
|
const initialSettings = {
|
|
17
17
|
selectedObs: null,
|
|
18
18
|
// { name: "obs_name", omit: ["obs_item"], bins: {} }
|
|
19
|
-
selectedObsIndex: null,
|
|
20
19
|
selectedVar: null,
|
|
21
20
|
// { name: "var_name", isSet: false } or { name: "var_set_name", isSet: true, vars: [{ name: "var1" }, { name: "var2" }] }
|
|
22
21
|
selectedObsm: null,
|
|
@@ -49,7 +48,8 @@ const initialSettings = {
|
|
|
49
48
|
violinplot: VIOLINPLOT_SCALES.WIDTH.value
|
|
50
49
|
},
|
|
51
50
|
meanOnlyExpressed: false,
|
|
52
|
-
expressionCutoff: 0.0
|
|
51
|
+
expressionCutoff: 0.0,
|
|
52
|
+
radiusScale: {}
|
|
53
53
|
},
|
|
54
54
|
varSort: {
|
|
55
55
|
var: {
|
|
@@ -70,6 +70,8 @@ const initialSettings = {
|
|
|
70
70
|
opacity: 1
|
|
71
71
|
}
|
|
72
72
|
},
|
|
73
|
+
// for obsExplorer
|
|
74
|
+
selectedObsIndex: null,
|
|
73
75
|
// dataset resolved values
|
|
74
76
|
data: {
|
|
75
77
|
// store resolved obs and vars from selectedObs, selectedVar, selectedMultiVar, vars, labelObs
|
|
@@ -164,7 +166,7 @@ export function SettingsProvider(_ref2) {
|
|
|
164
166
|
|
|
165
167
|
// If the buster is not set or does not match the current package version,
|
|
166
168
|
// reset localSettings to avoid stale data
|
|
167
|
-
if (!buster || buster !== "
|
|
169
|
+
if (!buster || buster !== "2.0.0") {
|
|
168
170
|
localSettings = {};
|
|
169
171
|
}
|
|
170
172
|
const initSettings = useRef(initializer({
|
|
@@ -189,7 +191,7 @@ export function SettingsProvider(_ref2) {
|
|
|
189
191
|
if (canOverrideSettings && settings) {
|
|
190
192
|
try {
|
|
191
193
|
localStorage.setItem(DATASET_STORAGE_KEY, JSON.stringify(_objectSpread({
|
|
192
|
-
buster: "
|
|
194
|
+
buster: "2.0.0" || '0.0.0',
|
|
193
195
|
timestamp: Date.now()
|
|
194
196
|
}, _.omit(settings, 'data'))));
|
|
195
197
|
} catch (err) {
|
|
@@ -219,7 +221,9 @@ const OBS_DATA_KEYS = ['name', 'type',
|
|
|
219
221
|
// categorical and numerical
|
|
220
222
|
'codes', 'codesMap', 'values', 'n_values', 'value_counts',
|
|
221
223
|
// numerical
|
|
222
|
-
'bins', 'min', 'max', 'mean', 'median', 'n_unique'
|
|
224
|
+
'bins', 'min', 'max', 'mean', 'median', 'n_unique',
|
|
225
|
+
// optional custom colors
|
|
226
|
+
'colors'];
|
|
223
227
|
const splitObs = obs => {
|
|
224
228
|
if (!obs) return {
|
|
225
229
|
settings: null,
|
|
@@ -590,6 +594,16 @@ function settingsReducer(settings, action) {
|
|
|
590
594
|
})
|
|
591
595
|
});
|
|
592
596
|
}
|
|
597
|
+
case 'set.controls.radiusScale':
|
|
598
|
+
{
|
|
599
|
+
return _objectSpread(_objectSpread({}, settings), {}, {
|
|
600
|
+
controls: _objectSpread(_objectSpread({}, settings.controls), {}, {
|
|
601
|
+
radiusScale: _objectSpread(_objectSpread({}, settings.controls.radiusScale), {}, {
|
|
602
|
+
[action.obsm]: action.radiusScale
|
|
603
|
+
})
|
|
604
|
+
})
|
|
605
|
+
});
|
|
606
|
+
}
|
|
593
607
|
case 'toggle.slice.obs':
|
|
594
608
|
{
|
|
595
609
|
if (settings.selectedObs && settings.selectedObs.name === action.obs.name) {
|