@haniffalab/cherita-react 2.0.0 → 2.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 (67) hide show
  1. package/dist/cjs/components/dotplot/Dotplot.js +4 -5
  2. package/dist/cjs/components/dotplot/DotplotControls.js +7 -3
  3. package/dist/cjs/components/heatmap/Heatmap.js +4 -5
  4. package/dist/cjs/components/icons/HeatmapIcon.js +2 -2
  5. package/dist/cjs/components/matrixplot/Matrixplot.js +4 -5
  6. package/dist/cjs/components/obs-list/ObsItem.js +7 -7
  7. package/dist/cjs/components/offcanvas/OffCanvas.js +7 -4
  8. package/dist/cjs/components/plot/PlotTypeSelector.js +49 -10
  9. package/dist/cjs/components/pseudospatial/Pseudospatial.js +8 -5
  10. package/dist/cjs/components/scatterplot/Scatterplot.js +134 -136
  11. package/dist/cjs/components/scatterplot/ScatterplotLayer.js +144 -0
  12. package/dist/cjs/components/scatterplot/SpatialControls.js +7 -4
  13. package/dist/cjs/components/scatterplot/Toolbox.js +8 -4
  14. package/dist/cjs/components/search-bar/SearchBar.js +51 -29
  15. package/dist/cjs/components/search-bar/SearchInfo.js +2 -2
  16. package/dist/cjs/components/search-bar/SearchResults.js +9 -6
  17. package/dist/cjs/components/toolbar/Toolbar.js +10 -65
  18. package/dist/cjs/components/var-list/VarItem.js +4 -6
  19. package/dist/cjs/components/var-list/VarList.js +17 -9
  20. package/dist/cjs/components/var-list/VarListToolbar.js +1 -1
  21. package/dist/cjs/components/var-list/VarSet.js +7 -5
  22. package/dist/cjs/components/violin/Violin.js +6 -7
  23. package/dist/cjs/constants/constants.js +6 -3
  24. package/dist/cjs/context/DatasetContext.js +11 -2
  25. package/dist/cjs/context/SettingsContext.js +27 -2
  26. package/dist/cjs/helpers/color-helper.js +17 -12
  27. package/dist/cjs/index.js +0 -7
  28. package/dist/cjs/utils/Legend.js +6 -5
  29. package/dist/cjs/utils/requests.js +2 -2
  30. package/dist/cjs/views/ObservationFeature/StandardView.js +1 -1
  31. package/dist/cjs/views/PerturbationMap/ObsExplorer.js +11 -9
  32. package/dist/cjs/views/PerturbationMap/StandardView.js +2 -1
  33. package/dist/cjs/workers/scatterplotData.js +16 -0
  34. package/dist/esm/components/dotplot/Dotplot.js +5 -6
  35. package/dist/esm/components/dotplot/DotplotControls.js +6 -3
  36. package/dist/esm/components/heatmap/Heatmap.js +5 -6
  37. package/dist/esm/components/icons/HeatmapIcon.js +2 -2
  38. package/dist/esm/components/matrixplot/Matrixplot.js +5 -6
  39. package/dist/esm/components/obs-list/ObsItem.js +7 -7
  40. package/dist/esm/components/offcanvas/OffCanvas.js +7 -4
  41. package/dist/esm/components/plot/PlotTypeSelector.js +49 -10
  42. package/dist/esm/components/pseudospatial/Pseudospatial.js +8 -5
  43. package/dist/esm/components/scatterplot/Scatterplot.js +132 -134
  44. package/dist/esm/components/scatterplot/ScatterplotLayer.js +137 -0
  45. package/dist/esm/components/scatterplot/SpatialControls.js +7 -4
  46. package/dist/esm/components/scatterplot/Toolbox.js +8 -4
  47. package/dist/esm/components/search-bar/SearchBar.js +52 -30
  48. package/dist/esm/components/search-bar/SearchInfo.js +2 -2
  49. package/dist/esm/components/search-bar/SearchResults.js +9 -6
  50. package/dist/esm/components/toolbar/Toolbar.js +9 -63
  51. package/dist/esm/components/var-list/VarItem.js +4 -6
  52. package/dist/esm/components/var-list/VarList.js +17 -9
  53. package/dist/esm/components/var-list/VarListToolbar.js +1 -1
  54. package/dist/esm/components/var-list/VarSet.js +7 -5
  55. package/dist/esm/components/violin/Violin.js +7 -8
  56. package/dist/esm/constants/constants.js +5 -2
  57. package/dist/esm/context/DatasetContext.js +11 -2
  58. package/dist/esm/context/SettingsContext.js +27 -2
  59. package/dist/esm/helpers/color-helper.js +17 -12
  60. package/dist/esm/index.js +0 -1
  61. package/dist/esm/utils/Legend.js +6 -5
  62. package/dist/esm/utils/requests.js +2 -2
  63. package/dist/esm/views/ObservationFeature/StandardView.js +1 -1
  64. package/dist/esm/views/PerturbationMap/ObsExplorer.js +11 -9
  65. package/dist/esm/views/PerturbationMap/StandardView.js +2 -1
  66. package/dist/esm/workers/scatterplotData.js +10 -0
  67. package/package.json +6 -3
@@ -176,7 +176,7 @@ function SettingsProvider(_ref2) {
176
176
 
177
177
  // If the buster is not set or does not match the current package version,
178
178
  // reset localSettings to avoid stale data
179
- if (!buster || buster !== "2.0.0") {
179
+ if (!buster || buster !== "2.1.0") {
180
180
  localSettings = {};
181
181
  }
182
182
  const initSettings = (0, _react.useRef)(initializer({
@@ -201,7 +201,7 @@ function SettingsProvider(_ref2) {
201
201
  if (canOverrideSettings && settings) {
202
202
  try {
203
203
  localStorage.setItem(DATASET_STORAGE_KEY, JSON.stringify(_objectSpread({
204
- buster: "2.0.0" || '0.0.0',
204
+ buster: "2.1.0" || '0.0.0',
205
205
  timestamp: Date.now()
206
206
  }, _lodash.default.omit(settings, 'data'))));
207
207
  } catch (err) {
@@ -345,6 +345,31 @@ function settingsReducer(settings, action) {
345
345
  }));
346
346
  }
347
347
  }
348
+ case 'select.multivar.batch':
349
+ {
350
+ const newVars = [];
351
+ let newVarData = {};
352
+ _lodash.default.forEach(action.vars, v => {
353
+ const inMultiVar = settings.selectedMultiVar.some(mv => mv.name === v.name);
354
+ if (!inMultiVar) {
355
+ const {
356
+ settings: varSettings,
357
+ data: varData
358
+ } = splitVar(v);
359
+ newVars.push(varSettings);
360
+ newVarData = _objectSpread(_objectSpread({}, newVarData), varData);
361
+ }
362
+ });
363
+ if (!newVars.length) {
364
+ return validateSettings(_objectSpread({}, settings));
365
+ }
366
+ return validateSettings(_objectSpread(_objectSpread({}, settings), {}, {
367
+ selectedMultiVar: [...settings.selectedMultiVar, ...newVars],
368
+ data: _objectSpread(_objectSpread({}, settings.data), {}, {
369
+ vars: _objectSpread(_objectSpread({}, settings.data.vars), newVarData)
370
+ })
371
+ }));
372
+ }
348
373
  case 'deselect.multivar':
349
374
  {
350
375
  return validateSettings(_objectSpread(_objectSpread({}, settings), {}, {
@@ -6,8 +6,8 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.useColor = exports.rgbToHex = void 0;
7
7
  var _react = require("react");
8
8
  var _colorscales = require("../constants/colorscales");
9
+ var _constants = require("../constants/constants");
9
10
  var _SettingsContext = require("../context/SettingsContext");
10
- const GRAY = [214, 212, 212];
11
11
  const parseHexColor = color => {
12
12
  const r = parseInt(color === null || color === void 0 ? void 0 : color.substring(1, 3), 16);
13
13
  const g = parseInt(color === null || color === void 0 ? void 0 : color.substring(3, 5), 16);
@@ -40,34 +40,39 @@ const rgbToHex = color => {
40
40
  return '#' + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
41
41
  };
42
42
  exports.rgbToHex = rgbToHex;
43
- const useColor = () => {
43
+ const useColor = _ref => {
44
+ let {
45
+ isCategorical = false,
46
+ colorscale = null
47
+ } = _ref;
44
48
  const settings = (0, _SettingsContext.useSettings)();
45
- const getColor = (0, _react.useCallback)(_ref => {
49
+ const colormap = (0, _react.useMemo)(() => {
50
+ return colorscale || _colorscales.COLORSCALES[isCategorical ? 'Accent' : settings.controls.colorScale];
51
+ }, [colorscale, isCategorical, settings.controls.colorScale]);
52
+ const getColor = (0, _react.useCallback)(_ref2 => {
46
53
  let {
47
54
  value,
48
- categorical = false,
49
55
  grayOut = false,
50
56
  grayParams: {
51
- alpha = 0.75,
52
- gray = 0.95
57
+ alpha = _constants.GRAY_ALPHA,
58
+ gray = _constants.GRAY_MIX
53
59
  } = {},
54
- colorEncoding = settings.colorEncoding,
55
- colorscale = null
56
- } = _ref;
57
- const colormap = colorscale || _colorscales.COLORSCALES[categorical ? 'Accent' : settings.controls.colorScale];
60
+ colorEncoding = settings.colorEncoding
61
+ } = _ref2;
58
62
  if (colorEncoding) {
59
63
  if (grayOut) {
60
64
  // Mix color with gray manually instead of chroma.mix to get better performance with deck.gl
61
65
  const rgb = computeColor(colormap, value);
62
- return [rgb[0] * (1 - gray) + GRAY[0] * gray, rgb[1] * (1 - gray) + GRAY[1] * gray, rgb[2] * (1 - gray) + GRAY[2] * gray, 255 * alpha];
66
+ return [rgb[0] * (1 - gray) + _constants.GRAY[0] * gray, rgb[1] * (1 - gray) + _constants.GRAY[1] * gray, rgb[2] * (1 - gray) + _constants.GRAY[2] * gray, 255 * alpha];
63
67
  } else {
64
68
  return [...computeColor(colormap, value), 255];
65
69
  }
66
70
  } else {
67
71
  return null;
68
72
  }
69
- }, [settings.colorEncoding, settings.controls.colorScale]);
73
+ }, [settings.colorEncoding, colormap]);
70
74
  return {
75
+ colormap,
71
76
  getColor
72
77
  };
73
78
  };
package/dist/cjs/index.js CHANGED
@@ -147,12 +147,6 @@ Object.defineProperty(exports, "SearchBar", {
147
147
  return _SearchBar.SearchBar;
148
148
  }
149
149
  });
150
- Object.defineProperty(exports, "Toolbar", {
151
- enumerable: true,
152
- get: function () {
153
- return _Toolbar.Toolbar;
154
- }
155
- });
156
150
  Object.defineProperty(exports, "VIOLIN_MODES", {
157
151
  enumerable: true,
158
152
  get: function () {
@@ -192,7 +186,6 @@ var _Pseudospatial = require("./components/pseudospatial/Pseudospatial");
192
186
  var _Scatterplot = require("./components/scatterplot/Scatterplot");
193
187
  var _ScatterplotControls = require("./components/scatterplot/ScatterplotControls");
194
188
  var _SearchBar = require("./components/search-bar/SearchBar");
195
- var _Toolbar = require("./components/toolbar/Toolbar");
196
189
  var _VarList = require("./components/var-list/VarList");
197
190
  var _Violin = require("./components/violin/Violin");
198
191
  var _ViolinControls = require("./components/violin/ViolinControls");
@@ -25,13 +25,14 @@ function Legend(_ref) {
25
25
  const settings = (0, _SettingsContext.useSettings)();
26
26
  const {
27
27
  getColor
28
- } = (0, _colorHelper.useColor)();
28
+ } = (0, _colorHelper.useColor)({
29
+ isCategorical,
30
+ colorscale
31
+ });
29
32
  const spanList = (0, _react.useMemo)(() => {
30
33
  return _lodash.default.range(100).map(i => {
31
34
  var color = (0, _colorHelper.rgbToHex)(getColor({
32
- value: i / 100,
33
- categorical: isCategorical,
34
- colorscale: colorscale
35
+ value: i / 100
35
36
  }));
36
37
  return /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
37
38
  className: "grad-step",
@@ -40,7 +41,7 @@ function Legend(_ref) {
40
41
  }
41
42
  }, i);
42
43
  });
43
- }, [colorscale, getColor, isCategorical]);
44
+ }, [getColor]);
44
45
  if (settings.colorEncoding && !isCategorical) {
45
46
  var _settings$selectedVar, _settings$selectedObs;
46
47
  return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
@@ -15,8 +15,8 @@ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol"
15
15
  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); }
16
16
  async function fetchData(endpoint, params) {
17
17
  let signal = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
18
- let ms = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 300000;
19
- let apiUrl = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : null;
18
+ let apiUrl = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
19
+ let ms = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 300000;
20
20
  apiUrl = apiUrl || process.env.REACT_APP_API_URL;
21
21
  const controller = new AbortController();
22
22
  const timeout = setTimeout(() => {
@@ -109,7 +109,7 @@ function StandardView(_ref) {
109
109
  default:
110
110
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_Scatterplot.Scatterplot, _objectSpread({}, commonProps));
111
111
  }
112
- }, [plotType]);
112
+ }, [plotType, props]);
113
113
  return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
114
114
  className: "cherita-app",
115
115
  children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_DatasetContext.DatasetProvider, _objectSpread(_objectSpread({}, props), {}, {
@@ -149,7 +149,9 @@ function ObsExplorer() {
149
149
  selectedObsIndex
150
150
  } = (0, _SettingsContext.useSettings)();
151
151
  const {
152
- obsExplorer = {}
152
+ obsExplorer = {},
153
+ obsLabel,
154
+ valueLabel
153
155
  } = (0, _DatasetContext.useDataset)();
154
156
  (0, _parquetData.useParquet)(); // initialize duckdb instance
155
157
 
@@ -160,9 +162,9 @@ function ObsExplorer() {
160
162
  serverError
161
163
  } = (0, _zarrData.useObsColsData)(obsExplorer === null || obsExplorer === void 0 ? void 0 : obsExplorer.obsCols);
162
164
  if (selectedObsIndex == null) {
163
- return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
165
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
164
166
  className: "my-4 text-muted",
165
- children: "Select a point in the scatterplot to view details about the gene perturbation."
167
+ children: ["Select a point in the scatterplot or search for ", obsLabel.plural, " to view details about the ", obsLabel.singular, " perturbation."]
166
168
  });
167
169
  }
168
170
  if (isPending) {
@@ -184,8 +186,8 @@ function ObsExplorer() {
184
186
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("h2", {
185
187
  className: "fw-bold mb-2",
186
188
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Tooltip.default, {
187
- title: /*#__PURE__*/(0, _jsxRuntime.jsx)(_jsxRuntime.Fragment, {
188
- children: "This panel shows metadata and predicted downstream effects for the selected gene perturbation across the atlas."
189
+ title: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
190
+ children: ["This panel shows metadata and predicted downstream effects for the selected ", obsLabel.singular, " perturbation across the atlas."]
189
191
  }),
190
192
  placement: "right",
191
193
  arrow: true,
@@ -200,8 +202,8 @@ function ObsExplorer() {
200
202
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("h5", {
201
203
  className: "fw-bold mb-2",
202
204
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Tooltip.default, {
203
- title: /*#__PURE__*/(0, _jsxRuntime.jsx)(_jsxRuntime.Fragment, {
204
- children: "These values describe how the selected gene perturbation is annotated in the atlas, including lineage, biological context, and summary scores used in the perturbation landscape."
205
+ title: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
206
+ children: ["These values describe how the selected ", obsLabel.singular, ' ', "perturbation is annotated in the atlas, including lineage, biological context, and summary scores used in the perturbation landscape."]
205
207
  }),
206
208
  placement: "right",
207
209
  arrow: true,
@@ -255,8 +257,8 @@ function ObsExplorer() {
255
257
  children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)("h5", {
256
258
  className: "fw-bold mb-2 d-flex align-items-center justify-content-between",
257
259
  children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_Tooltip.default, {
258
- title: /*#__PURE__*/(0, _jsxRuntime.jsx)(_jsxRuntime.Fragment, {
259
- children: "This table shows genes predicted to change expression in response to the selected perturbation. Results can be sorted and explored to identify affected pathways and regulatory programs."
260
+ title: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
261
+ children: ["This table shows ", obsLabel.plural, " predicted to change", ' ', valueLabel, " in response to the selected perturbation. Results can be sorted and explored to identify affected pathways and regulatory programs."]
260
262
  }),
261
263
  placement: "right",
262
264
  arrow: true,
@@ -51,7 +51,8 @@ function StandardView(_ref) {
51
51
  setShowSearch: setShowObsExplorer,
52
52
  setShowControls: setShowControls,
53
53
  isFullscreen: true,
54
- pointInteractionEnabled: true
54
+ pointInteractionEnabled: true,
55
+ isSearchObs: true
55
56
  })
56
57
  }), /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
57
58
  className: "cherita-app-sidebar p-3",
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.createScatterplotWorker = createScatterplotWorker;
7
+ const WORKER_CODE = "\nfunction computeBitmask(indices, length) {\n if (indices === null) return new Uint8Array(length).fill(1);\n const bitmask = new Uint8Array(length);\n for (const idx of indices) {\n bitmask[idx] = 1;\n }\n return bitmask;\n}\n\nself.onmessage = ({ data }) => {\n // compute and transfer only updated data\n const msg = {};\n const transfer = [];\n\n if (data.positions) {\n const positions = new Float32Array(data.positions.flat());\n msg.positions = positions;\n msg.count = data.positions.length;\n transfer.push(positions.buffer);\n }\n\n if (data.values) {\n const values = new Float32Array(data.values);\n msg.values = values;\n transfer.push(values.buffer);\n }\n\n if (data.obsIndices !== undefined && !!data.length) {\n const bitmask = computeBitmask(data.obsIndices, data.length);\n msg.indexEnabledBitmask = bitmask;\n transfer.push(bitmask.buffer);\n }\n\n self.postMessage(msg, transfer);\n};\n";
8
+ function createScatterplotWorker() {
9
+ const blob = new Blob([WORKER_CODE], {
10
+ type: 'application/javascript'
11
+ });
12
+ const url = URL.createObjectURL(blob);
13
+ const worker = new Worker(url);
14
+ URL.revokeObjectURL(url);
15
+ return worker;
16
+ }
@@ -7,7 +7,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
7
7
  import _ from 'lodash';
8
8
  import { Button } from 'react-bootstrap';
9
9
  import Plot from 'react-plotly.js';
10
- import { PLOTLY_MODEBAR_BUTTONS } from '../../constants/constants';
10
+ import { PLOT_TYPES, PLOTLY_MODEBAR_BUTTONS } from '../../constants/constants';
11
11
  import { useDataset } from '../../context/DatasetContext';
12
12
  import { useFilteredData } from '../../context/FilterContext';
13
13
  import { useSettings, useSettingsDispatch } from '../../context/SettingsContext';
@@ -23,7 +23,6 @@ export function Dotplot(_ref) {
23
23
  setShowCategories,
24
24
  setShowSearch,
25
25
  setShowControls,
26
- plotType,
27
26
  setPlotType,
28
27
  isFullscreen = false
29
28
  } = _ref;
@@ -153,7 +152,7 @@ export function Dotplot(_ref) {
153
152
  return /*#__PURE__*/_jsx(PlotAlert, {
154
153
  variant: "info",
155
154
  heading: "Set up your dotplot",
156
- plotType: plotType,
155
+ plotType: PLOT_TYPES.DOTPLOT,
157
156
  setPlotType: setPlotType,
158
157
  children: /*#__PURE__*/_jsxs("p", {
159
158
  className: "p-0 m-0",
@@ -161,8 +160,8 @@ export function Dotplot(_ref) {
161
160
  variant: "link",
162
161
  className: "border-0 p-0 align-baseline",
163
162
  onClick: setShowSearch,
164
- children: "features"
165
- }) : 'features', ' ', "to display their expression across groups, then choose a", ' ', showCategoriesBtn ? /*#__PURE__*/_jsx(Button, {
163
+ children: dataset.varLabel.plural
164
+ }) : dataset.varLabel.plural, ' ', "to display their ", dataset.valueLabel, " across groups, then choose a", ' ', showCategoriesBtn ? /*#__PURE__*/_jsx(Button, {
166
165
  variant: "link",
167
166
  className: "border-0 p-0 align-baseline",
168
167
  onClick: setShowCategories,
@@ -174,7 +173,7 @@ export function Dotplot(_ref) {
174
173
  return /*#__PURE__*/_jsx(PlotAlert, {
175
174
  variant: "danger",
176
175
  heading: "Error displaying the dotplot",
177
- plotType: plotType,
176
+ plotType: PLOT_TYPES.DOTPLOT,
178
177
  setPlotType: setPlotType,
179
178
  children: serverError.message || 'An unexpected error occurred while generating the plot.'
180
179
  });
@@ -4,13 +4,16 @@ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object
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
6
  import { useEffect, useState } from 'react';
7
+ import _ from 'lodash';
7
8
  import { Button, Form, InputGroup } from 'react-bootstrap';
9
+ import { useDataset } from '../../context/DatasetContext';
8
10
  import { useSettings, useSettingsDispatch } from '../../context/SettingsContext';
9
11
  import { ColorscaleSelect, ScaleSelect } from '../controls/Controls';
10
12
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
11
13
  export function DotplotControls() {
12
14
  const settings = useSettings();
13
15
  const dispatch = useSettingsDispatch();
16
+ const dataset = useDataset();
14
17
  const [controls, setControls] = useState({
15
18
  expressionCutoff: settings.controls.expressionCutoff,
16
19
  colorAxis: {
@@ -91,8 +94,8 @@ export function DotplotControls() {
91
94
  plot: "dotplot"
92
95
  }), /*#__PURE__*/_jsxs(Form.Group, {
93
96
  className: "mb-2",
94
- children: [/*#__PURE__*/_jsx(Form.Label, {
95
- children: "Expression Cutoff"
97
+ children: [/*#__PURE__*/_jsxs(Form.Label, {
98
+ children: [_.capitalize(dataset.valueLabel), " Cutoff"]
96
99
  }), /*#__PURE__*/_jsxs(InputGroup, {
97
100
  children: [/*#__PURE__*/_jsx(Form.Control, {
98
101
  size: "sm",
@@ -119,7 +122,7 @@ export function DotplotControls() {
119
122
  children: /*#__PURE__*/_jsx(Form.Check, {
120
123
  type: "switch",
121
124
  id: "meanOnlyExpressed",
122
- label: "Average only above cutoff",
125
+ label: "Average only above ".concat(dataset.valueLabel, " cutoff"),
123
126
  checked: settings.controls.meanOnlyExpressed,
124
127
  onChange: () => {
125
128
  dispatch({
@@ -7,7 +7,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
7
7
  import _ from 'lodash';
8
8
  import { Button } from 'react-bootstrap';
9
9
  import Plot from 'react-plotly.js';
10
- import { PLOTLY_MODEBAR_BUTTONS } from '../../constants/constants';
10
+ import { PLOT_TYPES, PLOTLY_MODEBAR_BUTTONS } from '../../constants/constants';
11
11
  import { useDataset } from '../../context/DatasetContext';
12
12
  import { useFilteredData } from '../../context/FilterContext';
13
13
  import { useSettings } from '../../context/SettingsContext';
@@ -23,7 +23,6 @@ export function Heatmap(_ref) {
23
23
  setShowCategories,
24
24
  setShowSearch,
25
25
  setShowControls,
26
- plotType,
27
26
  setPlotType,
28
27
  isFullscreen = false
29
28
  } = _ref;
@@ -127,7 +126,7 @@ export function Heatmap(_ref) {
127
126
  return /*#__PURE__*/_jsx(PlotAlert, {
128
127
  variant: "info",
129
128
  heading: "Set up your heatmap",
130
- plotType: plotType,
129
+ plotType: PLOT_TYPES.HEATMAP,
131
130
  setPlotType: setPlotType,
132
131
  children: /*#__PURE__*/_jsxs("p", {
133
132
  className: "p-0 m-0",
@@ -135,8 +134,8 @@ export function Heatmap(_ref) {
135
134
  variant: "link",
136
135
  className: "border-0 p-0 align-baseline",
137
136
  onClick: setShowSearch,
138
- children: "features"
139
- }) : 'features', ' ', "to display their expression, then choose a", ' ', showCategoriesBtn ? /*#__PURE__*/_jsx(Button, {
137
+ children: dataset.varLabel.plural
138
+ }) : dataset.varLabel.plural, ' ', "to display their ", dataset.valueLabel, ", then choose a", ' ', showCategoriesBtn ? /*#__PURE__*/_jsx(Button, {
140
139
  variant: "link",
141
140
  className: "border-0 p-0 align-baseline",
142
141
  onClick: setShowCategories,
@@ -148,7 +147,7 @@ export function Heatmap(_ref) {
148
147
  return /*#__PURE__*/_jsx(PlotAlert, {
149
148
  variant: "danger",
150
149
  heading: "Error displaying the heatmap",
151
- plotType: plotType,
150
+ plotType: PLOT_TYPES.HEATMAP,
152
151
  setPlotType: setPlotType,
153
152
  children: serverError.message || 'An unexpected error occurred while generating the plot.'
154
153
  });
@@ -14,8 +14,8 @@ export default function HeatmapIcon(_ref) {
14
14
  gap = 1
15
15
  } = _ref,
16
16
  props = _objectWithoutProperties(_ref, _excluded);
17
- const rows = 6; // genes
18
- const cols = 8; // cells
17
+ const rows = 6; // features
18
+ const cols = 8; // observations
19
19
 
20
20
  // Example expression pattern for visual clusters
21
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]];
@@ -7,7 +7,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
7
7
  import _ from 'lodash';
8
8
  import { Button } from 'react-bootstrap';
9
9
  import Plot from 'react-plotly.js';
10
- import { PLOTLY_MODEBAR_BUTTONS } from '../../constants/constants';
10
+ import { PLOT_TYPES, PLOTLY_MODEBAR_BUTTONS } from '../../constants/constants';
11
11
  import { useDataset } from '../../context/DatasetContext';
12
12
  import { useFilteredData } from '../../context/FilterContext';
13
13
  import { useSettings } from '../../context/SettingsContext';
@@ -23,7 +23,6 @@ export function Matrixplot(_ref) {
23
23
  setShowCategories,
24
24
  setShowSearch,
25
25
  setShowControls,
26
- plotType,
27
26
  setPlotType,
28
27
  isFullscreen = false
29
28
  } = _ref;
@@ -128,7 +127,7 @@ export function Matrixplot(_ref) {
128
127
  return /*#__PURE__*/_jsx(PlotAlert, {
129
128
  variant: "info",
130
129
  heading: "Set up your matrix plot",
131
- plotType: plotType,
130
+ plotType: PLOT_TYPES.MATRIXPLOT,
132
131
  setPlotType: setPlotType,
133
132
  children: /*#__PURE__*/_jsxs("p", {
134
133
  className: "p-0 m-0",
@@ -141,15 +140,15 @@ export function Matrixplot(_ref) {
141
140
  variant: "link",
142
141
  className: "border-0 p-0 align-baseline",
143
142
  onClick: setShowSearch,
144
- children: "features"
145
- }) : 'features', ' ', "to display the matrix plot."]
143
+ children: dataset.varLabel.plural
144
+ }) : dataset.varLabel.plural, ' ', "to display the matrix plot."]
146
145
  })
147
146
  });
148
147
  } else {
149
148
  return /*#__PURE__*/_jsx(PlotAlert, {
150
149
  variant: "danger",
151
150
  heading: "Error displaying the matrix plot",
152
- plotType: plotType,
151
+ plotType: PLOT_TYPES.MATRIXPLOT,
153
152
  setPlotType: setPlotType,
154
153
  children: serverError.message || 'An unexpected error occurred while generating the plot.'
155
154
  });
@@ -158,7 +158,10 @@ function CategoricalItem(_ref2) {
158
158
  } = useDataset();
159
159
  const {
160
160
  getColor
161
- } = useColor();
161
+ } = useColor({
162
+ isCategorical: true,
163
+ colorscale: useUnsColors ? colors : null
164
+ });
162
165
  return /*#__PURE__*/_jsx("div", {
163
166
  className: "virtualized-list-wrapper ps-1",
164
167
  children: /*#__PURE__*/_jsx(ListGroup.Item, {
@@ -253,17 +256,14 @@ function CategoricalItem(_ref2) {
253
256
  y: "0",
254
257
  width: "10",
255
258
  height: "10",
256
- fill: "rgb(".concat(getColor(_objectSpread({
257
- value: (code - min) / (max - min),
258
- categorical: true,
259
+ fill: "rgb(".concat(getColor({
260
+ value: (code - min) / Math.max(max - min, 1e-6),
259
261
  grayOut: isOmitted,
260
262
  grayParams: {
261
263
  alpha: 1
262
264
  },
263
265
  colorEncoding: 'obs'
264
- }, useUnsColors ? {
265
- colorscale: colors
266
- } : {})), ")")
266
+ }), ")")
267
267
  })
268
268
  })
269
269
  }) : null]
@@ -10,6 +10,7 @@ function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i
10
10
  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; }
11
11
  import Offcanvas from 'react-bootstrap/Offcanvas';
12
12
  import { SELECTION_MODES } from '../../constants/constants';
13
+ import { useDataset } from '../../context/DatasetContext';
13
14
  import { ObsExplorer } from '../../views/PerturbationMap/ObsExplorer';
14
15
  import { ObsColsList } from '../obs-list/ObsList';
15
16
  import { ObsmKeysList } from '../obsm-list/ObsmList';
@@ -61,14 +62,15 @@ export function OffcanvasVars(_ref3) {
61
62
  handleClose,
62
63
  mode = SELECTION_MODES.MULTIPLE
63
64
  } = _ref3;
65
+ const dataset = useDataset();
64
66
  return /*#__PURE__*/_jsxs(Offcanvas, {
65
67
  show: show,
66
68
  onHide: handleClose,
67
69
  className: "offcanvas-vars",
68
70
  children: [/*#__PURE__*/_jsx(Offcanvas.Header, {
69
71
  closeButton: true,
70
- children: /*#__PURE__*/_jsx(Offcanvas.Title, {
71
- children: "Features"
72
+ children: /*#__PURE__*/_jsxs(Offcanvas.Title, {
73
+ children: ["Search for ", dataset.varLabel.plural]
72
74
  })
73
75
  }), /*#__PURE__*/_jsx(Offcanvas.Body, {
74
76
  children: /*#__PURE__*/_jsxs("div", {
@@ -111,13 +113,14 @@ export function OffcanvasObsExplorer(_ref5) {
111
113
  handleClose
112
114
  } = _ref5,
113
115
  props = _objectWithoutProperties(_ref5, _excluded3);
116
+ const dataset = useDataset();
114
117
  return /*#__PURE__*/_jsxs(Offcanvas, {
115
118
  show: show,
116
119
  onHide: handleClose,
117
120
  children: [/*#__PURE__*/_jsx(Offcanvas.Header, {
118
121
  closeButton: true,
119
- children: /*#__PURE__*/_jsx(Offcanvas.Title, {
120
- children: "Gene Perturbations"
122
+ children: /*#__PURE__*/_jsxs(Offcanvas.Title, {
123
+ children: ["Search for ", dataset.obsLabel.plural]
121
124
  })
122
125
  }), /*#__PURE__*/_jsx(Offcanvas.Body, {
123
126
  className: "p-1",
@@ -5,6 +5,7 @@ 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 { useState } from 'react';
7
7
  import { PLOT_TYPES } from '../../constants/constants';
8
+ import { useDataset } from '../../context/DatasetContext';
8
9
  import { StyledTooltip } from '../../utils/StyledTooltip';
9
10
  import DotPlotIcon from '../icons/DotPlotIcon';
10
11
  import HeatmapIcon from '../icons/HeatmapIcon';
@@ -16,33 +17,67 @@ const plotTypes = [{
16
17
  type: PLOT_TYPES.SCATTERPLOT,
17
18
  icon: ScatterplotIcon,
18
19
  name: 'Scatterplot',
19
- description: 'Displays cells in 2D based on dimensionality reduction.'
20
+ description: _ref => {
21
+ let {
22
+ obsLabel
23
+ } = _ref;
24
+ return "Displays ".concat(obsLabel.plural, " in 2D based on dimensionality reduction.");
25
+ }
20
26
  }, {
21
27
  type: PLOT_TYPES.MATRIXPLOT,
22
28
  icon: MatrixPlotIcon,
23
29
  name: 'Matrix Plot',
24
- description: 'Shows expression values of genes across categories.'
30
+ description: _ref2 => {
31
+ let {
32
+ varLabel,
33
+ valueLabel
34
+ } = _ref2;
35
+ return "Shows ".concat(valueLabel, " values of ").concat(varLabel.plural, " across categories.");
36
+ }
25
37
  }, {
26
38
  type: PLOT_TYPES.DOTPLOT,
27
39
  icon: DotPlotIcon,
28
40
  name: 'Dot Plot',
29
- description: 'Shows proportion and expression of genes across groups.'
41
+ description: _ref3 => {
42
+ let {
43
+ varLabel,
44
+ valueLabel
45
+ } = _ref3;
46
+ return "Shows proportion and ".concat(valueLabel, " of ").concat(varLabel.plural, " across groups.");
47
+ }
30
48
  }, {
31
49
  type: PLOT_TYPES.HEATMAP,
32
50
  icon: HeatmapIcon,
33
51
  name: 'Heatmap',
34
- description: 'Visualises gene expression or feature activity as a colour-coded matrix.'
52
+ description: _ref4 => {
53
+ let {
54
+ varLabel,
55
+ valueLabel
56
+ } = _ref4;
57
+ return "Visualises ".concat(valueLabel, " of ").concat(varLabel.plural, " as a colour-coded matrix.");
58
+ }
35
59
  }, {
36
60
  type: PLOT_TYPES.VIOLINPLOT,
37
61
  icon: ViolinPlotIcon,
38
62
  name: 'Violin Plot',
39
- description: 'Displays distribution of gene expression across categories.'
63
+ description: _ref5 => {
64
+ let {
65
+ obsLabel,
66
+ valueLabel
67
+ } = _ref5;
68
+ return "Displays distribution of ".concat(valueLabel, " across ").concat(obsLabel.plural, ".");
69
+ }
40
70
  }];
41
- export function PlotTypeSelector(_ref) {
71
+ export function PlotTypeSelector(_ref6) {
42
72
  let {
43
73
  currentType,
44
74
  onChange
45
- } = _ref;
75
+ } = _ref6;
76
+ const {
77
+ obsLabel,
78
+ varLabel,
79
+ valueLabel
80
+ } = useDataset();
46
81
  const [hoveredMap, setHoveredMap] = useState({});
47
82
  const handleMouseEnter = type => setHoveredMap(prev => _objectSpread(_objectSpread({}, prev), {}, {
48
83
  [type]: true
@@ -52,13 +87,13 @@ export function PlotTypeSelector(_ref) {
52
87
  }));
53
88
  return /*#__PURE__*/_jsx("div", {
54
89
  className: "d-flex gap-2 justify-content-between",
55
- children: plotTypes.map(_ref2 => {
90
+ children: plotTypes.map(_ref7 => {
56
91
  let {
57
92
  type,
58
93
  icon: Icon,
59
94
  name,
60
95
  description
61
- } = _ref2;
96
+ } = _ref7;
62
97
  const isActive = currentType === type;
63
98
  const hovered = hoveredMap[type] || false;
64
99
  const colour = isActive ? '#005a86' : hovered ? '#0071a7' : '#000';
@@ -66,7 +101,11 @@ export function PlotTypeSelector(_ref) {
66
101
  title: /*#__PURE__*/_jsxs(_Fragment, {
67
102
  children: [/*#__PURE__*/_jsx("strong", {
68
103
  children: name
69
- }), /*#__PURE__*/_jsx("br", {}), description]
104
+ }), /*#__PURE__*/_jsx("br", {}), description({
105
+ obsLabel,
106
+ varLabel,
107
+ valueLabel
108
+ })]
70
109
  }),
71
110
  placement: "bottom",
72
111
  slotProps: {