@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
@@ -166,7 +166,7 @@ export function SettingsProvider(_ref2) {
166
166
 
167
167
  // If the buster is not set or does not match the current package version,
168
168
  // reset localSettings to avoid stale data
169
- if (!buster || buster !== "2.0.0") {
169
+ if (!buster || buster !== "2.1.0") {
170
170
  localSettings = {};
171
171
  }
172
172
  const initSettings = useRef(initializer({
@@ -191,7 +191,7 @@ export function SettingsProvider(_ref2) {
191
191
  if (canOverrideSettings && settings) {
192
192
  try {
193
193
  localStorage.setItem(DATASET_STORAGE_KEY, JSON.stringify(_objectSpread({
194
- buster: "2.0.0" || '0.0.0',
194
+ buster: "2.1.0" || '0.0.0',
195
195
  timestamp: Date.now()
196
196
  }, _.omit(settings, 'data'))));
197
197
  } catch (err) {
@@ -335,6 +335,31 @@ function settingsReducer(settings, action) {
335
335
  }));
336
336
  }
337
337
  }
338
+ case 'select.multivar.batch':
339
+ {
340
+ const newVars = [];
341
+ let newVarData = {};
342
+ _.forEach(action.vars, v => {
343
+ const inMultiVar = settings.selectedMultiVar.some(mv => mv.name === v.name);
344
+ if (!inMultiVar) {
345
+ const {
346
+ settings: varSettings,
347
+ data: varData
348
+ } = splitVar(v);
349
+ newVars.push(varSettings);
350
+ newVarData = _objectSpread(_objectSpread({}, newVarData), varData);
351
+ }
352
+ });
353
+ if (!newVars.length) {
354
+ return validateSettings(_objectSpread({}, settings));
355
+ }
356
+ return validateSettings(_objectSpread(_objectSpread({}, settings), {}, {
357
+ selectedMultiVar: [...settings.selectedMultiVar, ...newVars],
358
+ data: _objectSpread(_objectSpread({}, settings.data), {}, {
359
+ vars: _objectSpread(_objectSpread({}, settings.data.vars), newVarData)
360
+ })
361
+ }));
362
+ }
338
363
  case 'deselect.multivar':
339
364
  {
340
365
  return validateSettings(_objectSpread(_objectSpread({}, settings), {}, {
@@ -1,7 +1,7 @@
1
- import { useCallback } from 'react';
1
+ import { useCallback, useMemo } from 'react';
2
2
  import { COLORSCALES } from '../constants/colorscales';
3
+ import { GRAY, GRAY_MIX, GRAY_ALPHA } from '../constants/constants';
3
4
  import { useSettings } from '../context/SettingsContext';
4
- const GRAY = [214, 212, 212];
5
5
  const parseHexColor = color => {
6
6
  const r = parseInt(color === null || color === void 0 ? void 0 : color.substring(1, 3), 16);
7
7
  const g = parseInt(color === null || color === void 0 ? void 0 : color.substring(3, 5), 16);
@@ -33,21 +33,25 @@ export const rgbToHex = color => {
33
33
  const [r, g, b] = color || [0, 0, 0, 0];
34
34
  return '#' + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
35
35
  };
36
- export const useColor = () => {
36
+ export const useColor = _ref => {
37
+ let {
38
+ isCategorical = false,
39
+ colorscale = null
40
+ } = _ref;
37
41
  const settings = useSettings();
38
- const getColor = useCallback(_ref => {
42
+ const colormap = useMemo(() => {
43
+ return colorscale || COLORSCALES[isCategorical ? 'Accent' : settings.controls.colorScale];
44
+ }, [colorscale, isCategorical, settings.controls.colorScale]);
45
+ const getColor = useCallback(_ref2 => {
39
46
  let {
40
47
  value,
41
- categorical = false,
42
48
  grayOut = false,
43
49
  grayParams: {
44
- alpha = 0.75,
45
- gray = 0.95
50
+ alpha = GRAY_ALPHA,
51
+ gray = GRAY_MIX
46
52
  } = {},
47
- colorEncoding = settings.colorEncoding,
48
- colorscale = null
49
- } = _ref;
50
- const colormap = colorscale || COLORSCALES[categorical ? 'Accent' : settings.controls.colorScale];
53
+ colorEncoding = settings.colorEncoding
54
+ } = _ref2;
51
55
  if (colorEncoding) {
52
56
  if (grayOut) {
53
57
  // Mix color with gray manually instead of chroma.mix to get better performance with deck.gl
@@ -59,8 +63,9 @@ export const useColor = () => {
59
63
  } else {
60
64
  return null;
61
65
  }
62
- }, [settings.colorEncoding, settings.controls.colorScale]);
66
+ }, [settings.colorEncoding, colormap]);
63
67
  return {
68
+ colormap,
64
69
  getColor
65
70
  };
66
71
  };
package/dist/esm/index.js CHANGED
@@ -13,7 +13,6 @@ export { Pseudospatial } from './components/pseudospatial/Pseudospatial';
13
13
  export { Scatterplot } from './components/scatterplot/Scatterplot';
14
14
  export { ScatterplotControls } from './components/scatterplot/ScatterplotControls';
15
15
  export { SearchBar } from './components/search-bar/SearchBar';
16
- export { Toolbar } from './components/toolbar/Toolbar';
17
16
  export { VarNamesList } from './components/var-list/VarList';
18
17
  export { Violin } from './components/violin/Violin';
19
18
  export { ViolinControls } from './components/violin/ViolinControls';
@@ -18,13 +18,14 @@ export function Legend(_ref) {
18
18
  const settings = useSettings();
19
19
  const {
20
20
  getColor
21
- } = useColor();
21
+ } = useColor({
22
+ isCategorical,
23
+ colorscale
24
+ });
22
25
  const spanList = useMemo(() => {
23
26
  return _.range(100).map(i => {
24
27
  var color = rgbToHex(getColor({
25
- value: i / 100,
26
- categorical: isCategorical,
27
- colorscale: colorscale
28
+ value: i / 100
28
29
  }));
29
30
  return /*#__PURE__*/_jsx("span", {
30
31
  className: "grad-step",
@@ -33,7 +34,7 @@ export function Legend(_ref) {
33
34
  }
34
35
  }, i);
35
36
  });
36
- }, [colorscale, getColor, isCategorical]);
37
+ }, [getColor]);
37
38
  if (settings.colorEncoding && !isCategorical) {
38
39
  var _settings$selectedVar, _settings$selectedObs;
39
40
  return /*#__PURE__*/_jsx("div", {
@@ -8,8 +8,8 @@ import { useDebounce } from '@uidotdev/usehooks';
8
8
  import { parseError } from './errors';
9
9
  export async function fetchData(endpoint, params) {
10
10
  let signal = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
11
- let ms = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 300000;
12
- let apiUrl = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : null;
11
+ let apiUrl = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
12
+ let ms = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 300000;
13
13
  apiUrl = apiUrl || process.env.REACT_APP_API_URL;
14
14
  const controller = new AbortController();
15
15
  const timeout = setTimeout(() => {
@@ -103,7 +103,7 @@ export function StandardView(_ref) {
103
103
  default:
104
104
  return /*#__PURE__*/_jsx(Scatterplot, _objectSpread({}, commonProps));
105
105
  }
106
- }, [plotType]);
106
+ }, [plotType, props]);
107
107
  return /*#__PURE__*/_jsx("div", {
108
108
  className: "cherita-app",
109
109
  children: /*#__PURE__*/_jsxs(DatasetProvider, _objectSpread(_objectSpread({}, props), {}, {
@@ -142,7 +142,9 @@ export function ObsExplorer() {
142
142
  selectedObsIndex
143
143
  } = useSettings();
144
144
  const {
145
- obsExplorer = {}
145
+ obsExplorer = {},
146
+ obsLabel,
147
+ valueLabel
146
148
  } = useDataset();
147
149
  useParquet(); // initialize duckdb instance
148
150
 
@@ -153,9 +155,9 @@ export function ObsExplorer() {
153
155
  serverError
154
156
  } = useObsColsData(obsExplorer === null || obsExplorer === void 0 ? void 0 : obsExplorer.obsCols);
155
157
  if (selectedObsIndex == null) {
156
- return /*#__PURE__*/_jsx("div", {
158
+ return /*#__PURE__*/_jsxs("div", {
157
159
  className: "my-4 text-muted",
158
- children: "Select a point in the scatterplot to view details about the gene perturbation."
160
+ children: ["Select a point in the scatterplot or search for ", obsLabel.plural, " to view details about the ", obsLabel.singular, " perturbation."]
159
161
  });
160
162
  }
161
163
  if (isPending) {
@@ -177,8 +179,8 @@ export function ObsExplorer() {
177
179
  children: [/*#__PURE__*/_jsx("h2", {
178
180
  className: "fw-bold mb-2",
179
181
  children: /*#__PURE__*/_jsx(Tooltip, {
180
- title: /*#__PURE__*/_jsx(_Fragment, {
181
- children: "This panel shows metadata and predicted downstream effects for the selected gene perturbation across the atlas."
182
+ title: /*#__PURE__*/_jsxs(_Fragment, {
183
+ children: ["This panel shows metadata and predicted downstream effects for the selected ", obsLabel.singular, " perturbation across the atlas."]
182
184
  }),
183
185
  placement: "right",
184
186
  arrow: true,
@@ -193,8 +195,8 @@ export function ObsExplorer() {
193
195
  children: [/*#__PURE__*/_jsx("h5", {
194
196
  className: "fw-bold mb-2",
195
197
  children: /*#__PURE__*/_jsx(Tooltip, {
196
- title: /*#__PURE__*/_jsx(_Fragment, {
197
- 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."
198
+ title: /*#__PURE__*/_jsxs(_Fragment, {
199
+ 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."]
198
200
  }),
199
201
  placement: "right",
200
202
  arrow: true,
@@ -248,8 +250,8 @@ export function ObsExplorer() {
248
250
  children: [/*#__PURE__*/_jsxs("h5", {
249
251
  className: "fw-bold mb-2 d-flex align-items-center justify-content-between",
250
252
  children: [/*#__PURE__*/_jsx(Tooltip, {
251
- title: /*#__PURE__*/_jsx(_Fragment, {
252
- 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."
253
+ title: /*#__PURE__*/_jsxs(_Fragment, {
254
+ 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."]
253
255
  }),
254
256
  placement: "right",
255
257
  arrow: true,
@@ -45,7 +45,8 @@ export function StandardView(_ref) {
45
45
  setShowSearch: setShowObsExplorer,
46
46
  setShowControls: setShowControls,
47
47
  isFullscreen: true,
48
- pointInteractionEnabled: true
48
+ pointInteractionEnabled: true,
49
+ isSearchObs: true
49
50
  })
50
51
  }), /*#__PURE__*/_jsx("div", {
51
52
  className: "cherita-app-sidebar p-3",
@@ -0,0 +1,10 @@
1
+ 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";
2
+ export function createScatterplotWorker() {
3
+ const blob = new Blob([WORKER_CODE], {
4
+ type: 'application/javascript'
5
+ });
6
+ const url = URL.createObjectURL(blob);
7
+ const worker = new Worker(url);
8
+ URL.revokeObjectURL(url);
9
+ return worker;
10
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@haniffalab/cherita-react",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
4
4
  "author": "Haniffa Lab",
5
5
  "license": "MIT",
6
6
  "keywords": [
@@ -52,7 +52,7 @@
52
52
  "ndarray-unpack": "^1.0.0",
53
53
  "nebula.gl": "^1.0.4",
54
54
  "numbro": "^2.5.0",
55
- "plotly.js": "^2.23.2",
55
+ "plotly.js": "^3.4.0",
56
56
  "popper.js": "^1.16.1",
57
57
  "react-bootstrap": "^2.7.4",
58
58
  "react-plotly.js": "^2.6.0",
@@ -117,7 +117,10 @@
117
117
  "lint:js": "eslint 'src/**/*.{js,jsx}' --fix",
118
118
  "lint": "npm run lint:scss && npm run lint:js",
119
119
  "start-demo": "npm run dev --prefix sites/demo",
120
- "reinstall": "rm -rf node_modules package-lock.json && npm install"
120
+ "reinstall": "rm -rf node_modules package-lock.json && npm install",
121
+ "docs:start": "npm run start --prefix website",
122
+ "docs:build": "npm run build --prefix website",
123
+ "docs:serve": "npm run serve --prefix website"
121
124
  },
122
125
  "eslintConfig": {
123
126
  "extends": [