@haniffalab/cherita-react 1.3.0-dev.2025-05-29.ee7e9b72 → 1.3.0-dev.2025-06-04.bee6fd81
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 +35 -5
- package/dist/cjs/components/full-page/FullPage.js +108 -50
- package/dist/cjs/components/full-page/PlotTypeSelector.js +57 -0
- package/dist/cjs/components/heatmap/Heatmap.js +35 -5
- package/dist/cjs/components/matrixplot/Matrixplot.js +35 -5
- package/dist/cjs/components/obs-list/ObsItem.js +15 -4
- package/dist/cjs/components/obs-list/ObsList.js +4 -3
- package/dist/cjs/components/scatterplot/SpatialControls.js +3 -3
- package/dist/cjs/components/toolbar/Toolbar.js +102 -0
- package/dist/cjs/components/violin/Violin.js +37 -6
- package/dist/cjs/constants/constants.js +14 -2
- package/dist/cjs/index.js +15 -21
- package/dist/css/cherita.css +76 -23
- package/dist/css/cherita.css.map +1 -1
- package/dist/esm/components/dotplot/Dotplot.js +36 -6
- package/dist/esm/components/full-page/FullPage.js +110 -50
- package/dist/esm/components/full-page/PlotTypeSelector.js +50 -0
- package/dist/esm/components/heatmap/Heatmap.js +36 -6
- package/dist/esm/components/matrixplot/Matrixplot.js +36 -6
- package/dist/esm/components/obs-list/ObsItem.js +15 -4
- package/dist/esm/components/obs-list/ObsList.js +4 -3
- package/dist/esm/components/scatterplot/SpatialControls.js +3 -3
- package/dist/esm/components/toolbar/Toolbar.js +91 -0
- package/dist/esm/components/violin/Violin.js +39 -8
- package/dist/esm/constants/constants.js +13 -1
- package/dist/esm/index.js +4 -4
- package/package.json +2 -2
- package/scss/cherita.scss +0 -1
- package/scss/components/layouts.scss +69 -1
- package/scss/components/plotly.scss +19 -14
- package/dist/cjs/components/full-page/FullPagePseudospatial.js +0 -157
- package/dist/esm/components/full-page/FullPagePseudospatial.js +0 -149
|
@@ -5,15 +5,25 @@ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol"
|
|
|
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
6
|
import React, { useCallback, useEffect, useRef, useState } from "react";
|
|
7
7
|
import _ from "lodash";
|
|
8
|
-
import { Alert } from "react-bootstrap";
|
|
8
|
+
import { Alert, Button } from "react-bootstrap";
|
|
9
9
|
import Plot from "react-plotly.js";
|
|
10
|
+
import { PLOTLY_MODEBAR_BUTTONS } from "../../constants/constants";
|
|
10
11
|
import { useDataset } from "../../context/DatasetContext";
|
|
11
12
|
import { useFilteredData } from "../../context/FilterContext";
|
|
12
13
|
import { useSettings } from "../../context/SettingsContext";
|
|
13
14
|
import { LoadingSpinner } from "../../utils/LoadingIndicators";
|
|
14
15
|
import { useDebouncedFetch } from "../../utils/requests";
|
|
15
|
-
|
|
16
|
+
import { ControlsPlotlyToolbar, ObsPlotlyToolbar, VarPlotlyToolbar } from "../toolbar/Toolbar";
|
|
17
|
+
export function Heatmap(_ref) {
|
|
16
18
|
var _settings$selectedObs, _settings$selectedObs2, _settings$selectedObs3;
|
|
19
|
+
let {
|
|
20
|
+
showObsBtn = false,
|
|
21
|
+
showVarsBtn = false,
|
|
22
|
+
showCtrlsBtn = false,
|
|
23
|
+
setShowObs,
|
|
24
|
+
setShowVars,
|
|
25
|
+
setShowControls
|
|
26
|
+
} = _ref;
|
|
17
27
|
const ENDPOINT = "heatmap";
|
|
18
28
|
const dataset = useDataset();
|
|
19
29
|
const settings = useSettings();
|
|
@@ -90,17 +100,29 @@ export function Heatmap() {
|
|
|
90
100
|
colorscale.current = settings.controls.colorScale;
|
|
91
101
|
updateColorscale(colorscale.current);
|
|
92
102
|
}, [settings.controls.colorScale, updateColorscale]);
|
|
103
|
+
const customModeBarButtons = _.compact([showObsBtn && ObsPlotlyToolbar({
|
|
104
|
+
onClick: setShowObs
|
|
105
|
+
}), showVarsBtn && VarPlotlyToolbar({
|
|
106
|
+
onClick: setShowVars
|
|
107
|
+
}), showCtrlsBtn && ControlsPlotlyToolbar({
|
|
108
|
+
onClick: setShowControls
|
|
109
|
+
})]);
|
|
110
|
+
const modeBarButtons = customModeBarButtons.length ? [customModeBarButtons, PLOTLY_MODEBAR_BUTTONS] : [PLOTLY_MODEBAR_BUTTONS];
|
|
93
111
|
if (!serverError) {
|
|
94
112
|
if (hasSelections) {
|
|
95
113
|
return /*#__PURE__*/React.createElement("div", {
|
|
96
|
-
className: "cherita-heatmap position-relative"
|
|
114
|
+
className: "cherita-plot cherita-heatmap position-relative"
|
|
97
115
|
}, isPending && /*#__PURE__*/React.createElement(LoadingSpinner, null), /*#__PURE__*/React.createElement(Plot, {
|
|
98
116
|
data: data,
|
|
99
117
|
layout: layout,
|
|
100
118
|
useResizeHandler: true,
|
|
101
119
|
style: {
|
|
102
|
-
|
|
103
|
-
|
|
120
|
+
width: "100%",
|
|
121
|
+
height: "100%"
|
|
122
|
+
},
|
|
123
|
+
config: {
|
|
124
|
+
displaylogo: false,
|
|
125
|
+
modeBarButtons: modeBarButtons
|
|
104
126
|
}
|
|
105
127
|
}));
|
|
106
128
|
}
|
|
@@ -108,7 +130,15 @@ export function Heatmap() {
|
|
|
108
130
|
className: "cherita-heatmap"
|
|
109
131
|
}, /*#__PURE__*/React.createElement(Alert, {
|
|
110
132
|
variant: "light"
|
|
111
|
-
}, "Select
|
|
133
|
+
}, "Select", " ", showVarsBtn ? /*#__PURE__*/React.createElement(Button, {
|
|
134
|
+
variant: "link",
|
|
135
|
+
className: "border-0 p-0 align-baseline",
|
|
136
|
+
onClick: setShowVars
|
|
137
|
+
}, "features") : "features", " ", "and a", " ", showObsBtn ? /*#__PURE__*/React.createElement(Button, {
|
|
138
|
+
variant: "link",
|
|
139
|
+
className: "border-0 p-0 align-baseline",
|
|
140
|
+
onClick: setShowObs
|
|
141
|
+
}, "category") : "category"));
|
|
112
142
|
} else {
|
|
113
143
|
return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Alert, {
|
|
114
144
|
variant: "danger"
|
|
@@ -5,15 +5,25 @@ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol"
|
|
|
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
6
|
import React, { useCallback, useEffect, useRef, useState } from "react";
|
|
7
7
|
import _ from "lodash";
|
|
8
|
-
import { Alert } from "react-bootstrap";
|
|
8
|
+
import { Alert, Button } from "react-bootstrap";
|
|
9
9
|
import Plot from "react-plotly.js";
|
|
10
|
+
import { PLOTLY_MODEBAR_BUTTONS } from "../../constants/constants";
|
|
10
11
|
import { useDataset } from "../../context/DatasetContext";
|
|
11
12
|
import { useFilteredData } from "../../context/FilterContext";
|
|
12
13
|
import { useSettings } from "../../context/SettingsContext";
|
|
13
14
|
import { LoadingSpinner } from "../../utils/LoadingIndicators";
|
|
14
15
|
import { useDebouncedFetch } from "../../utils/requests";
|
|
15
|
-
|
|
16
|
+
import { ControlsPlotlyToolbar, ObsPlotlyToolbar, VarPlotlyToolbar } from "../toolbar/Toolbar";
|
|
17
|
+
export function Matrixplot(_ref) {
|
|
16
18
|
var _settings$selectedObs, _settings$selectedObs2, _settings$selectedObs3;
|
|
19
|
+
let {
|
|
20
|
+
showObsBtn = false,
|
|
21
|
+
showVarsBtn = false,
|
|
22
|
+
showCtrlsBtn = false,
|
|
23
|
+
setShowObs,
|
|
24
|
+
setShowVars,
|
|
25
|
+
setShowControls
|
|
26
|
+
} = _ref;
|
|
17
27
|
const ENDPOINT = "matrixplot";
|
|
18
28
|
const dataset = useDataset();
|
|
19
29
|
const settings = useSettings();
|
|
@@ -92,17 +102,29 @@ export function Matrixplot() {
|
|
|
92
102
|
colorscale.current = settings.controls.colorScale;
|
|
93
103
|
updateColorscale(colorscale.current);
|
|
94
104
|
}, [settings.controls.colorScale, updateColorscale]);
|
|
105
|
+
const customModeBarButtons = _.compact([showObsBtn && ObsPlotlyToolbar({
|
|
106
|
+
onClick: setShowObs
|
|
107
|
+
}), showVarsBtn && VarPlotlyToolbar({
|
|
108
|
+
onClick: setShowVars
|
|
109
|
+
}), showCtrlsBtn && ControlsPlotlyToolbar({
|
|
110
|
+
onClick: setShowControls
|
|
111
|
+
})]);
|
|
112
|
+
const modeBarButtons = customModeBarButtons.length ? [customModeBarButtons, PLOTLY_MODEBAR_BUTTONS] : [PLOTLY_MODEBAR_BUTTONS];
|
|
95
113
|
if (!serverError) {
|
|
96
114
|
if (hasSelections) {
|
|
97
115
|
return /*#__PURE__*/React.createElement("div", {
|
|
98
|
-
className: "cherita-matrixplot position-relative"
|
|
116
|
+
className: "cherita-plot cherita-matrixplot position-relative"
|
|
99
117
|
}, isPending && /*#__PURE__*/React.createElement(LoadingSpinner, null), /*#__PURE__*/React.createElement(Plot, {
|
|
100
118
|
data: data,
|
|
101
119
|
layout: layout,
|
|
102
120
|
useResizeHandler: true,
|
|
103
121
|
style: {
|
|
104
|
-
|
|
105
|
-
|
|
122
|
+
width: "100%",
|
|
123
|
+
height: "100%"
|
|
124
|
+
},
|
|
125
|
+
config: {
|
|
126
|
+
displaylogo: false,
|
|
127
|
+
modeBarButtons: modeBarButtons
|
|
106
128
|
}
|
|
107
129
|
}));
|
|
108
130
|
}
|
|
@@ -110,7 +132,15 @@ export function Matrixplot() {
|
|
|
110
132
|
className: "cherita-matrixplot"
|
|
111
133
|
}, /*#__PURE__*/React.createElement(Alert, {
|
|
112
134
|
variant: "light"
|
|
113
|
-
}, "Select
|
|
135
|
+
}, "Select", " ", showVarsBtn ? /*#__PURE__*/React.createElement(Button, {
|
|
136
|
+
variant: "link",
|
|
137
|
+
className: "border-0 p-0 align-baseline",
|
|
138
|
+
onClick: setShowVars
|
|
139
|
+
}, "features") : "features", " ", "and a", " ", showObsBtn ? /*#__PURE__*/React.createElement(Button, {
|
|
140
|
+
variant: "link",
|
|
141
|
+
className: "border-0 p-0 align-baseline",
|
|
142
|
+
onClick: setShowObs
|
|
143
|
+
}, "category") : "category"));
|
|
114
144
|
} else {
|
|
115
145
|
return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Alert, {
|
|
116
146
|
variant: "danger"
|
|
@@ -370,21 +370,23 @@ function ObsContinuousStats(_ref3) {
|
|
|
370
370
|
}
|
|
371
371
|
|
|
372
372
|
// @TODO: add bin controls
|
|
373
|
-
// @TODO: add histogram
|
|
374
373
|
export function ContinuousObs(_ref4) {
|
|
375
374
|
let {
|
|
376
375
|
obs,
|
|
377
376
|
toggleAll,
|
|
378
377
|
toggleObs
|
|
379
378
|
} = _ref4;
|
|
379
|
+
const settings = useSettings();
|
|
380
380
|
const {
|
|
381
381
|
isSliced
|
|
382
382
|
} = useFilteredData();
|
|
383
383
|
const totalCounts = _.sum(_.values(obs.value_counts));
|
|
384
384
|
const min = _.min(_.values(obs.codes));
|
|
385
385
|
const max = _.max(_.values(obs.codes));
|
|
386
|
+
const obsHistograms = useObsHistogram(obs);
|
|
386
387
|
const filteredObsData = useFilteredObsData(obs);
|
|
387
|
-
const getDataAtIndex = index => {
|
|
388
|
+
const getDataAtIndex = useCallback(index => {
|
|
389
|
+
var _obsHistograms$fetche2;
|
|
388
390
|
return {
|
|
389
391
|
value: obs.values[index],
|
|
390
392
|
code: obs.codes[obs.values[index]],
|
|
@@ -394,13 +396,21 @@ export function ContinuousObs(_ref4) {
|
|
|
394
396
|
},
|
|
395
397
|
isOmitted: _.includes(obs.omit, obs.codes[obs.values[index]]),
|
|
396
398
|
label: isNaN(obs.values[index]) ? "NaN" : getContinuousLabel(obs.codes[obs.values[index]], obs.bins.binEdges),
|
|
399
|
+
histogramData: settings.colorEncoding === COLOR_ENCODINGS.VAR ? {
|
|
400
|
+
data: (_obsHistograms$fetche2 = obsHistograms.fetchedData) === null || _obsHistograms$fetche2 === void 0 ? void 0 : _obsHistograms$fetche2[obs.values[index]],
|
|
401
|
+
isPending: obsHistograms.isPending,
|
|
402
|
+
altColor: isSliced
|
|
403
|
+
} : {
|
|
404
|
+
data: null,
|
|
405
|
+
isPending: false
|
|
406
|
+
},
|
|
397
407
|
filteredStats: {
|
|
398
408
|
value_counts: (filteredObsData === null || filteredObsData === void 0 ? void 0 : filteredObsData.value_counts[obs.values[index]]) || 0,
|
|
399
409
|
pct: (filteredObsData === null || filteredObsData === void 0 ? void 0 : filteredObsData.pct[obs.values[index]]) || 0
|
|
400
410
|
},
|
|
401
411
|
isSliced: isSliced
|
|
402
412
|
};
|
|
403
|
-
};
|
|
413
|
+
}, [filteredObsData === null || filteredObsData === void 0 ? void 0 : filteredObsData.pct, filteredObsData === null || filteredObsData === void 0 ? void 0 : filteredObsData.value_counts, isSliced, obs.bins.binEdges, obs.codes, obs.omit, obs.value_counts, obs.values, obsHistograms.fetchedData, obsHistograms.isPending, settings.colorEncoding, totalCounts]);
|
|
404
414
|
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(ListGroup, {
|
|
405
415
|
variant: "flush",
|
|
406
416
|
className: "cherita-list"
|
|
@@ -417,7 +427,8 @@ export function ContinuousObs(_ref4) {
|
|
|
417
427
|
min: min,
|
|
418
428
|
max: max,
|
|
419
429
|
onChange: toggleObs,
|
|
420
|
-
showColor: false
|
|
430
|
+
showColor: false,
|
|
431
|
+
estimateSize: 42
|
|
421
432
|
})), /*#__PURE__*/React.createElement(ObsContinuousStats, {
|
|
422
433
|
obs: obs
|
|
423
434
|
}));
|
|
@@ -48,7 +48,8 @@ export function ObsColsList(_ref2) {
|
|
|
48
48
|
var _settings$selectedObs;
|
|
49
49
|
let {
|
|
50
50
|
showColor = true,
|
|
51
|
-
enableObsGroups = true
|
|
51
|
+
enableObsGroups = true,
|
|
52
|
+
showSelectedAsActive = false
|
|
52
53
|
} = _ref2;
|
|
53
54
|
const ENDPOINT = "obs/cols";
|
|
54
55
|
const dataset = useDataset();
|
|
@@ -215,7 +216,7 @@ export function ObsColsList(_ref2) {
|
|
|
215
216
|
}
|
|
216
217
|
const inLabelObs = _.some(settings.labelObs, i => i.name === item.name);
|
|
217
218
|
const inSliceObs = settings.sliceBy.obs && ((_settings$selectedObs5 = settings.selectedObs) === null || _settings$selectedObs5 === void 0 ? void 0 : _settings$selectedObs5.name) === item.name;
|
|
218
|
-
const isColorEncoding = settings.colorEncoding === COLOR_ENCODINGS.OBS && ((_settings$selectedObs6 = settings.selectedObs) === null || _settings$selectedObs6 === void 0 ? void 0 : _settings$selectedObs6.name) === item.name;
|
|
219
|
+
const isColorEncoding = (showSelectedAsActive || settings.colorEncoding === COLOR_ENCODINGS.OBS) && ((_settings$selectedObs6 = settings.selectedObs) === null || _settings$selectedObs6 === void 0 ? void 0 : _settings$selectedObs6.name) === item.name;
|
|
219
220
|
return /*#__PURE__*/React.createElement("div", {
|
|
220
221
|
className: "accordion-item",
|
|
221
222
|
key: item.name
|
|
@@ -242,7 +243,7 @@ export function ObsColsList(_ref2) {
|
|
|
242
243
|
event.stopPropagation();
|
|
243
244
|
toggleColor(item);
|
|
244
245
|
},
|
|
245
|
-
title: "Is color encoding"
|
|
246
|
+
title: showSelectedAsActive ? "Is selected" : "Is color encoding"
|
|
246
247
|
}, /*#__PURE__*/React.createElement(WaterDropIcon, null)))), /*#__PURE__*/React.createElement(Accordion.Collapse, {
|
|
247
248
|
eventKey: item.name
|
|
248
249
|
}, /*#__PURE__*/React.createElement("div", {
|
|
@@ -8,9 +8,9 @@ import { OverlayTrigger, Tooltip } from "react-bootstrap";
|
|
|
8
8
|
import Button from "react-bootstrap/Button";
|
|
9
9
|
import ButtonGroup from "react-bootstrap/ButtonGroup";
|
|
10
10
|
import Dropdown from "react-bootstrap/Dropdown";
|
|
11
|
-
import { useDataset } from "../../context/DatasetContext";
|
|
12
11
|
import { OffcanvasControls } from "../offcanvas";
|
|
13
12
|
import { ScatterplotControls } from "./ScatterplotControls";
|
|
13
|
+
import { BREAKPOINTS } from "../../constants/constants";
|
|
14
14
|
import { useSettings, useSettingsDispatch } from "../../context/SettingsContext";
|
|
15
15
|
export function SpatialControls(_ref) {
|
|
16
16
|
var _features$features;
|
|
@@ -32,8 +32,8 @@ export function SpatialControls(_ref) {
|
|
|
32
32
|
const [showControls, setShowControls] = useState(false);
|
|
33
33
|
const handleCloseControls = () => setShowControls(false);
|
|
34
34
|
const handleShowControls = () => setShowControls(true);
|
|
35
|
-
const LgBreakpoint = useMediaQuery(
|
|
36
|
-
const XlBreakpoint = useMediaQuery(
|
|
35
|
+
const LgBreakpoint = useMediaQuery(BREAKPOINTS.LG);
|
|
36
|
+
const XlBreakpoint = useMediaQuery(BREAKPOINTS.XL);
|
|
37
37
|
const showObsBtn = isFullscreen ? LgBreakpoint : true;
|
|
38
38
|
const showVarsBtn = isFullscreen ? XlBreakpoint : true;
|
|
39
39
|
const onSelect = (eventKey, event) => {
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { faList, faSearch, faSliders } from "@fortawesome/free-solid-svg-icons";
|
|
3
|
+
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|
4
|
+
import { Container, Nav, Navbar } from "react-bootstrap";
|
|
5
|
+
export const Toolbar = _ref => {
|
|
6
|
+
let {
|
|
7
|
+
showObsBtn = true,
|
|
8
|
+
showVarsBtn = true,
|
|
9
|
+
showCtrlsBtn = true,
|
|
10
|
+
setShowObs,
|
|
11
|
+
setShowVars,
|
|
12
|
+
setShowControls
|
|
13
|
+
} = _ref;
|
|
14
|
+
return /*#__PURE__*/React.createElement(Navbar, {
|
|
15
|
+
expand: "md",
|
|
16
|
+
bg: "primary",
|
|
17
|
+
variant: "dark",
|
|
18
|
+
className: "cherita-navbar"
|
|
19
|
+
}, /*#__PURE__*/React.createElement(Container, {
|
|
20
|
+
fluid: true
|
|
21
|
+
}, /*#__PURE__*/React.createElement(Navbar.Toggle, {
|
|
22
|
+
"aria-controls": "navbarScroll"
|
|
23
|
+
}), /*#__PURE__*/React.createElement(Navbar.Collapse, {
|
|
24
|
+
id: "navbarScroll"
|
|
25
|
+
}, /*#__PURE__*/React.createElement(Nav, {
|
|
26
|
+
navbarScroll: true
|
|
27
|
+
}, showObsBtn && /*#__PURE__*/React.createElement(Nav.Item, {
|
|
28
|
+
className: "me-2"
|
|
29
|
+
}, /*#__PURE__*/React.createElement(Nav.Link, {
|
|
30
|
+
onClick: () => setShowObs(true)
|
|
31
|
+
}, /*#__PURE__*/React.createElement(FontAwesomeIcon, {
|
|
32
|
+
icon: faList,
|
|
33
|
+
className: "me-2"
|
|
34
|
+
}), "Explore Categories")), showVarsBtn && /*#__PURE__*/React.createElement(Nav.Item, {
|
|
35
|
+
className: "me-2"
|
|
36
|
+
}, /*#__PURE__*/React.createElement(Nav.Link, {
|
|
37
|
+
onClick: () => setShowVars(true)
|
|
38
|
+
}, /*#__PURE__*/React.createElement(FontAwesomeIcon, {
|
|
39
|
+
icon: faSearch,
|
|
40
|
+
className: "me-2"
|
|
41
|
+
}), "Search Genes")), showCtrlsBtn && /*#__PURE__*/React.createElement(Nav.Item, {
|
|
42
|
+
className: "me-2"
|
|
43
|
+
}, /*#__PURE__*/React.createElement(Nav.Link, {
|
|
44
|
+
onClick: () => setShowControls(true)
|
|
45
|
+
}, /*#__PURE__*/React.createElement(FontAwesomeIcon, {
|
|
46
|
+
icon: faSliders,
|
|
47
|
+
className: "me-2"
|
|
48
|
+
}), "Controls"))))));
|
|
49
|
+
};
|
|
50
|
+
export const ObsPlotlyToolbar = _ref2 => {
|
|
51
|
+
let {
|
|
52
|
+
onClick
|
|
53
|
+
} = _ref2;
|
|
54
|
+
return {
|
|
55
|
+
name: "Categories",
|
|
56
|
+
icon: {
|
|
57
|
+
width: 512,
|
|
58
|
+
height: 512,
|
|
59
|
+
path: faList.icon[4]
|
|
60
|
+
},
|
|
61
|
+
click: onClick
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
export const VarPlotlyToolbar = _ref3 => {
|
|
65
|
+
let {
|
|
66
|
+
onClick
|
|
67
|
+
} = _ref3;
|
|
68
|
+
return {
|
|
69
|
+
name: "Features",
|
|
70
|
+
icon: {
|
|
71
|
+
width: 512,
|
|
72
|
+
height: 512,
|
|
73
|
+
path: faSearch.icon[4]
|
|
74
|
+
},
|
|
75
|
+
click: onClick
|
|
76
|
+
};
|
|
77
|
+
};
|
|
78
|
+
export const ControlsPlotlyToolbar = _ref4 => {
|
|
79
|
+
let {
|
|
80
|
+
onClick
|
|
81
|
+
} = _ref4;
|
|
82
|
+
return {
|
|
83
|
+
name: "Controls",
|
|
84
|
+
icon: {
|
|
85
|
+
width: 512,
|
|
86
|
+
height: 512,
|
|
87
|
+
path: faSliders.icon[4]
|
|
88
|
+
},
|
|
89
|
+
click: onClick
|
|
90
|
+
};
|
|
91
|
+
};
|
|
@@ -7,18 +7,25 @@ import React, { useEffect, useState } from "react";
|
|
|
7
7
|
import { faCircleInfo } from "@fortawesome/free-solid-svg-icons";
|
|
8
8
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|
9
9
|
import _ from "lodash";
|
|
10
|
-
import { Alert, OverlayTrigger, Tooltip } from "react-bootstrap";
|
|
10
|
+
import { Alert, Button, OverlayTrigger, Tooltip } from "react-bootstrap";
|
|
11
11
|
import Plot from "react-plotly.js";
|
|
12
|
-
import { VIOLIN_MODES } from "../../constants/constants";
|
|
12
|
+
import { PLOTLY_MODEBAR_BUTTONS, VIOLIN_MODES } from "../../constants/constants";
|
|
13
13
|
import { useDataset } from "../../context/DatasetContext";
|
|
14
14
|
import { useFilteredData } from "../../context/FilterContext";
|
|
15
15
|
import { useSettings } from "../../context/SettingsContext";
|
|
16
16
|
import { LoadingSpinner } from "../../utils/LoadingIndicators";
|
|
17
17
|
import { useDebouncedFetch } from "../../utils/requests";
|
|
18
|
+
import { ControlsPlotlyToolbar, ObsPlotlyToolbar, VarPlotlyToolbar } from "../toolbar/Toolbar";
|
|
18
19
|
export function Violin(_ref) {
|
|
19
20
|
var _settings$selectedVar, _settings$selectedVar2, _settings$selectedVar3, _settings$selectedVar4, _settings$selectedObs, _settings$selectedObs2, _settings$selectedObs3;
|
|
20
21
|
let {
|
|
21
|
-
mode = VIOLIN_MODES.MULTIKEY
|
|
22
|
+
mode = VIOLIN_MODES.MULTIKEY,
|
|
23
|
+
showObsBtn = false,
|
|
24
|
+
showVarsBtn = false,
|
|
25
|
+
showCtrlsBtn = false,
|
|
26
|
+
setShowObs,
|
|
27
|
+
setShowVars,
|
|
28
|
+
setShowControls
|
|
22
29
|
} = _ref;
|
|
23
30
|
const ENDPOINT = "violin";
|
|
24
31
|
const dataset = useDataset();
|
|
@@ -117,17 +124,29 @@ export function Violin(_ref) {
|
|
|
117
124
|
setLayout(fetchedData.layout);
|
|
118
125
|
}
|
|
119
126
|
}, [fetchedData, hasSelections, isPending, serverError]);
|
|
127
|
+
const customModeBarButtons = _.compact([showObsBtn && ObsPlotlyToolbar({
|
|
128
|
+
onClick: setShowObs
|
|
129
|
+
}), showVarsBtn && VarPlotlyToolbar({
|
|
130
|
+
onClick: setShowVars
|
|
131
|
+
}), showCtrlsBtn && ControlsPlotlyToolbar({
|
|
132
|
+
onClick: setShowControls
|
|
133
|
+
})]);
|
|
134
|
+
const modeBarButtons = customModeBarButtons.length ? [customModeBarButtons, PLOTLY_MODEBAR_BUTTONS] : [PLOTLY_MODEBAR_BUTTONS];
|
|
120
135
|
if (!serverError) {
|
|
121
136
|
if (hasSelections) {
|
|
122
137
|
return /*#__PURE__*/React.createElement("div", {
|
|
123
|
-
className: "cherita-violin position-relative"
|
|
138
|
+
className: "cherita-plot cherita-violin position-relative"
|
|
124
139
|
}, isPending && /*#__PURE__*/React.createElement(LoadingSpinner, null), /*#__PURE__*/React.createElement(Plot, {
|
|
125
140
|
data: data,
|
|
126
141
|
layout: layout,
|
|
127
142
|
useResizeHandler: true,
|
|
128
143
|
style: {
|
|
129
|
-
|
|
130
|
-
|
|
144
|
+
width: "100%",
|
|
145
|
+
height: "100%"
|
|
146
|
+
},
|
|
147
|
+
config: {
|
|
148
|
+
displaylogo: false,
|
|
149
|
+
modeBarButtons: modeBarButtons
|
|
131
150
|
}
|
|
132
151
|
}), (fetchedData === null || fetchedData === void 0 ? void 0 : fetchedData.resampled) && /*#__PURE__*/React.createElement(Alert, {
|
|
133
152
|
variant: "warning"
|
|
@@ -142,9 +161,21 @@ export function Violin(_ref) {
|
|
|
142
161
|
className: "cherita-violin"
|
|
143
162
|
}, mode === VIOLIN_MODES.MULTIKEY && /*#__PURE__*/React.createElement(Alert, {
|
|
144
163
|
variant: "light"
|
|
145
|
-
}, "Select
|
|
164
|
+
}, "Select", " ", showVarsBtn ? /*#__PURE__*/React.createElement(Button, {
|
|
165
|
+
variant: "link",
|
|
166
|
+
className: "border-0 p-0 align-baseline",
|
|
167
|
+
onClick: setShowVars
|
|
168
|
+
}, "features") : "features"), mode === VIOLIN_MODES.GROUPBY && /*#__PURE__*/React.createElement(Alert, {
|
|
146
169
|
variant: "light"
|
|
147
|
-
}, "Select
|
|
170
|
+
}, "Select", " ", showObsBtn ? /*#__PURE__*/React.createElement(Button, {
|
|
171
|
+
variant: "link",
|
|
172
|
+
className: "border-0 p-0 align-baseline",
|
|
173
|
+
onClick: setShowObs
|
|
174
|
+
}, "categories") : "categories", " ", "and a", " ", showVarsBtn ? /*#__PURE__*/React.createElement(Button, {
|
|
175
|
+
variant: "link",
|
|
176
|
+
className: "border-0 p-0 align-baseline",
|
|
177
|
+
onClick: setShowVars
|
|
178
|
+
}, "feature") : "feature"));
|
|
148
179
|
} else {
|
|
149
180
|
return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Alert, {
|
|
150
181
|
variant: "danger"
|
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
export const LOCAL_STORAGE_KEY = "CHERITA";
|
|
2
|
+
export const PLOT_TYPES = {
|
|
3
|
+
SCATTERPLOT: "scatterplot",
|
|
4
|
+
DOTPLOT: "dotplot",
|
|
5
|
+
HEATMAP: "heatmap",
|
|
6
|
+
MATRIXPLOT: "matrixplot",
|
|
7
|
+
VIOLINPLOT: "violinplot"
|
|
8
|
+
};
|
|
2
9
|
export const COLOR_ENCODINGS = {
|
|
3
10
|
VAR: "var",
|
|
4
11
|
OBS: "obs"
|
|
@@ -85,4 +92,9 @@ export const PSEUDOSPATIAL_CATEGORICAL_MODES = {
|
|
|
85
92
|
|
|
86
93
|
// `default` cols to be shown out of accordion, at top of obslist
|
|
87
94
|
// default values from cellxgene schema
|
|
88
|
-
export const DEFAULT_OBS_GROUP = ["assay", "cell_type", "development_stage", "disease", "donor_id", "organism", "self_reported_ethnicity", "sex", "suspension_type", "tissue", "tissue_type"];
|
|
95
|
+
export const DEFAULT_OBS_GROUP = ["assay", "cell_type", "development_stage", "disease", "donor_id", "organism", "self_reported_ethnicity", "sex", "suspension_type", "tissue", "tissue_type"];
|
|
96
|
+
export const PLOTLY_MODEBAR_BUTTONS = ["toImage", "zoom2d", "pan2d", "zoomIn2d", "zoomOut2d", "autoScale2d", "resetScale2d"];
|
|
97
|
+
export const BREAKPOINTS = {
|
|
98
|
+
LG: "(max-width: 991.98px)",
|
|
99
|
+
XL: "(max-width: 1199.98px)"
|
|
100
|
+
};
|
package/dist/esm/index.js
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
export { Dotplot } from "./components/dotplot/Dotplot";
|
|
2
2
|
export { DotplotControls } from "./components/dotplot/DotplotControls";
|
|
3
|
+
export { FullPage } from "./components/full-page/FullPage";
|
|
3
4
|
export { Heatmap } from "./components/heatmap/Heatmap";
|
|
4
5
|
export { HeatmapControls } from "./components/heatmap/HeatmapControls";
|
|
5
6
|
export { Matrixplot } from "./components/matrixplot/Matrixplot";
|
|
6
7
|
export { MatrixplotControls } from "./components/matrixplot/MatrixplotControls";
|
|
7
8
|
export { ObsColsList } from "./components/obs-list/ObsList";
|
|
8
9
|
export { ObsmKeysList } from "./components/obsm-list/ObsmList";
|
|
10
|
+
export { OffcanvasControls, OffcanvasObs, OffcanvasObsm, OffcanvasVars } from "./components/offcanvas";
|
|
9
11
|
export { Pseudospatial } from "./components/pseudospatial/Pseudospatial";
|
|
10
12
|
export { Scatterplot } from "./components/scatterplot/Scatterplot";
|
|
11
13
|
export { ScatterplotControls } from "./components/scatterplot/ScatterplotControls";
|
|
12
14
|
export { SearchBar } from "./components/search-bar/SearchBar";
|
|
15
|
+
export { Toolbar } from "./components/toolbar/Toolbar";
|
|
13
16
|
export { VarNamesList } from "./components/var-list/VarList";
|
|
14
17
|
export { Violin } from "./components/violin/Violin";
|
|
15
18
|
export { ViolinControls } from "./components/violin/ViolinControls";
|
|
16
|
-
export { FullPage, FullPagePlots, FullPageScatterplot } from "./components/full-page/FullPage";
|
|
17
|
-
export { FullPagePseudospatial } from "./components/full-page/FullPagePseudospatial";
|
|
18
|
-
export { OffcanvasControls, OffcanvasObs, OffcanvasObsm, OffcanvasVars } from "./components/offcanvas";
|
|
19
19
|
export { COLORSCALES } from "./constants/colorscales";
|
|
20
|
-
export { SELECTION_MODES, VIOLIN_MODES } from "./constants/constants";
|
|
20
|
+
export { PLOT_TYPES, SELECTION_MODES, VIOLIN_MODES } from "./constants/constants";
|
|
21
21
|
export { DatasetProvider } from "./context/DatasetContext";
|
|
22
22
|
export { FilterProvider } from "./context/FilterContext";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@haniffalab/cherita-react",
|
|
3
|
-
"version": "1.3.0-dev.2025-
|
|
3
|
+
"version": "1.3.0-dev.2025-06-04.bee6fd81",
|
|
4
4
|
"author": "Haniffa Lab",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"keywords": [
|
|
@@ -126,5 +126,5 @@
|
|
|
126
126
|
"url": "https://github.com/haniffalab/cherita-react/issues"
|
|
127
127
|
},
|
|
128
128
|
"homepage": "https://github.com/haniffalab/cherita-react#readme",
|
|
129
|
-
"prereleaseSha": "
|
|
129
|
+
"prereleaseSha": "bee6fd816597b2a731ce2565b16db2d9fa63bb06"
|
|
130
130
|
}
|
package/scss/cherita.scss
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
.cherita-app {
|
|
2
2
|
position: relative;
|
|
3
|
+
width: 100%;
|
|
3
4
|
}
|
|
4
5
|
|
|
5
6
|
.cherita-app {
|
|
@@ -50,6 +51,21 @@
|
|
|
50
51
|
overflow-y: hidden;
|
|
51
52
|
}
|
|
52
53
|
|
|
54
|
+
.sidebar-plotselector {
|
|
55
|
+
padding: 6px;
|
|
56
|
+
border-bottom: 1px solid #dee2e6;
|
|
57
|
+
|
|
58
|
+
.plotselector-icon {
|
|
59
|
+
padding-bottom: 2px;
|
|
60
|
+
cursor: pointer;
|
|
61
|
+
|
|
62
|
+
.active {
|
|
63
|
+
opacity: 1;
|
|
64
|
+
border-bottom: 2px solid #007bff;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
53
69
|
.sidebar-pseudospatial {
|
|
54
70
|
padding: 10px;
|
|
55
71
|
border-bottom: 1px solid #dee2e6;
|
|
@@ -108,6 +124,58 @@
|
|
|
108
124
|
border-left: 1px solid #dee2e6;
|
|
109
125
|
}
|
|
110
126
|
|
|
127
|
+
.cherita-app-canvas {
|
|
128
|
+
.cherita-plot {
|
|
129
|
+
height: 100%;
|
|
130
|
+
min-height: 400px;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.cherita-app-container {
|
|
135
|
+
@extend .p-0;
|
|
136
|
+
display: flex;
|
|
137
|
+
flex-wrap: nowrap;
|
|
138
|
+
width: 100%;
|
|
139
|
+
height: 100%;
|
|
140
|
+
|
|
141
|
+
.cherita-app-obs {
|
|
142
|
+
flex: 0 0 auto;
|
|
143
|
+
min-width: 350px;
|
|
144
|
+
max-width: 20%;
|
|
145
|
+
overflow-y: auto;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.cherita-app-canvas {
|
|
149
|
+
@extend .p-1;
|
|
150
|
+
flex: 1 1 auto;
|
|
151
|
+
min-width: 400px;
|
|
152
|
+
position: relative;
|
|
153
|
+
max-height: 100%;
|
|
154
|
+
display: flex;
|
|
155
|
+
flex-direction: column;
|
|
156
|
+
|
|
157
|
+
.cherita-navbar {
|
|
158
|
+
@extend .m-0;
|
|
159
|
+
@extend .d-block;
|
|
160
|
+
position: relative;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.cherita-app-sidebar {
|
|
165
|
+
flex: 0 0 auto;
|
|
166
|
+
min-width: 350px;
|
|
167
|
+
max-width: 20%;
|
|
168
|
+
position: relative;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
@media (max-width: 1400px) {
|
|
172
|
+
.cherita-app-obs,
|
|
173
|
+
.cherita-app-sidebar {
|
|
174
|
+
max-width: 25%;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
111
179
|
.ps-xs-1 {
|
|
112
180
|
padding-left: 0.15rem !important;
|
|
113
|
-
}
|
|
181
|
+
}
|
|
@@ -1,30 +1,35 @@
|
|
|
1
1
|
.js-plotly-plot .plotly .modebar {
|
|
2
|
-
border-radius: 5px;
|
|
3
|
-
background-color: rgba(0, 0, 0, 0.6);
|
|
4
|
-
padding: 0 4px !important;
|
|
5
2
|
|
|
6
3
|
.modebar-group {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
4
|
+
@extend .bg-primary;
|
|
5
|
+
@extend .mx-1;
|
|
6
|
+
border-radius: 5px;
|
|
7
|
+
padding: 4px !important;
|
|
10
8
|
|
|
11
9
|
.modebar-btn {
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
display: inline-flex;
|
|
11
|
+
justify-content: center;
|
|
14
12
|
position: relative;
|
|
15
|
-
font-size:
|
|
16
|
-
padding:
|
|
13
|
+
font-size: 1.25rem;
|
|
14
|
+
padding: 0.25rem;
|
|
17
15
|
height: auto;
|
|
18
16
|
cursor: pointer;
|
|
19
17
|
line-height: normal;
|
|
20
18
|
|
|
21
19
|
svg {
|
|
22
20
|
position: relative;
|
|
23
|
-
top:
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
21
|
+
top: 1px;
|
|
22
|
+
|
|
23
|
+
path {
|
|
24
|
+
fill: white !important;
|
|
25
|
+
color: white !important;
|
|
26
|
+
}
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
|
+
|
|
32
|
+
.js-plotly-plot .plotly .modebar--hover > :not(.watermark) {
|
|
33
|
+
opacity: 0.5;
|
|
34
|
+
transition: opacity 0.3s;
|
|
35
|
+
}
|