@haniffalab/cherita-react 1.0.0 → 1.1.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.
Files changed (106) hide show
  1. package/LICENSE +1 -1
  2. package/dist/{components → cjs/components}/full-page/FullPage.js +32 -22
  3. package/dist/{components → cjs/components}/full-page/FullPagePseudospatial.js +7 -6
  4. package/dist/{components → cjs/components}/obs-list/ObsItem.js +88 -77
  5. package/dist/{components → cjs/components}/obs-list/ObsList.js +133 -50
  6. package/dist/cjs/components/obs-list/ObsToolbar.js +24 -0
  7. package/dist/{components → cjs/components}/obsm-list/ObsmList.js +8 -5
  8. package/dist/{components → cjs/components}/offcanvas/index.js +24 -20
  9. package/dist/{components → cjs/components}/pseudospatial/Pseudospatial.js +10 -9
  10. package/dist/{components → cjs/components}/pseudospatial/PseudospatialToolbar.js +4 -3
  11. package/dist/{components → cjs/components}/scatterplot/Scatterplot.js +33 -24
  12. package/dist/{components → cjs/components}/scatterplot/SpatialControls.js +43 -42
  13. package/dist/cjs/components/scatterplot/Toolbox.js +62 -0
  14. package/dist/{components → cjs/components}/search-bar/SearchBar.js +24 -7
  15. package/dist/{components → cjs/components}/search-bar/SearchResults.js +13 -17
  16. package/dist/{components → cjs/components}/var-list/VarItem.js +38 -29
  17. package/dist/{components → cjs/components}/var-list/VarList.js +59 -31
  18. package/dist/{components → cjs/components}/var-list/VarListToolbar.js +18 -14
  19. package/dist/{components → cjs/components}/var-list/VarSet.js +24 -20
  20. package/dist/{components → cjs/components}/violin/Violin.js +4 -3
  21. package/dist/{constants → cjs/constants}/constants.js +6 -2
  22. package/dist/{context → cjs/context}/DatasetContext.js +12 -11
  23. package/dist/{context → cjs/context}/FilterContext.js +4 -3
  24. package/dist/{context → cjs/context}/ZarrDataContext.js +4 -3
  25. package/dist/{helpers → cjs/helpers}/color-helper.js +12 -11
  26. package/dist/{helpers → cjs/helpers}/map-helper.js +8 -7
  27. package/dist/{helpers → cjs/helpers}/zarr-helper.js +30 -38
  28. package/dist/{utils → cjs/utils}/Filter.js +1 -1
  29. package/dist/{utils → cjs/utils}/Histogram.js +12 -8
  30. package/dist/{utils → cjs/utils}/ImageViewer.js +6 -5
  31. package/dist/{utils → cjs/utils}/Legend.js +8 -7
  32. package/dist/{utils → cjs/utils}/LoadingIndicators.js +5 -4
  33. package/dist/cjs/utils/Skeleton.js +19 -0
  34. package/dist/{utils → cjs/utils}/VirtualizedList.js +10 -9
  35. package/dist/{utils → cjs/utils}/requests.js +37 -39
  36. package/dist/{utils → cjs/utils}/string.js +9 -4
  37. package/dist/{utils → cjs/utils}/zarrData.js +12 -4
  38. package/dist/css/cherita.css +147 -152
  39. package/dist/css/cherita.css.map +1 -1
  40. package/dist/esm/components/dotplot/Dotplot.js +135 -0
  41. package/dist/esm/components/dotplot/DotplotControls.js +148 -0
  42. package/dist/esm/components/full-page/FullPage.js +143 -0
  43. package/dist/esm/components/full-page/FullPagePseudospatial.js +151 -0
  44. package/dist/esm/components/heatmap/Heatmap.js +105 -0
  45. package/dist/esm/components/heatmap/HeatmapControls.js +23 -0
  46. package/dist/esm/components/matrixplot/Matrixplot.js +107 -0
  47. package/dist/esm/components/matrixplot/MatrixplotControls.js +38 -0
  48. package/dist/esm/components/obs-list/ObsItem.js +484 -0
  49. package/dist/esm/components/obs-list/ObsList.js +338 -0
  50. package/dist/esm/components/obs-list/ObsToolbar.js +17 -0
  51. package/dist/esm/components/obsm-list/ObsmList.js +75 -0
  52. package/dist/esm/components/offcanvas/index.js +67 -0
  53. package/dist/esm/components/pseudospatial/Pseudospatial.js +228 -0
  54. package/dist/esm/components/pseudospatial/PseudospatialToolbar.js +123 -0
  55. package/dist/esm/components/scatterplot/Scatterplot.js +394 -0
  56. package/dist/esm/components/scatterplot/ScatterplotControls.js +71 -0
  57. package/dist/esm/components/scatterplot/SpatialControls.js +140 -0
  58. package/dist/esm/components/scatterplot/Toolbox.js +55 -0
  59. package/dist/esm/components/search-bar/SearchBar.js +90 -0
  60. package/dist/esm/components/search-bar/SearchResults.js +139 -0
  61. package/dist/esm/components/var-list/VarItem.js +254 -0
  62. package/dist/esm/components/var-list/VarList.js +291 -0
  63. package/dist/esm/components/var-list/VarListToolbar.js +87 -0
  64. package/dist/esm/components/var-list/VarSet.js +194 -0
  65. package/dist/esm/components/violin/Violin.js +141 -0
  66. package/dist/esm/components/violin/ViolinControls.js +24 -0
  67. package/dist/esm/constants/colorscales.js +22 -0
  68. package/dist/esm/constants/constants.js +88 -0
  69. package/dist/esm/context/DatasetContext.js +571 -0
  70. package/dist/esm/context/FilterContext.js +48 -0
  71. package/dist/esm/context/ZarrDataContext.js +26 -0
  72. package/dist/esm/helpers/color-helper.js +66 -0
  73. package/dist/esm/helpers/map-helper.js +53 -0
  74. package/dist/esm/helpers/zarr-helper.js +111 -0
  75. package/dist/esm/index.js +22 -0
  76. package/dist/esm/utils/Filter.js +147 -0
  77. package/dist/esm/utils/Histogram.js +44 -0
  78. package/dist/esm/utils/ImageViewer.js +27 -0
  79. package/dist/esm/utils/Legend.js +58 -0
  80. package/dist/esm/utils/LoadingIndicators.js +22 -0
  81. package/dist/esm/utils/Skeleton.js +12 -0
  82. package/dist/esm/utils/VirtualizedList.js +55 -0
  83. package/dist/esm/utils/errors.js +47 -0
  84. package/dist/esm/utils/requests.js +102 -0
  85. package/dist/esm/utils/search.js +39 -0
  86. package/dist/esm/utils/string.js +59 -0
  87. package/dist/esm/utils/zarrData.js +102 -0
  88. package/package.json +19 -7
  89. package/scss/cherita.scss +19 -50
  90. package/scss/components/accordions.scss +32 -0
  91. package/scss/components/layouts.scss +2 -1
  92. package/scss/components/lists.scss +14 -0
  93. package/dist/components/obs-list/ObsToolbar.js +0 -64
  94. package/dist/components/scatterplot/Toolbox.js +0 -31
  95. /package/dist/{components → cjs/components}/dotplot/Dotplot.js +0 -0
  96. /package/dist/{components → cjs/components}/dotplot/DotplotControls.js +0 -0
  97. /package/dist/{components → cjs/components}/heatmap/Heatmap.js +0 -0
  98. /package/dist/{components → cjs/components}/heatmap/HeatmapControls.js +0 -0
  99. /package/dist/{components → cjs/components}/matrixplot/Matrixplot.js +0 -0
  100. /package/dist/{components → cjs/components}/matrixplot/MatrixplotControls.js +0 -0
  101. /package/dist/{components → cjs/components}/scatterplot/ScatterplotControls.js +0 -0
  102. /package/dist/{components → cjs/components}/violin/ViolinControls.js +0 -0
  103. /package/dist/{constants → cjs/constants}/colorscales.js +0 -0
  104. /package/dist/{index.js → cjs/index.js} +0 -0
  105. /package/dist/{utils → cjs/utils}/errors.js +0 -0
  106. /package/dist/{utils → cjs/utils}/search.js +0 -0
@@ -0,0 +1,143 @@
1
+ function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
2
+ import React, { useEffect, useRef, useState } from "react";
3
+ import { Card, Container, Modal, Nav, Navbar } from "react-bootstrap";
4
+ import { SELECTION_MODES, VIOLIN_MODES } from "../../constants/constants";
5
+ import { DatasetProvider } from "../../context/DatasetContext";
6
+ import { Dotplot } from "../dotplot/Dotplot";
7
+ import { Heatmap } from "../heatmap/Heatmap";
8
+ import { Matrixplot } from "../matrixplot/Matrixplot";
9
+ import { ObsColsList } from "../obs-list/ObsList";
10
+ import { OffcanvasControls, OffcanvasObs, OffcanvasObsm, OffcanvasVars } from "../offcanvas";
11
+ import { Scatterplot } from "../scatterplot/Scatterplot";
12
+ import { ScatterplotControls } from "../scatterplot/ScatterplotControls";
13
+ import { SearchBar } from "../search-bar/SearchBar";
14
+ import { VarNamesList } from "../var-list/VarList";
15
+ import { Violin } from "../violin/Violin";
16
+ export function FullPage(_ref) {
17
+ let {
18
+ children,
19
+ varMode = SELECTION_MODES.SINGLE,
20
+ ...props
21
+ } = _ref;
22
+ const appRef = useRef();
23
+ const [appDimensions, setAppDimensions] = useState({
24
+ width: 0,
25
+ height: 0
26
+ });
27
+ const [showObs, setShowObs] = useState(false);
28
+ const [showObsm, setShowObsm] = useState(false);
29
+ const [showVars, setShowVars] = useState(false);
30
+ const [showControls, setShowControls] = useState(false);
31
+ const [showModal, setShowModal] = useState(false);
32
+ useEffect(() => {
33
+ const updateDimensions = () => {
34
+ if (appRef.current) {
35
+ // Get the distance from the top of the page to the target element
36
+ const rect = appRef.current.getBoundingClientRect();
37
+ const distanceFromTop = rect.top + window.scrollY;
38
+
39
+ // Calculate the available height for the Cherita app
40
+ const availableHeight = window.innerHeight - distanceFromTop;
41
+
42
+ // Update the dimensions to fit the viewport minus the navbar height
43
+ setAppDimensions({
44
+ width: appRef.current.offsetWidth,
45
+ height: availableHeight
46
+ });
47
+ }
48
+ };
49
+ window.addEventListener("resize", updateDimensions);
50
+ updateDimensions(); // Initial update
51
+ return () => window.removeEventListener("resize", updateDimensions);
52
+ }, []);
53
+ return /*#__PURE__*/React.createElement("div", {
54
+ ref: appRef,
55
+ className: "cherita-app",
56
+ style: {
57
+ height: appDimensions.height
58
+ }
59
+ }, /*#__PURE__*/React.createElement(DatasetProvider, props, /*#__PURE__*/React.createElement(Container, {
60
+ fluid: true,
61
+ className: "d-flex g-0",
62
+ style: {
63
+ height: appDimensions.height
64
+ }
65
+ }, /*#__PURE__*/React.createElement(Navbar, {
66
+ expand: "sm",
67
+ bg: "primary",
68
+ className: "cherita-navbar"
69
+ }, /*#__PURE__*/React.createElement("div", {
70
+ className: "container-fluid"
71
+ }, /*#__PURE__*/React.createElement(Navbar.Toggle, {
72
+ "aria-controls": "navbarScroll"
73
+ }), /*#__PURE__*/React.createElement(Navbar.Collapse, {
74
+ id: "navbarScroll"
75
+ }, /*#__PURE__*/React.createElement(Nav, {
76
+ className: "me-auto my-0",
77
+ navbarScroll: true
78
+ }, /*#__PURE__*/React.createElement(Nav.Item, {
79
+ className: "d-block d-lg-none"
80
+ }, /*#__PURE__*/React.createElement(Nav.Link, {
81
+ onClick: () => setShowObs(true)
82
+ }, "Observations")), /*#__PURE__*/React.createElement(Nav.Item, null, /*#__PURE__*/React.createElement(Nav.Link, {
83
+ onClick: () => setShowVars(true)
84
+ }, "Features"))), /*#__PURE__*/React.createElement(Nav, {
85
+ className: "d-flex"
86
+ }, /*#__PURE__*/React.createElement(Nav.Item, null, /*#__PURE__*/React.createElement(Nav.Link, {
87
+ onClick: () => setShowControls(true)
88
+ }, "Controls")))))), /*#__PURE__*/React.createElement("div", {
89
+ className: "cherita-app-obs modern-scrollbars border-end h-100"
90
+ }, /*#__PURE__*/React.createElement(ObsColsList, props)), /*#__PURE__*/React.createElement("div", {
91
+ className: "cherita-app-canvas flex-grow-1"
92
+ }, children), /*#__PURE__*/React.createElement("div", {
93
+ className: "cherita-app-sidebar p-3"
94
+ }, /*#__PURE__*/React.createElement(Card, null, /*#__PURE__*/React.createElement(Card.Body, {
95
+ className: "d-flex flex-column p-0"
96
+ }, /*#__PURE__*/React.createElement("div", {
97
+ className: "sidebar-features modern-scrollbars"
98
+ }, /*#__PURE__*/React.createElement(SearchBar, {
99
+ searchDiseases: true,
100
+ searchVar: true
101
+ }), /*#__PURE__*/React.createElement(VarNamesList, {
102
+ mode: varMode
103
+ })))))), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Modal, {
104
+ show: showModal,
105
+ onHide: () => setShowModal(false),
106
+ centered: true
107
+ }, /*#__PURE__*/React.createElement(Modal.Header, {
108
+ closeButton: true
109
+ }), /*#__PURE__*/React.createElement(Modal.Body, null)), /*#__PURE__*/React.createElement(OffcanvasObs, {
110
+ show: showObs,
111
+ handleClose: () => setShowObs(false)
112
+ }), /*#__PURE__*/React.createElement(OffcanvasVars, {
113
+ show: showVars,
114
+ handleClose: () => setShowVars(false)
115
+ }), /*#__PURE__*/React.createElement(OffcanvasControls, {
116
+ show: showControls,
117
+ handleClose: () => setShowControls(false),
118
+ Controls: ScatterplotControls
119
+ }), /*#__PURE__*/React.createElement(OffcanvasObsm, {
120
+ show: showObsm,
121
+ handleClose: () => setShowObsm(false)
122
+ }))));
123
+ }
124
+ export function FullPageScatterplot(props) {
125
+ return /*#__PURE__*/React.createElement(FullPage, props, /*#__PURE__*/React.createElement(Scatterplot, null));
126
+ }
127
+ export function FullPagePlots(props) {
128
+ return /*#__PURE__*/React.createElement(FullPage, _extends({}, props, {
129
+ varMode: SELECTION_MODES.MULTIPLE
130
+ }), /*#__PURE__*/React.createElement("div", {
131
+ className: "container-fluid w-100 h-100 d-flex flex-column overflow-y-auto"
132
+ }, /*#__PURE__*/React.createElement("div", {
133
+ className: "row flex-grow-1"
134
+ }, /*#__PURE__*/React.createElement(Heatmap, null)), /*#__PURE__*/React.createElement("div", {
135
+ className: "row flex-grow-1"
136
+ }, /*#__PURE__*/React.createElement(Matrixplot, null)), /*#__PURE__*/React.createElement("div", {
137
+ className: "row flex-grow-1"
138
+ }, /*#__PURE__*/React.createElement(Dotplot, null)), /*#__PURE__*/React.createElement("div", {
139
+ className: "row flex-grow-1"
140
+ }, /*#__PURE__*/React.createElement(Violin, {
141
+ mode: VIOLIN_MODES.GROUPBY
142
+ }))));
143
+ }
@@ -0,0 +1,151 @@
1
+ import React, { useEffect, useRef, useState } from "react";
2
+ import { faArrowUpRightFromSquare } from "@fortawesome/free-solid-svg-icons";
3
+ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
4
+ import { Button, Card, Container, Modal, Nav, Navbar } from "react-bootstrap";
5
+ import { SELECTION_MODES } from "../../constants/constants";
6
+ import { DatasetProvider } from "../../context/DatasetContext";
7
+ import { ObsColsList } from "../obs-list/ObsList";
8
+ import { OffcanvasControls, OffcanvasObs, OffcanvasObsm, OffcanvasVars } from "../offcanvas";
9
+ import { Pseudospatial } from "../pseudospatial/Pseudospatial";
10
+ import { PseudospatialToolbar } from "../pseudospatial/PseudospatialToolbar";
11
+ import { Scatterplot } from "../scatterplot/Scatterplot";
12
+ import { ScatterplotControls } from "../scatterplot/ScatterplotControls";
13
+ import { SearchBar } from "../search-bar/SearchBar";
14
+ import { VarNamesList } from "../var-list/VarList";
15
+ export function FullPage(_ref) {
16
+ let {
17
+ children,
18
+ varMode = SELECTION_MODES.SINGLE,
19
+ ...props
20
+ } = _ref;
21
+ const appRef = useRef();
22
+ const [appDimensions, setAppDimensions] = useState({
23
+ width: 0,
24
+ height: 0
25
+ });
26
+ const [showObs, setShowObs] = useState(false);
27
+ const [showObsm, setShowObsm] = useState(false);
28
+ const [showVars, setShowVars] = useState(false);
29
+ const [showControls, setShowControls] = useState(false);
30
+ const [showPseudospatialControls, setShowPseudospatialControls] = useState(false);
31
+ const [showModal, setShowModal] = useState(false);
32
+ const [pseudospatialPlotType, setpseudospatialPlotType] = useState(null);
33
+ useEffect(() => {
34
+ const updateDimensions = () => {
35
+ if (appRef.current) {
36
+ // Get the distance from the top of the page to the target element
37
+ const rect = appRef.current.getBoundingClientRect();
38
+ const distanceFromTop = rect.top + window.scrollY;
39
+
40
+ // Calculate the available height for the Cherita app
41
+ const availableHeight = window.innerHeight - distanceFromTop;
42
+
43
+ // Update the dimensions to fit the viewport minus the navbar height
44
+ setAppDimensions({
45
+ width: appRef.current.offsetWidth,
46
+ height: availableHeight
47
+ });
48
+ }
49
+ };
50
+ window.addEventListener("resize", updateDimensions);
51
+ updateDimensions(); // Initial update
52
+ return () => window.removeEventListener("resize", updateDimensions);
53
+ }, []);
54
+ return /*#__PURE__*/React.createElement("div", {
55
+ ref: appRef,
56
+ className: "cherita-app",
57
+ style: {
58
+ height: appDimensions.height
59
+ }
60
+ }, /*#__PURE__*/React.createElement(DatasetProvider, props, /*#__PURE__*/React.createElement(Container, {
61
+ fluid: true,
62
+ className: "d-flex g-0",
63
+ style: {
64
+ height: appDimensions.height
65
+ }
66
+ }, /*#__PURE__*/React.createElement(Navbar, {
67
+ expand: "sm",
68
+ bg: "primary",
69
+ className: "cherita-navbar"
70
+ }, /*#__PURE__*/React.createElement("div", {
71
+ className: "container-fluid"
72
+ }, /*#__PURE__*/React.createElement(Navbar.Toggle, {
73
+ "aria-controls": "navbarScroll"
74
+ }), /*#__PURE__*/React.createElement(Navbar.Collapse, {
75
+ id: "navbarScroll"
76
+ }, /*#__PURE__*/React.createElement(Nav, {
77
+ className: "me-auto my-0",
78
+ navbarScroll: true
79
+ }, /*#__PURE__*/React.createElement(Nav.Item, {
80
+ className: "d-block d-lg-none"
81
+ }, /*#__PURE__*/React.createElement(Nav.Link, {
82
+ onClick: () => setShowObs(true)
83
+ }, "Observations")), /*#__PURE__*/React.createElement(Nav.Item, null, /*#__PURE__*/React.createElement(Nav.Link, {
84
+ onClick: () => setShowVars(true)
85
+ }, "Features"))), /*#__PURE__*/React.createElement(Nav, {
86
+ className: "d-flex"
87
+ }, /*#__PURE__*/React.createElement(Nav.Item, null, /*#__PURE__*/React.createElement(Nav.Link, {
88
+ onClick: () => setShowControls(true)
89
+ }, "Controls")))))), /*#__PURE__*/React.createElement("div", {
90
+ className: "cherita-app-obs modern-scrollbars border-end h-100"
91
+ }, /*#__PURE__*/React.createElement(ObsColsList, props)), /*#__PURE__*/React.createElement("div", {
92
+ className: "cherita-app-canvas flex-grow-1"
93
+ }, children), /*#__PURE__*/React.createElement("div", {
94
+ className: "cherita-app-sidebar p-3"
95
+ }, /*#__PURE__*/React.createElement(Card, null, /*#__PURE__*/React.createElement(Card.Header, {
96
+ className: "d-flex justify-content-evenly align-items-center"
97
+ }, /*#__PURE__*/React.createElement(Button, {
98
+ variant: "link",
99
+ onClick: () => setShowModal(true)
100
+ }, /*#__PURE__*/React.createElement(FontAwesomeIcon, {
101
+ icon: faArrowUpRightFromSquare
102
+ }))), /*#__PURE__*/React.createElement(Card.Body, {
103
+ className: "d-flex flex-column p-0"
104
+ }, /*#__PURE__*/React.createElement("div", {
105
+ className: "sidebar-pseudospatial"
106
+ }, /*#__PURE__*/React.createElement(Pseudospatial, {
107
+ className: "sidebar-pseudospatial",
108
+ plotType: pseudospatialPlotType,
109
+ setPlotType: setpseudospatialPlotType,
110
+ setShowControls: setShowPseudospatialControls
111
+ })), /*#__PURE__*/React.createElement("div", {
112
+ className: "sidebar-features modern-scrollbars"
113
+ }, /*#__PURE__*/React.createElement(SearchBar, {
114
+ searchDiseases: true,
115
+ searchVar: true
116
+ }), /*#__PURE__*/React.createElement(VarNamesList, {
117
+ mode: varMode
118
+ })))))), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Modal, {
119
+ show: showModal,
120
+ onHide: () => setShowModal(false),
121
+ centered: true
122
+ }, /*#__PURE__*/React.createElement(Modal.Header, {
123
+ closeButton: true
124
+ }), /*#__PURE__*/React.createElement(Modal.Body, null, /*#__PURE__*/React.createElement(Pseudospatial, {
125
+ plotType: pseudospatialPlotType,
126
+ setPlotType: setpseudospatialPlotType,
127
+ setShowControls: setShowPseudospatialControls,
128
+ height: 500
129
+ }))), /*#__PURE__*/React.createElement(OffcanvasObs, {
130
+ show: showObs,
131
+ handleClose: () => setShowObs(false)
132
+ }), /*#__PURE__*/React.createElement(OffcanvasVars, {
133
+ show: showVars,
134
+ handleClose: () => setShowVars(false)
135
+ }), /*#__PURE__*/React.createElement(OffcanvasControls, {
136
+ show: showControls,
137
+ handleClose: () => setShowControls(false),
138
+ Controls: ScatterplotControls
139
+ }), /*#__PURE__*/React.createElement(OffcanvasControls, {
140
+ show: showPseudospatialControls,
141
+ handleClose: () => setShowPseudospatialControls(false),
142
+ Controls: PseudospatialToolbar,
143
+ plotType: pseudospatialPlotType
144
+ }), /*#__PURE__*/React.createElement(OffcanvasObsm, {
145
+ show: showObsm,
146
+ handleClose: () => setShowObsm(false)
147
+ }))));
148
+ }
149
+ export function FullPagePseudospatial(props) {
150
+ return /*#__PURE__*/React.createElement(FullPage, props, /*#__PURE__*/React.createElement(Scatterplot, null));
151
+ }
@@ -0,0 +1,105 @@
1
+ import React, { useCallback, useEffect, useRef, useState } from "react";
2
+ import _ from "lodash";
3
+ import { Alert } from "react-bootstrap";
4
+ import Plot from "react-plotly.js";
5
+ import { useDataset } from "../../context/DatasetContext";
6
+ import { useFilteredData } from "../../context/FilterContext";
7
+ import { LoadingSpinner } from "../../utils/LoadingIndicators";
8
+ import { useDebouncedFetch } from "../../utils/requests";
9
+ export function Heatmap() {
10
+ const ENDPOINT = "heatmap";
11
+ const dataset = useDataset();
12
+ const {
13
+ obsIndices,
14
+ isSliced
15
+ } = useFilteredData();
16
+ const colorscale = useRef(dataset.controls.colorScale);
17
+ const [data, setData] = useState([]);
18
+ const [layout, setLayout] = useState({});
19
+ const [hasSelections, setHasSelections] = useState(false);
20
+ const [params, setParams] = useState({
21
+ url: dataset.url,
22
+ obsCol: dataset.selectedObs,
23
+ obsValues: !dataset.selectedObs?.omit.length ? null : _.difference(_.values(dataset.selectedObs?.codes), dataset.selectedObs?.omit).map(c => dataset.selectedObs?.codesMap[c]),
24
+ varKeys: dataset.selectedMultiVar.map(i => i.isSet ? {
25
+ name: i.name,
26
+ indices: i.vars.map(v => v.index)
27
+ } : i.index),
28
+ obsIndices: isSliced ? [...(obsIndices || [])] : null,
29
+ varNamesCol: dataset.varNamesCol
30
+ });
31
+ useEffect(() => {
32
+ if (dataset.selectedObs && dataset.selectedMultiVar.length) {
33
+ setHasSelections(true);
34
+ } else {
35
+ setHasSelections(false);
36
+ }
37
+ setParams(p => {
38
+ return {
39
+ ...p,
40
+ url: dataset.url,
41
+ obsCol: dataset.selectedObs,
42
+ obsValues: !dataset.selectedObs?.omit.length ? null : _.difference(_.values(dataset.selectedObs?.codes), dataset.selectedObs?.omit).map(c => dataset.selectedObs?.codesMap[c]),
43
+ varKeys: dataset.selectedMultiVar.map(i => i.isSet ? {
44
+ name: i.name,
45
+ indices: i.vars.map(v => v.index)
46
+ } : i.index),
47
+ obsIndices: isSliced ? [...(obsIndices || [])] : null,
48
+ varNamesCol: dataset.varNamesCol
49
+ };
50
+ });
51
+ }, [dataset.selectedMultiVar, dataset.selectedObs, dataset.url, dataset.varNamesCol, obsIndices, isSliced]);
52
+ const updateColorscale = useCallback(colorscale => {
53
+ setLayout(l => {
54
+ return {
55
+ ...l,
56
+ coloraxis: {
57
+ ...l.coloraxis,
58
+ colorscale: colorscale
59
+ }
60
+ };
61
+ });
62
+ }, []);
63
+ const {
64
+ fetchedData,
65
+ isPending,
66
+ serverError
67
+ } = useDebouncedFetch(ENDPOINT, params, 500, {
68
+ enabled: !!params.obsCol && !!params.varKeys.length
69
+ });
70
+ useEffect(() => {
71
+ if (hasSelections && !isPending && !serverError) {
72
+ setData(fetchedData.data);
73
+ setLayout(fetchedData.layout);
74
+ updateColorscale(colorscale.current);
75
+ }
76
+ }, [fetchedData, hasSelections, isPending, serverError, updateColorscale]);
77
+ useEffect(() => {
78
+ colorscale.current = dataset.controls.colorScale;
79
+ updateColorscale(colorscale.current);
80
+ }, [dataset.controls.colorScale, updateColorscale]);
81
+ if (!serverError) {
82
+ if (hasSelections) {
83
+ return /*#__PURE__*/React.createElement("div", {
84
+ className: "cherita-heatmap position-relative"
85
+ }, isPending && /*#__PURE__*/React.createElement(LoadingSpinner, null), /*#__PURE__*/React.createElement(Plot, {
86
+ data: data,
87
+ layout: layout,
88
+ useResizeHandler: true,
89
+ style: {
90
+ maxWidth: "100%",
91
+ maxHeight: "100%"
92
+ }
93
+ }));
94
+ }
95
+ return /*#__PURE__*/React.createElement("div", {
96
+ className: "cherita-heatmap"
97
+ }, /*#__PURE__*/React.createElement(Alert, {
98
+ variant: "light"
99
+ }, "Select features and a category"));
100
+ } else {
101
+ return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Alert, {
102
+ variant: "danger"
103
+ }, serverError.message));
104
+ }
105
+ }
@@ -0,0 +1,23 @@
1
+ import React from "react";
2
+ import _ from "lodash";
3
+ import { Dropdown } from "react-bootstrap";
4
+ import { COLORSCALES } from "../../constants/colorscales";
5
+ import { useDataset, useDatasetDispatch } from "../../context/DatasetContext";
6
+ export function HeatmapControls() {
7
+ const dataset = useDataset();
8
+ const dispatch = useDatasetDispatch();
9
+ const colormapList = _.keys(COLORSCALES).map(key => /*#__PURE__*/React.createElement(Dropdown.Item, {
10
+ key: key,
11
+ active: dataset.controls.colorScale === key,
12
+ onClick: () => {
13
+ dispatch({
14
+ type: "set.controls.colorScale",
15
+ colorScale: key
16
+ });
17
+ }
18
+ }, key));
19
+ return /*#__PURE__*/React.createElement(Dropdown, null, /*#__PURE__*/React.createElement(Dropdown.Toggle, {
20
+ id: "dropdownColorscale",
21
+ variant: "light"
22
+ }, dataset.controls.colorScale), /*#__PURE__*/React.createElement(Dropdown.Menu, null, colormapList));
23
+ }
@@ -0,0 +1,107 @@
1
+ import React, { useCallback, useEffect, useRef, useState } from "react";
2
+ import _ from "lodash";
3
+ import { Alert } from "react-bootstrap";
4
+ import Plot from "react-plotly.js";
5
+ import { useDataset } from "../../context/DatasetContext";
6
+ import { useFilteredData } from "../../context/FilterContext";
7
+ import { LoadingSpinner } from "../../utils/LoadingIndicators";
8
+ import { useDebouncedFetch } from "../../utils/requests";
9
+ export function Matrixplot() {
10
+ const ENDPOINT = "matrixplot";
11
+ const dataset = useDataset();
12
+ const {
13
+ obsIndices,
14
+ isSliced
15
+ } = useFilteredData();
16
+ const colorscale = useRef(dataset.controls.colorScale);
17
+ const [data, setData] = useState([]);
18
+ const [layout, setLayout] = useState({});
19
+ const [hasSelections, setHasSelections] = useState(false);
20
+ const [params, setParams] = useState({
21
+ url: dataset.url,
22
+ obsCol: dataset.selectedObs,
23
+ obsValues: !dataset.selectedObs?.omit.length ? null : _.difference(_.values(dataset.selectedObs?.codes), dataset.selectedObs?.omit).map(c => dataset.selectedObs?.codesMap[c]),
24
+ varKeys: dataset.selectedMultiVar.map(i => i.isSet ? {
25
+ name: i.name,
26
+ indices: i.vars.map(v => v.index)
27
+ } : i.index),
28
+ obsIndices: isSliced ? [...(obsIndices || [])] : null,
29
+ standardScale: dataset.controls.standardScale,
30
+ varNamesCol: dataset.varNamesCol
31
+ });
32
+ useEffect(() => {
33
+ if (dataset.selectedObs && dataset.selectedMultiVar.length) {
34
+ setHasSelections(true);
35
+ } else {
36
+ setHasSelections(false);
37
+ }
38
+ setParams(p => {
39
+ return {
40
+ ...p,
41
+ url: dataset.url,
42
+ obsCol: dataset.selectedObs,
43
+ obsValues: !dataset.selectedObs?.omit.length ? null : _.difference(_.values(dataset.selectedObs?.codes), dataset.selectedObs?.omit).map(c => dataset.selectedObs?.codesMap[c]),
44
+ varKeys: dataset.selectedMultiVar.map(i => i.isSet ? {
45
+ name: i.name,
46
+ indices: i.vars.map(v => v.index)
47
+ } : i.index),
48
+ obsIndices: isSliced ? [...(obsIndices || [])] : null,
49
+ standardScale: dataset.controls.standardScale,
50
+ varNamesCol: dataset.varNamesCol
51
+ };
52
+ });
53
+ }, [dataset.controls.standardScale, dataset.selectedMultiVar, dataset.selectedObs, dataset.url, dataset.varNamesCol, obsIndices, isSliced]);
54
+ const updateColorscale = useCallback(colorscale => {
55
+ setLayout(l => {
56
+ return {
57
+ ...l,
58
+ coloraxis: {
59
+ ...l.coloraxis,
60
+ colorscale: colorscale
61
+ }
62
+ };
63
+ });
64
+ }, []);
65
+ const {
66
+ fetchedData,
67
+ isPending,
68
+ serverError
69
+ } = useDebouncedFetch(ENDPOINT, params, 500, {
70
+ enabled: !!params.obsCol && !!params.varKeys.length
71
+ });
72
+ useEffect(() => {
73
+ if (hasSelections && !isPending && !serverError) {
74
+ setData(fetchedData.data);
75
+ setLayout(fetchedData.layout);
76
+ updateColorscale(colorscale.current);
77
+ }
78
+ }, [fetchedData, hasSelections, isPending, serverError, updateColorscale]);
79
+ useEffect(() => {
80
+ colorscale.current = dataset.controls.colorScale;
81
+ updateColorscale(colorscale.current);
82
+ }, [dataset.controls.colorScale, updateColorscale]);
83
+ if (!serverError) {
84
+ if (hasSelections) {
85
+ return /*#__PURE__*/React.createElement("div", {
86
+ className: "cherita-matrixplot position-relative"
87
+ }, isPending && /*#__PURE__*/React.createElement(LoadingSpinner, null), /*#__PURE__*/React.createElement(Plot, {
88
+ data: data,
89
+ layout: layout,
90
+ useResizeHandler: true,
91
+ style: {
92
+ maxWidth: "100%",
93
+ maxHeight: "100%"
94
+ }
95
+ }));
96
+ }
97
+ return /*#__PURE__*/React.createElement("div", {
98
+ className: "cherita-matrixplot"
99
+ }, /*#__PURE__*/React.createElement(Alert, {
100
+ variant: "light"
101
+ }, "Select features and a category"));
102
+ } else {
103
+ return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Alert, {
104
+ variant: "danger"
105
+ }, serverError.message));
106
+ }
107
+ }
@@ -0,0 +1,38 @@
1
+ import React from "react";
2
+ import _ from "lodash";
3
+ import { Dropdown, ButtonGroup, ButtonToolbar, InputGroup } from "react-bootstrap";
4
+ import { COLORSCALES } from "../../constants/colorscales";
5
+ import { MATRIXPLOT_SCALES } from "../../constants/constants";
6
+ import { useDataset, useDatasetDispatch } from "../../context/DatasetContext";
7
+ export function MatrixplotControls() {
8
+ const dataset = useDataset();
9
+ const dispatch = useDatasetDispatch();
10
+ const colorScaleList = _.keys(COLORSCALES).map(key => /*#__PURE__*/React.createElement(Dropdown.Item, {
11
+ key: key,
12
+ active: dataset.controls.colorScale === key,
13
+ onClick: () => {
14
+ dispatch({
15
+ type: "set.controls.colorScale",
16
+ colorScale: key
17
+ });
18
+ }
19
+ }, key));
20
+ const standardScaleList = _.values(MATRIXPLOT_SCALES).map(scale => /*#__PURE__*/React.createElement(Dropdown.Item, {
21
+ key: scale.value,
22
+ active: dataset.controls.scale.matrixplot.name === scale.name,
23
+ onClick: () => {
24
+ dispatch({
25
+ type: "set.controls.scale",
26
+ plot: "matrixplot",
27
+ scale: scale
28
+ });
29
+ }
30
+ }, scale.name));
31
+ return /*#__PURE__*/React.createElement(ButtonToolbar, null, /*#__PURE__*/React.createElement(ButtonGroup, null, /*#__PURE__*/React.createElement(Dropdown, null, /*#__PURE__*/React.createElement(Dropdown.Toggle, {
32
+ id: "dropdownColorscale",
33
+ variant: "light"
34
+ }, dataset.controls.colorScale), /*#__PURE__*/React.createElement(Dropdown.Menu, null, colorScaleList))), /*#__PURE__*/React.createElement(ButtonGroup, null, /*#__PURE__*/React.createElement(InputGroup, null, /*#__PURE__*/React.createElement(InputGroup.Text, null, "Standard scale"), /*#__PURE__*/React.createElement(Dropdown, null, /*#__PURE__*/React.createElement(Dropdown.Toggle, {
35
+ id: "dropdownStandardScale",
36
+ variant: "light"
37
+ }, dataset.controls.scale.matrixplot.name), /*#__PURE__*/React.createElement(Dropdown.Menu, null, standardScaleList)))));
38
+ }