@haniffalab/cherita-react 1.3.0-dev.2025-06-06.f1eddad0 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (138) hide show
  1. package/README.md +1 -1
  2. package/dist/cjs/components/controls/Controls.js +38 -30
  3. package/dist/cjs/components/dotplot/Dotplot.js +67 -69
  4. package/dist/cjs/components/dotplot/DotplotControls.js +103 -83
  5. package/dist/cjs/components/full-page/FullPage.js +99 -105
  6. package/dist/cjs/components/full-page/PlotAlert.js +45 -0
  7. package/dist/cjs/components/full-page/PlotTypeSelector.js +89 -44
  8. package/dist/cjs/components/heatmap/Heatmap.js +65 -65
  9. package/dist/cjs/components/heatmap/HeatmapControls.js +6 -3
  10. package/dist/cjs/components/icons/DotPlotIcon.js +64 -0
  11. package/dist/cjs/components/icons/HeatmapIcon.js +45 -0
  12. package/dist/cjs/components/icons/MatrixPlotIcon.1.js +57 -0
  13. package/dist/cjs/components/icons/MatrixPlotIcon.js +59 -0
  14. package/dist/cjs/components/icons/ScatterplotIcon.1.js +164 -0
  15. package/dist/cjs/components/icons/ScatterplotIcon.js +144 -0
  16. package/dist/cjs/components/icons/ViolinPlotIcon.js +42 -0
  17. package/dist/cjs/components/matrixplot/Matrixplot.js +65 -66
  18. package/dist/cjs/components/matrixplot/MatrixplotControls.js +8 -5
  19. package/dist/cjs/components/obs-list/ObsItem.js +267 -205
  20. package/dist/cjs/components/obs-list/ObsList.js +161 -129
  21. package/dist/cjs/components/obs-list/ObsToolbar.js +2 -3
  22. package/dist/cjs/components/obsm-list/ObsmList.js +67 -28
  23. package/dist/cjs/components/offcanvas/index.js +62 -27
  24. package/dist/cjs/components/pseudospatial/Pseudospatial.js +132 -76
  25. package/dist/cjs/components/pseudospatial/PseudospatialToolbar.js +122 -74
  26. package/dist/cjs/components/scatterplot/Scatterplot.js +128 -100
  27. package/dist/cjs/components/scatterplot/ScatterplotControls.js +45 -31
  28. package/dist/cjs/components/scatterplot/SpatialControls.js +140 -113
  29. package/dist/cjs/components/scatterplot/Toolbox.js +41 -30
  30. package/dist/cjs/components/search-bar/SearchBar.js +176 -120
  31. package/dist/cjs/components/search-bar/SearchInfo.js +76 -50
  32. package/dist/cjs/components/search-bar/SearchResults.js +93 -71
  33. package/dist/cjs/components/toolbar/Toolbar.js +46 -37
  34. package/dist/cjs/components/var-list/VarItem.js +131 -103
  35. package/dist/cjs/components/var-list/VarList.js +85 -71
  36. package/dist/cjs/components/var-list/VarListToolbar.js +59 -54
  37. package/dist/cjs/components/var-list/VarSet.js +126 -108
  38. package/dist/cjs/components/violin/Violin.js +109 -97
  39. package/dist/cjs/components/violin/ViolinControls.js +8 -5
  40. package/dist/cjs/constants/colorscales.js +19 -19
  41. package/dist/cjs/constants/constants.js +51 -48
  42. package/dist/cjs/context/DatasetContext.js +26 -17
  43. package/dist/cjs/context/FilterContext.js +11 -9
  44. package/dist/cjs/context/SettingsContext.js +271 -88
  45. package/dist/cjs/context/ZarrDataContext.js +6 -5
  46. package/dist/cjs/helpers/color-helper.js +2 -2
  47. package/dist/cjs/helpers/zarr-helper.js +3 -3
  48. package/dist/cjs/utils/Filter.js +16 -11
  49. package/dist/cjs/utils/Histogram.js +35 -33
  50. package/dist/cjs/utils/ImageViewer.js +11 -8
  51. package/dist/cjs/utils/Legend.js +37 -30
  52. package/dist/cjs/utils/LoadingIndicators.js +15 -13
  53. package/dist/cjs/utils/Resolver.js +213 -0
  54. package/dist/cjs/utils/Skeleton.js +10 -10
  55. package/dist/cjs/utils/StyledTooltip.js +44 -0
  56. package/dist/cjs/utils/VirtualizedList.js +36 -29
  57. package/dist/cjs/utils/errors.js +15 -15
  58. package/dist/cjs/utils/requests.js +21 -9
  59. package/dist/cjs/utils/search.js +4 -4
  60. package/dist/cjs/utils/string.js +6 -6
  61. package/dist/cjs/utils/zarrData.js +20 -21
  62. package/dist/css/cherita.css +135 -65
  63. package/dist/css/cherita.css.map +1 -1
  64. package/dist/esm/components/controls/Controls.js +43 -35
  65. package/dist/esm/components/dotplot/Dotplot.js +77 -78
  66. package/dist/esm/components/dotplot/DotplotControls.js +106 -85
  67. package/dist/esm/components/full-page/FullPage.js +119 -124
  68. package/dist/esm/components/full-page/PlotAlert.js +39 -0
  69. package/dist/esm/components/full-page/PlotTypeSelector.js +90 -45
  70. package/dist/esm/components/heatmap/Heatmap.js +75 -74
  71. package/dist/esm/components/heatmap/HeatmapControls.js +8 -4
  72. package/dist/esm/components/icons/DotPlotIcon.js +58 -0
  73. package/dist/esm/components/icons/HeatmapIcon.js +39 -0
  74. package/dist/esm/components/icons/MatrixPlotIcon.1.js +51 -0
  75. package/dist/esm/components/icons/MatrixPlotIcon.js +53 -0
  76. package/dist/esm/components/icons/ScatterplotIcon.1.js +158 -0
  77. package/dist/esm/components/icons/ScatterplotIcon.js +138 -0
  78. package/dist/esm/components/icons/ViolinPlotIcon.js +36 -0
  79. package/dist/esm/components/matrixplot/Matrixplot.js +75 -75
  80. package/dist/esm/components/matrixplot/MatrixplotControls.js +10 -6
  81. package/dist/esm/components/obs-list/ObsItem.js +282 -217
  82. package/dist/esm/components/obs-list/ObsList.js +176 -143
  83. package/dist/esm/components/obs-list/ObsToolbar.js +3 -3
  84. package/dist/esm/components/obsm-list/ObsmList.js +71 -32
  85. package/dist/esm/components/offcanvas/index.js +68 -33
  86. package/dist/esm/components/pseudospatial/Pseudospatial.js +145 -88
  87. package/dist/esm/components/pseudospatial/PseudospatialToolbar.js +127 -78
  88. package/dist/esm/components/scatterplot/Scatterplot.js +149 -120
  89. package/dist/esm/components/scatterplot/ScatterplotControls.js +50 -35
  90. package/dist/esm/components/scatterplot/SpatialControls.js +153 -125
  91. package/dist/esm/components/scatterplot/Toolbox.js +44 -32
  92. package/dist/esm/components/search-bar/SearchBar.js +187 -130
  93. package/dist/esm/components/search-bar/SearchInfo.js +86 -59
  94. package/dist/esm/components/search-bar/SearchResults.js +100 -77
  95. package/dist/esm/components/toolbar/Toolbar.js +49 -39
  96. package/dist/esm/components/var-list/VarItem.js +142 -113
  97. package/dist/esm/components/var-list/VarList.js +99 -84
  98. package/dist/esm/components/var-list/VarListToolbar.js +64 -58
  99. package/dist/esm/components/var-list/VarSet.js +134 -115
  100. package/dist/esm/components/violin/Violin.js +121 -108
  101. package/dist/esm/components/violin/ViolinControls.js +10 -6
  102. package/dist/esm/constants/colorscales.js +19 -19
  103. package/dist/esm/constants/constants.js +50 -47
  104. package/dist/esm/context/DatasetContext.js +33 -23
  105. package/dist/esm/context/FilterContext.js +11 -8
  106. package/dist/esm/context/SettingsContext.js +273 -89
  107. package/dist/esm/context/ZarrDataContext.js +8 -6
  108. package/dist/esm/helpers/color-helper.js +5 -5
  109. package/dist/esm/helpers/map-helper.js +2 -2
  110. package/dist/esm/helpers/zarr-helper.js +6 -6
  111. package/dist/esm/index.js +22 -22
  112. package/dist/esm/utils/Filter.js +22 -17
  113. package/dist/esm/utils/Histogram.js +39 -37
  114. package/dist/esm/utils/ImageViewer.js +12 -8
  115. package/dist/esm/utils/Legend.js +44 -36
  116. package/dist/esm/utils/LoadingIndicators.js +16 -13
  117. package/dist/esm/utils/Resolver.js +201 -0
  118. package/dist/esm/utils/Skeleton.js +11 -10
  119. package/dist/esm/utils/StyledTooltip.js +38 -0
  120. package/dist/esm/utils/VirtualizedList.js +37 -29
  121. package/dist/esm/utils/errors.js +15 -15
  122. package/dist/esm/utils/requests.js +24 -12
  123. package/dist/esm/utils/search.js +7 -7
  124. package/dist/esm/utils/string.js +7 -7
  125. package/dist/esm/utils/zarrData.js +27 -28
  126. package/package.json +21 -10
  127. package/scss/cherita-bootstrap.scss +2 -2
  128. package/scss/cherita.scss +65 -16
  129. package/scss/components/accordions.scss +15 -2
  130. package/scss/components/layouts.scss +68 -50
  131. package/scss/components/lists.scss +16 -5
  132. package/scss/components/plotly.scss +38 -26
  133. package/scss/components/plots.scss +14 -1
  134. package/dist/assets/images/plots/dotplot.svg +0 -152
  135. package/dist/assets/images/plots/heatmap.svg +0 -193
  136. package/dist/assets/images/plots/matrixplot.svg +0 -275
  137. package/dist/assets/images/plots/scatterplot.svg +0 -198
  138. package/dist/assets/images/plots/violin.svg +0 -50
@@ -1,50 +1,95 @@
1
- import React from "react";
2
- import dotplotIcon from "../../../assets/images/plots/dotplot.svg";
3
- import heatmapIcon from "../../../assets/images/plots/heatmap.svg";
4
- import matrixplotIcon from "../../../assets/images/plots/matrixplot.svg";
5
- import scatterplotIcon from "../../../assets/images/plots/scatterplot.svg";
6
- import violinIcon from "../../../assets/images/plots/violin.svg";
7
- import { PLOT_TYPES } from "../../constants/constants";
8
- const iconMap = {
9
- [PLOT_TYPES.DOTPLOT]: dotplotIcon,
10
- [PLOT_TYPES.MATRIXPLOT]: matrixplotIcon,
11
- [PLOT_TYPES.VIOLINPLOT]: violinIcon,
12
- [PLOT_TYPES.SCATTERPLOT]: scatterplotIcon,
13
- [PLOT_TYPES.HEATMAP]: heatmapIcon
14
- };
15
- const plotTypes = Object.entries(iconMap).map(_ref => {
16
- let [type, icon] = _ref;
17
- return {
18
- type,
19
- icon,
20
- alt: type.charAt(0).toUpperCase() + type.slice(1)
21
- };
22
- });
23
- export function PlotTypeSelector(_ref2) {
1
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
2
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
3
+ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
4
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
5
+ function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
6
+ import { useState } from 'react';
7
+ import { PLOT_TYPES } from '../../constants/constants';
8
+ import { StyledTooltip } from '../../utils/StyledTooltip';
9
+ import DotPlotIcon from '../icons/DotPlotIcon';
10
+ import HeatmapIcon from '../icons/HeatmapIcon';
11
+ import MatrixPlotIcon from '../icons/MatrixPlotIcon';
12
+ import ScatterplotIcon from '../icons/ScatterplotIcon';
13
+ import ViolinPlotIcon from '../icons/ViolinPlotIcon';
14
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
15
+ const plotTypes = [{
16
+ type: PLOT_TYPES.SCATTERPLOT,
17
+ icon: ScatterplotIcon,
18
+ name: 'Scatterplot',
19
+ description: 'Displays cells in 2D based on dimensionality reduction.'
20
+ }, {
21
+ type: PLOT_TYPES.MATRIXPLOT,
22
+ icon: MatrixPlotIcon,
23
+ name: 'Matrix Plot',
24
+ description: 'Shows expression values of genes across categories.'
25
+ }, {
26
+ type: PLOT_TYPES.DOTPLOT,
27
+ icon: DotPlotIcon,
28
+ name: 'Dot Plot',
29
+ description: 'Shows proportion and expression of genes across groups.'
30
+ }, {
31
+ type: PLOT_TYPES.HEATMAP,
32
+ icon: HeatmapIcon,
33
+ name: 'Heatmap',
34
+ description: 'Visualises gene expression or feature activity as a colour-coded matrix.'
35
+ }, {
36
+ type: PLOT_TYPES.VIOLINPLOT,
37
+ icon: ViolinPlotIcon,
38
+ name: 'Violin Plot',
39
+ description: 'Displays distribution of gene expression across categories.'
40
+ }];
41
+ export function PlotTypeSelector(_ref) {
24
42
  let {
25
43
  currentType,
26
44
  onChange
27
- } = _ref2;
28
- return /*#__PURE__*/React.createElement("div", {
29
- className: "d-flex gap-2 justify-content-between"
30
- }, plotTypes.map(_ref3 => {
31
- let {
32
- type,
33
- icon,
34
- alt
35
- } = _ref3;
36
- return /*#__PURE__*/React.createElement("img", {
37
- key: type,
38
- src: icon,
39
- alt: alt,
40
- height: 32,
41
- width: 32,
42
- className: "plotselector-icon".concat(currentType === type ? " active" : ""),
43
- onClick: () => onChange(type),
44
- style: {
45
- borderBottom: currentType === type ? "2px solid #007bff" : "none"
46
- },
47
- title: alt
48
- });
45
+ } = _ref;
46
+ const [hoveredMap, setHoveredMap] = useState({});
47
+ const handleMouseEnter = type => setHoveredMap(prev => _objectSpread(_objectSpread({}, prev), {}, {
48
+ [type]: true
49
49
  }));
50
+ const handleMouseLeave = type => setHoveredMap(prev => _objectSpread(_objectSpread({}, prev), {}, {
51
+ [type]: false
52
+ }));
53
+ return /*#__PURE__*/_jsx("div", {
54
+ className: "d-flex gap-2 justify-content-between",
55
+ children: plotTypes.map(_ref2 => {
56
+ let {
57
+ type,
58
+ icon: Icon,
59
+ name,
60
+ description
61
+ } = _ref2;
62
+ const isActive = currentType === type;
63
+ const hovered = hoveredMap[type] || false;
64
+ const colour = isActive ? '#005a86' : hovered ? '#0071a7' : '#000';
65
+ return /*#__PURE__*/_jsx(StyledTooltip, {
66
+ title: /*#__PURE__*/_jsxs(_Fragment, {
67
+ children: [/*#__PURE__*/_jsx("strong", {
68
+ children: name
69
+ }), /*#__PURE__*/_jsx("br", {}), description]
70
+ }),
71
+ placement: "bottom",
72
+ slotProps: {
73
+ popper: {
74
+ modifiers: [{
75
+ name: 'offset',
76
+ options: {
77
+ offset: [0, -12]
78
+ }
79
+ }]
80
+ }
81
+ },
82
+ children: /*#__PURE__*/_jsx("div", {
83
+ onMouseEnter: () => handleMouseEnter(type),
84
+ onMouseLeave: () => handleMouseLeave(type),
85
+ onClick: () => onChange(type),
86
+ className: "plotselector-icon".concat(isActive ? ' active' : ''),
87
+ children: /*#__PURE__*/_jsx(Icon, {
88
+ size: 34,
89
+ colour: colour
90
+ })
91
+ })
92
+ }, type);
93
+ })
94
+ });
50
95
  }
@@ -3,28 +3,32 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
3
3
  function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
4
4
  function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
5
5
  function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
6
- import React, { useCallback, useEffect, useRef, useState } from "react";
7
- import _ from "lodash";
8
- import { Alert, Button } from "react-bootstrap";
9
- import Plot from "react-plotly.js";
10
- import { PLOTLY_MODEBAR_BUTTONS } from "../../constants/constants";
11
- import { useDataset } from "../../context/DatasetContext";
12
- import { useFilteredData } from "../../context/FilterContext";
13
- import { useSettings } from "../../context/SettingsContext";
14
- import { LoadingSpinner } from "../../utils/LoadingIndicators";
15
- import { useDebouncedFetch } from "../../utils/requests";
16
- import { ControlsPlotlyToolbar, ObsPlotlyToolbar, VarPlotlyToolbar } from "../toolbar/Toolbar";
6
+ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
7
+ import _ from 'lodash';
8
+ import { Button } from 'react-bootstrap';
9
+ import Plot from 'react-plotly.js';
10
+ import { PLOTLY_MODEBAR_BUTTONS } from '../../constants/constants';
11
+ import { useDataset } from '../../context/DatasetContext';
12
+ import { useFilteredData } from '../../context/FilterContext';
13
+ import { useSettings } from '../../context/SettingsContext';
14
+ import { LoadingSpinner } from '../../utils/LoadingIndicators';
15
+ import { useDebouncedFetch } from '../../utils/requests';
16
+ import { useSelectedMultiVar, useSelectedObs } from '../../utils/Resolver';
17
+ import { PlotAlert } from '../full-page/PlotAlert';
18
+ import { ControlsPlotlyToolbar, ObsPlotlyToolbar, VarPlotlyToolbar } from '../toolbar/Toolbar';
19
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
17
20
  export function Heatmap(_ref) {
18
- var _settings$selectedObs, _settings$selectedObs2, _settings$selectedObs3;
19
21
  let {
20
22
  showObsBtn = false,
21
23
  showVarsBtn = false,
22
24
  showCtrlsBtn = false,
23
25
  setShowObs,
24
26
  setShowVars,
25
- setShowControls
27
+ setShowControls,
28
+ plotType,
29
+ setPlotType
26
30
  } = _ref;
27
- const ENDPOINT = "heatmap";
31
+ const ENDPOINT = 'heatmap';
28
32
  const dataset = useDataset();
29
33
  const settings = useSettings();
30
34
  const {
@@ -35,44 +39,26 @@ export function Heatmap(_ref) {
35
39
  const [data, setData] = useState([]);
36
40
  const [layout, setLayout] = useState({});
37
41
  const [hasSelections, setHasSelections] = useState(false);
38
- const [params, setParams] = useState({
42
+ const selectedObs = useSelectedObs();
43
+ const selectedMultiVar = useSelectedMultiVar();
44
+ const params = useMemo(() => ({
39
45
  url: dataset.url,
40
- obsCol: settings.selectedObs,
41
- obsValues: !((_settings$selectedObs = settings.selectedObs) !== null && _settings$selectedObs !== void 0 && _settings$selectedObs.omit.length) ? null : _.difference(_.values((_settings$selectedObs2 = settings.selectedObs) === null || _settings$selectedObs2 === void 0 ? void 0 : _settings$selectedObs2.codes), (_settings$selectedObs3 = settings.selectedObs) === null || _settings$selectedObs3 === void 0 ? void 0 : _settings$selectedObs3.omit).map(c => {
42
- var _settings$selectedObs4;
43
- return (_settings$selectedObs4 = settings.selectedObs) === null || _settings$selectedObs4 === void 0 ? void 0 : _settings$selectedObs4.codesMap[c];
44
- }),
45
- varKeys: settings.selectedMultiVar.map(i => i.isSet ? {
46
+ obsCol: selectedObs,
47
+ obsValues: !(selectedObs !== null && selectedObs !== void 0 && selectedObs.omit.length) ? null : _.difference(selectedObs === null || selectedObs === void 0 ? void 0 : selectedObs.values, selectedObs === null || selectedObs === void 0 ? void 0 : selectedObs.omit),
48
+ varKeys: selectedMultiVar.map(i => i.isSet ? {
46
49
  name: i.name,
47
50
  indices: i.vars.map(v => v.index)
48
51
  } : i.index),
49
52
  obsIndices: isSliced ? [...(obsIndices || [])] : null,
50
53
  varNamesCol: dataset.varNamesCol
51
- });
54
+ }), [dataset.url, dataset.varNamesCol, isSliced, obsIndices, selectedMultiVar, selectedObs]);
52
55
  useEffect(() => {
53
- if (settings.selectedObs && settings.selectedMultiVar.length) {
56
+ if (selectedObs && selectedMultiVar.length) {
54
57
  setHasSelections(true);
55
58
  } else {
56
59
  setHasSelections(false);
57
60
  }
58
- setParams(p => {
59
- var _settings$selectedObs5, _settings$selectedObs6, _settings$selectedObs7;
60
- return _objectSpread(_objectSpread({}, p), {}, {
61
- url: dataset.url,
62
- obsCol: settings.selectedObs,
63
- obsValues: !((_settings$selectedObs5 = settings.selectedObs) !== null && _settings$selectedObs5 !== void 0 && _settings$selectedObs5.omit.length) ? null : _.difference(_.values((_settings$selectedObs6 = settings.selectedObs) === null || _settings$selectedObs6 === void 0 ? void 0 : _settings$selectedObs6.codes), (_settings$selectedObs7 = settings.selectedObs) === null || _settings$selectedObs7 === void 0 ? void 0 : _settings$selectedObs7.omit).map(c => {
64
- var _settings$selectedObs8;
65
- return (_settings$selectedObs8 = settings.selectedObs) === null || _settings$selectedObs8 === void 0 ? void 0 : _settings$selectedObs8.codesMap[c];
66
- }),
67
- varKeys: settings.selectedMultiVar.map(i => i.isSet ? {
68
- name: i.name,
69
- indices: i.vars.map(v => v.index)
70
- } : i.index),
71
- obsIndices: isSliced ? [...(obsIndices || [])] : null,
72
- varNamesCol: dataset.varNamesCol
73
- });
74
- });
75
- }, [settings.selectedMultiVar, settings.selectedObs, dataset.url, dataset.varNamesCol, obsIndices, isSliced]);
61
+ }, [selectedMultiVar, selectedObs, dataset.url, dataset.varNamesCol, obsIndices, isSliced]);
76
62
  const updateColorscale = useCallback(colorscale => {
77
63
  setLayout(l => {
78
64
  return _objectSpread(_objectSpread({}, l), {}, {
@@ -87,13 +73,16 @@ export function Heatmap(_ref) {
87
73
  isPending,
88
74
  serverError
89
75
  } = useDebouncedFetch(ENDPOINT, params, 500, {
90
- enabled: !!params.obsCol && !!params.varKeys.length
76
+ isEnabled: params => !!params.obsCol && !!params.varKeys.length
91
77
  });
92
78
  useEffect(() => {
93
- if (hasSelections && !isPending && !serverError) {
79
+ if (hasSelections && !!fetchedData && !isPending && !serverError) {
94
80
  setData(fetchedData.data);
95
81
  setLayout(fetchedData.layout);
96
82
  updateColorscale(colorscale.current);
83
+ } else {
84
+ setData([]);
85
+ setLayout({});
97
86
  }
98
87
  }, [fetchedData, hasSelections, isPending, serverError, updateColorscale]);
99
88
  useEffect(() => {
@@ -110,38 +99,50 @@ export function Heatmap(_ref) {
110
99
  const modeBarButtons = customModeBarButtons.length ? [customModeBarButtons, PLOTLY_MODEBAR_BUTTONS] : [PLOTLY_MODEBAR_BUTTONS];
111
100
  if (!serverError) {
112
101
  if (hasSelections) {
113
- return /*#__PURE__*/React.createElement("div", {
114
- className: "cherita-plot cherita-heatmap position-relative"
115
- }, isPending && /*#__PURE__*/React.createElement(LoadingSpinner, null), /*#__PURE__*/React.createElement(Plot, {
116
- data: data,
117
- layout: layout,
118
- useResizeHandler: true,
119
- style: {
120
- width: "100%",
121
- height: "100%"
122
- },
123
- config: {
124
- displaylogo: false,
125
- modeBarButtons: modeBarButtons
126
- }
127
- }));
102
+ return /*#__PURE__*/_jsxs("div", {
103
+ className: "cherita-plot cherita-heatmap position-relative",
104
+ children: [isPending && /*#__PURE__*/_jsx(LoadingSpinner, {}), /*#__PURE__*/_jsx(Plot, {
105
+ data: data,
106
+ layout: layout,
107
+ useResizeHandler: true,
108
+ style: {
109
+ width: '100%',
110
+ height: '100%'
111
+ },
112
+ config: {
113
+ displaylogo: false,
114
+ modeBarButtons: modeBarButtons
115
+ }
116
+ })]
117
+ });
128
118
  }
129
- return /*#__PURE__*/React.createElement("div", {
130
- className: "cherita-heatmap"
131
- }, /*#__PURE__*/React.createElement(Alert, {
132
- variant: "light"
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"));
119
+ return /*#__PURE__*/_jsx(PlotAlert, {
120
+ variant: "info",
121
+ heading: "Set up your heatmap",
122
+ plotType: plotType,
123
+ setPlotType: setPlotType,
124
+ children: /*#__PURE__*/_jsxs("p", {
125
+ className: "p-0 m-0",
126
+ children: ["Select one or more", ' ', showVarsBtn ? /*#__PURE__*/_jsx(Button, {
127
+ variant: "link",
128
+ className: "border-0 p-0 align-baseline",
129
+ onClick: setShowVars,
130
+ children: "features"
131
+ }) : 'features', ' ', "to display their expression, then choose a", ' ', showObsBtn ? /*#__PURE__*/_jsx(Button, {
132
+ variant: "link",
133
+ className: "border-0 p-0 align-baseline",
134
+ onClick: setShowObs,
135
+ children: "category"
136
+ }) : 'category', ' ', "to group observations in the heatmap."]
137
+ })
138
+ });
142
139
  } else {
143
- return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Alert, {
144
- variant: "danger"
145
- }, serverError.message));
140
+ return /*#__PURE__*/_jsx(PlotAlert, {
141
+ variant: "danger",
142
+ heading: "Error displaying the heatmap",
143
+ plotType: plotType,
144
+ setPlotType: setPlotType,
145
+ children: serverError.message || 'An unexpected error occurred while generating the plot.'
146
+ });
146
147
  }
147
148
  }
@@ -1,6 +1,10 @@
1
- import React from "react";
2
- import { Form } from "react-bootstrap";
3
- import { ColorscaleSelect } from "../controls/Controls";
1
+ import { Form } from 'react-bootstrap';
2
+ import { ColorscaleSelect } from '../controls/Controls';
3
+ import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
4
4
  export function HeatmapControls() {
5
- return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Form, null, /*#__PURE__*/React.createElement(ColorscaleSelect, null)));
5
+ return /*#__PURE__*/_jsx(_Fragment, {
6
+ children: /*#__PURE__*/_jsx(Form, {
7
+ children: /*#__PURE__*/_jsx(ColorscaleSelect, {})
8
+ })
9
+ });
6
10
  }
@@ -0,0 +1,58 @@
1
+ const _excluded = ["size", "colour", "gap"];
2
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
3
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
4
+ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
5
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
6
+ 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); }
7
+ import { jsx as _jsx } from "react/jsx-runtime";
8
+ function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; }
9
+ function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
10
+ export default function DotPlotIcon(_ref) {
11
+ let {
12
+ size = 40,
13
+ colour = '#000',
14
+ gap = 20
15
+ } = _ref,
16
+ props = _objectWithoutProperties(_ref, _excluded);
17
+ const rows = 3;
18
+ const cols = 3;
19
+
20
+ // Define two radii: small and large
21
+ const smallR = 10;
22
+ const largeR = 16;
23
+
24
+ // Indices for large circles
25
+ const largeIndices = [1, 4, 5, 6, 7];
26
+
27
+ // Indices for semi-transparent circles
28
+ const semiTransparentIndices = [0, 4, 8];
29
+ const circles = [];
30
+ for (let row = 0; row < rows; row++) {
31
+ for (let col = 0; col < cols; col++) {
32
+ const index = row * cols + col;
33
+ const r = largeIndices.includes(index) ? largeR : smallR;
34
+ circles.push({
35
+ cx: col * (2 * largeR + gap) + largeR,
36
+ cy: row * (2 * largeR + gap) + largeR,
37
+ r,
38
+ fill: colour,
39
+ fillOpacity: semiTransparentIndices.includes(index) ? 0.5 : 1
40
+ });
41
+ }
42
+ }
43
+ const viewBoxSize = (cols - 1) * (2 * largeR + gap) + 2 * largeR;
44
+ return /*#__PURE__*/_jsx("svg", _objectSpread(_objectSpread({
45
+ width: size,
46
+ height: size,
47
+ viewBox: "0 0 ".concat(viewBoxSize, " ").concat(viewBoxSize),
48
+ xmlns: "http://www.w3.org/2000/svg"
49
+ }, props), {}, {
50
+ children: circles.map((circle, i) => /*#__PURE__*/_jsx("circle", {
51
+ cx: circle.cx,
52
+ cy: circle.cy,
53
+ r: circle.r,
54
+ fill: circle.fill,
55
+ fillOpacity: circle.fillOpacity
56
+ }, i))
57
+ }));
58
+ }
@@ -0,0 +1,39 @@
1
+ const _excluded = ["size", "colour", "gap"];
2
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
3
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
4
+ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
5
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
6
+ 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); }
7
+ import { jsx as _jsx } from "react/jsx-runtime";
8
+ function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; }
9
+ function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
10
+ export default function HeatmapIcon(_ref) {
11
+ let {
12
+ size = 40,
13
+ colour = '#000',
14
+ gap = 1
15
+ } = _ref,
16
+ props = _objectWithoutProperties(_ref, _excluded);
17
+ const rows = 6; // genes
18
+ const cols = 8; // cells
19
+
20
+ // Example expression pattern for visual clusters
21
+ const expressionLevels = [[1, 0.8, 0.2, 0.2, 0.5, 0.9, 1, 0.7], [0.9, 0.7, 0.1, 0.2, 0.4, 0.8, 0.9, 0.6], [0.1, 0.2, 0.8, 0.9, 0.7, 0.2, 0.1, 0.3], [0.2, 0.3, 0.9, 1, 0.8, 0.3, 0.2, 0.4], [0.5, 0.6, 0.2, 0.1, 0.9, 0.7, 0.6, 0.8], [0.6, 0.7, 0.3, 0.2, 0.8, 0.6, 0.7, 0.9]];
22
+ const cellWidth = (size - (cols - 1) * gap) / cols;
23
+ const cellHeight = (size - (rows - 1) * gap) / rows;
24
+ return /*#__PURE__*/_jsx("svg", _objectSpread(_objectSpread({
25
+ width: size,
26
+ height: size,
27
+ viewBox: "0 0 ".concat(size, " ").concat(size),
28
+ xmlns: "http://www.w3.org/2000/svg"
29
+ }, props), {}, {
30
+ children: expressionLevels.map((row, rowIndex) => row.map((value, colIndex) => /*#__PURE__*/_jsx("rect", {
31
+ x: colIndex * (cellWidth + gap),
32
+ y: rowIndex * (cellHeight + gap),
33
+ width: cellWidth,
34
+ height: cellHeight,
35
+ fill: colour,
36
+ fillOpacity: value
37
+ }, "".concat(rowIndex, "-").concat(colIndex))))
38
+ }));
39
+ }
@@ -0,0 +1,51 @@
1
+ const _excluded = ["size", "colour", "gap"];
2
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
3
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
4
+ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
5
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
6
+ 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); }
7
+ import { jsx as _jsx } from "react/jsx-runtime";
8
+ function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; }
9
+ function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
10
+ export default function MatrixPlotIcon(_ref) {
11
+ let {
12
+ size = 40,
13
+ colour = '#000',
14
+ gap = 2
15
+ } = _ref,
16
+ props = _objectWithoutProperties(_ref, _excluded);
17
+ const rows = 4;
18
+ const cols = 4;
19
+ const squareSize = (size - gap * (cols - 1)) / cols;
20
+ const squares = [];
21
+ for (let row = 0; row < rows; row++) {
22
+ for (let col = 0; col < cols; col++) {
23
+ squares.push({
24
+ x: col * (squareSize + gap),
25
+ y: row * (squareSize + gap)
26
+ });
27
+ }
28
+ }
29
+ const semiTransparentSquares = [0, 5, 10, 15];
30
+ return /*#__PURE__*/_jsx("svg", _objectSpread(_objectSpread({
31
+ width: size,
32
+ height: size,
33
+ viewBox: "0 0 ".concat(size, " ").concat(size),
34
+ xmlns: "http://www.w3.org/2000/svg"
35
+ }, props), {}, {
36
+ children: squares.map((_ref2, i) => {
37
+ let {
38
+ x,
39
+ y
40
+ } = _ref2;
41
+ return /*#__PURE__*/_jsx("rect", {
42
+ x: x,
43
+ y: y,
44
+ width: squareSize,
45
+ height: squareSize,
46
+ fill: colour,
47
+ fillOpacity: semiTransparentSquares.includes(i) ? 0.5 : 1
48
+ }, i);
49
+ })
50
+ }));
51
+ }
@@ -0,0 +1,53 @@
1
+ const _excluded = ["size", "colour", "gap"];
2
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
3
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
4
+ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
5
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
6
+ 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); }
7
+ import { jsx as _jsx } from "react/jsx-runtime";
8
+ function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; }
9
+ function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
10
+ export default function MatrixPlotIcon(_ref) {
11
+ let {
12
+ size = 40,
13
+ colour = '#000',
14
+ gap = 2
15
+ } = _ref,
16
+ props = _objectWithoutProperties(_ref, _excluded);
17
+ const rows = 3;
18
+ const cols = 3;
19
+ const squareSize = (size - gap * (cols - 1)) / cols;
20
+ const squares = [];
21
+ for (let row = 0; row < rows; row++) {
22
+ for (let col = 0; col < cols; col++) {
23
+ squares.push({
24
+ x: col * (squareSize + gap),
25
+ y: row * (squareSize + gap)
26
+ });
27
+ }
28
+ }
29
+
30
+ // Example: corners semi-transparent
31
+ const semiTransparentSquares = [0, 2, 6, 8];
32
+ return /*#__PURE__*/_jsx("svg", _objectSpread(_objectSpread({
33
+ width: size,
34
+ height: size,
35
+ viewBox: "0 0 ".concat(size, " ").concat(size),
36
+ xmlns: "http://www.w3.org/2000/svg"
37
+ }, props), {}, {
38
+ children: squares.map((_ref2, i) => {
39
+ let {
40
+ x,
41
+ y
42
+ } = _ref2;
43
+ return /*#__PURE__*/_jsx("rect", {
44
+ x: x,
45
+ y: y,
46
+ width: squareSize,
47
+ height: squareSize,
48
+ fill: colour,
49
+ fillOpacity: semiTransparentSquares.includes(i) ? 0.5 : 1
50
+ }, i);
51
+ })
52
+ }));
53
+ }