@haniffalab/cherita-react 0.2.0-dev.2024-12-16.ab9c5057 → 0.2.0-dev.2024-12-16.f02cfae4

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.
@@ -14,7 +14,6 @@ var _layers2 = require("@nebula.gl/layers");
14
14
  var _turf = require("@turf/turf");
15
15
  var _lodash = _interopRequireDefault(require("lodash"));
16
16
  var _reactBootstrap = require("react-bootstrap");
17
- var _Legend = require("./Legend");
18
17
  var _SpatialControls = require("./SpatialControls");
19
18
  var _Toolbox = require("./Toolbox");
20
19
  var _constants = require("../../constants/constants");
@@ -22,6 +21,7 @@ var _DatasetContext = require("../../context/DatasetContext");
22
21
  var _FilterContext = require("../../context/FilterContext");
23
22
  var _colorHelper = require("../../helpers/color-helper");
24
23
  var _mapHelper = require("../../helpers/map-helper");
24
+ var _Legend = require("../../utils/Legend");
25
25
  var _LoadingIndicators = require("../../utils/LoadingIndicators");
26
26
  var _string = require("../../utils/string");
27
27
  var _zarrData = require("../../utils/zarrData");
@@ -300,8 +300,21 @@ function Scatterplot(_ref) {
300
300
  index
301
301
  } = _ref2;
302
302
  const grayOut = filteredIndices && !filteredIndices.has(index);
303
- return getColor((data.values[index] - min) / (max - min), isCategorical, grayOut);
303
+ return getColor({
304
+ value: (data.values[index] - min) / (max - min),
305
+ categorical: isCategorical,
306
+ grayOut: grayOut
307
+ });
304
308
  }, [data.values, filteredIndices, getColor, isCategorical, max, min]);
309
+
310
+ // @TODO: add support for pseudospatial hover to reflect in radius
311
+ const getRadius = (0, _react.useCallback)((_d, _ref3) => {
312
+ let {
313
+ index
314
+ } = _ref3;
315
+ const grayOut = filteredIndices && !filteredIndices.has(index);
316
+ return grayOut ? 1 : 3;
317
+ }, [filteredIndices]);
305
318
  const memoizedLayers = (0, _react.useMemo)(() => {
306
319
  return [new _layers.ScatterplotLayer({
307
320
  id: "cherita-layer-scatterplot",
@@ -311,21 +324,22 @@ function Scatterplot(_ref) {
311
324
  radiusMinPixels: 1,
312
325
  getPosition: d => d,
313
326
  getFillColor: getFillColor,
314
- getRadius: 1,
327
+ getRadius: getRadius,
315
328
  updateTriggers: {
316
- getFillColor: getFillColor
329
+ getFillColor: getFillColor,
330
+ getRadius: getRadius
317
331
  }
318
332
  }), new _layers2.EditableGeoJsonLayer({
319
333
  id: "cherita-layer-draw",
320
334
  data: features,
321
335
  mode: mode,
322
336
  selectedFeatureIndexes,
323
- onEdit: _ref3 => {
337
+ onEdit: _ref4 => {
324
338
  let {
325
339
  updatedData,
326
340
  editType,
327
341
  editContext
328
- } = _ref3;
342
+ } = _ref4;
329
343
  setFeatures(updatedData);
330
344
  let updatedSelectedFeatureIndexes = selectedFeatureIndexes;
331
345
  if (editType === "addFeature") {
@@ -349,7 +363,7 @@ function Scatterplot(_ref) {
349
363
  }
350
364
  }
351
365
  })];
352
- }, [data.positions, features, getFillColor, mode, radius, selectedFeatureIndexes]);
366
+ }, [data.positions, features, getFillColor, getRadius, mode, radius, selectedFeatureIndexes]);
353
367
  const layers = (0, _react.useDeferredValue)(mode === _editModes.ViewMode ? memoizedLayers.reverse() : memoizedLayers); // draw scatterplot on top of polygons when in ViewMode
354
368
 
355
369
  (0, _react.useEffect)(() => {
@@ -374,11 +388,11 @@ function Scatterplot(_ref) {
374
388
  return `${o.name}: ${o.codesMap[v]}`;
375
389
  }
376
390
  };
377
- const getTooltip = _ref4 => {
391
+ const getTooltip = _ref5 => {
378
392
  let {
379
393
  object,
380
394
  index
381
- } = _ref4;
395
+ } = _ref5;
382
396
  if (!object) return;
383
397
  const text = [];
384
398
  if (dataset.colorEncoding === _constants.COLOR_ENCODINGS.OBS && dataset.selectedObs && !_lodash.default.some(dataset.labelObs, {
@@ -396,70 +410,82 @@ function Scatterplot(_ref) {
396
410
  }));
397
411
  }
398
412
  if (!text.length) return;
413
+ const grayOut = filteredIndices && !filteredIndices.has(index);
399
414
  return {
400
- text: text.length ? _lodash.default.compact(text).join("\n") : null
415
+ text: text.length ? _lodash.default.compact(text).join("\n") : null,
416
+ className: grayOut ? "tooltip-grayout" : "deck-tooltip",
417
+ style: !grayOut ? {
418
+ "border-left": `3px solid ${(0, _colorHelper.rgbToHex)(getFillColor(null, {
419
+ index
420
+ }))}`
421
+ } : {
422
+ "border-left": "none"
423
+ }
401
424
  };
402
425
  };
403
426
  const isPending = (isRendering || xData.isPending || obsmData.isPending) && !obsmData.isPending;
404
427
  const error = dataset.selectedObsm && obsmData.serverError?.length || dataset.colorEncoding === _constants.COLOR_ENCODINGS.VAR && xData.serverError?.length || dataset.colorEncoding === _constants.COLOR_ENCODINGS.OBS && obsData.serverError?.length || dataset.labelObs.lengh && labelObsData.serverError?.length;
405
- return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
406
- className: "cherita-scatterplot",
407
- children: [obsmData.isPending && /*#__PURE__*/(0, _jsxRuntime.jsx)(_LoadingIndicators.LoadingSpinner, {
408
- disableShrink: true
409
- }), isPending && /*#__PURE__*/(0, _jsxRuntime.jsx)(_LoadingIndicators.LoadingLinear, {}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_react2.DeckGL, {
410
- viewState: viewState,
411
- onViewStateChange: e => setViewState(e.viewState),
412
- controller: {
413
- doubleClickZoom: mode === _editModes.ViewMode
414
- },
415
- layers: layers,
416
- onClick: onLayerClick,
417
- getTooltip: getTooltip,
418
- onAfterRender: () => {
419
- setIsRendering(false);
420
- },
421
- useDevicePixels: false,
422
- getCursor: _ref5 => {
423
- let {
424
- isDragging
425
- } = _ref5;
426
- return mode !== _editModes.ViewMode ? "crosshair" : isDragging ? "grabbing" : "grab";
427
- },
428
- ref: deckRef
429
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_SpatialControls.SpatialControls, {
430
- mode: mode,
431
- setMode: setMode,
432
- features: features,
433
- setFeatures: setFeatures,
434
- selectedFeatureIndexes: selectedFeatureIndexes,
435
- resetBounds: () => setViewState(getBounds()),
436
- increaseZoom: () => setViewState(v => ({
437
- ...v,
438
- zoom: v.zoom + 1
439
- })),
440
- decreaseZoom: () => setViewState(v => ({
441
- ...v,
442
- zoom: v.zoom - 1
443
- }))
444
- }), /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
445
- className: "cherita-spatial-footer",
446
- children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
447
- className: "cherita-toolbox-footer",
448
- children: [error && !isPending && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactBootstrap.Alert, {
449
- variant: "danger",
450
- children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactFontawesome.FontAwesomeIcon, {
451
- icon: _freeSolidSvgIcons.faTriangleExclamation
452
- }), "\xA0Error loading data"]
453
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_Toolbox.Toolbox, {
454
- mode: dataset.colorEncoding === _constants.COLOR_ENCODINGS.VAR ? dataset.selectedVar.name : dataset.colorEncoding === _constants.COLOR_ENCODINGS.OBS ? dataset.selectedObs.name : null,
455
- obsLength: parseInt(obsmData.data?.length),
456
- slicedLength: parseInt(slicedLength)
428
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
429
+ className: "cherita-container-scatterplot",
430
+ children: /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
431
+ className: "cherita-scatterplot",
432
+ children: [obsmData.isPending && /*#__PURE__*/(0, _jsxRuntime.jsx)(_LoadingIndicators.LoadingSpinner, {
433
+ disableShrink: true
434
+ }), isPending && /*#__PURE__*/(0, _jsxRuntime.jsx)(_LoadingIndicators.LoadingLinear, {}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_react2.DeckGL, {
435
+ viewState: viewState,
436
+ onViewStateChange: e => setViewState(e.viewState),
437
+ controller: {
438
+ doubleClickZoom: mode === _editModes.ViewMode
439
+ },
440
+ layers: layers,
441
+ onClick: onLayerClick,
442
+ getTooltip: getTooltip,
443
+ onAfterRender: () => {
444
+ setIsRendering(false);
445
+ },
446
+ useDevicePixels: false,
447
+ getCursor: _ref6 => {
448
+ let {
449
+ isDragging
450
+ } = _ref6;
451
+ return mode !== _editModes.ViewMode ? "crosshair" : isDragging ? "grabbing" : "grab";
452
+ },
453
+ ref: deckRef
454
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_SpatialControls.SpatialControls, {
455
+ mode: mode,
456
+ setMode: setMode,
457
+ features: features,
458
+ setFeatures: setFeatures,
459
+ selectedFeatureIndexes: selectedFeatureIndexes,
460
+ resetBounds: () => setViewState(getBounds()),
461
+ increaseZoom: () => setViewState(v => ({
462
+ ...v,
463
+ zoom: v.zoom + 1
464
+ })),
465
+ decreaseZoom: () => setViewState(v => ({
466
+ ...v,
467
+ zoom: v.zoom - 1
468
+ }))
469
+ }), /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
470
+ className: "cherita-spatial-footer",
471
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
472
+ className: "cherita-toolbox-footer",
473
+ children: [error && !isPending && /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactBootstrap.Alert, {
474
+ variant: "danger",
475
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactFontawesome.FontAwesomeIcon, {
476
+ icon: _freeSolidSvgIcons.faTriangleExclamation
477
+ }), "\xA0Error loading data"]
478
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_Toolbox.Toolbox, {
479
+ mode: dataset.colorEncoding === _constants.COLOR_ENCODINGS.VAR ? dataset.selectedVar.name : dataset.colorEncoding === _constants.COLOR_ENCODINGS.OBS ? dataset.selectedObs.name : null,
480
+ obsLength: parseInt(obsmData.data?.length),
481
+ slicedLength: parseInt(slicedLength)
482
+ })]
483
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_Legend.Legend, {
484
+ isCategorical: isCategorical,
485
+ min: min,
486
+ max: max
457
487
  })]
458
- }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_Legend.Legend, {
459
- isCategorical: isCategorical,
460
- min: min,
461
- max: max
462
488
  })]
463
- })]
489
+ })
464
490
  });
465
491
  }
@@ -88,10 +88,22 @@ function VarHistogram(_ref) {
88
88
  });
89
89
  }
90
90
  function VarDiseaseInfoItem(item) {
91
+ const dispatch = (0, _DatasetContext.useDatasetDispatch)();
91
92
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactBootstrap.ListGroup.Item, {
92
93
  className: "feature-disease-info",
93
94
  children: /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
94
- children: [item.disease_name, " ", /*#__PURE__*/(0, _jsxRuntime.jsx)("br", {}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactBootstrap.Table, {
95
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("button", {
96
+ type: "button",
97
+ className: "btn btn-link",
98
+ onClick: () => {
99
+ dispatch({
100
+ type: "select.disease",
101
+ id: item.disease_id,
102
+ name: item.disease_name
103
+ });
104
+ },
105
+ children: item.disease_name
106
+ }), /*#__PURE__*/(0, _jsxRuntime.jsx)("br", {}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactBootstrap.Table, {
95
107
  striped: true,
96
108
  children: /*#__PURE__*/(0, _jsxRuntime.jsxs)("tbody", {
97
109
  children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)("tr", {
@@ -120,7 +132,7 @@ function VarDiseaseInfoItem(item) {
120
132
  })
121
133
  })]
122
134
  })
123
- });
135
+ }, item.disease_name);
124
136
  }
125
137
  function VarDiseaseInfo(_ref3) {
126
138
  let {
@@ -131,8 +143,8 @@ function VarDiseaseInfo(_ref3) {
131
143
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_VirtualizedList.VirtualizedList, {
132
144
  getDataAtIndex: index => data[index],
133
145
  count: data.length,
134
- estimateSize: 70,
135
- maxHeight: "40vh",
146
+ estimateSize: 140,
147
+ maxHeight: "100%",
136
148
  ItemComponent: VarDiseaseInfoItem
137
149
  })
138
150
  })
@@ -207,7 +219,7 @@ function SingleSelectionItem(_ref4) {
207
219
  }), hasDiseaseInfo && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactBootstrap.Collapse, {
208
220
  in: openInfo,
209
221
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)("div", {
210
- className: "mt-2",
222
+ className: "mt-2 var-disease-info-collapse",
211
223
  children: /*#__PURE__*/(0, _jsxRuntime.jsx)(VarDiseaseInfo, {
212
224
  data: fetchedData
213
225
  })
@@ -18,6 +18,7 @@ var _jsxRuntime = require("react/jsx-runtime");
18
18
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
19
19
  function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
20
20
  function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
21
+ // @TODO: add button to score genes and plot
21
22
  const addVarToSet = (dispatch, set, v) => {
22
23
  dispatch({
23
24
  type: "add.varSet.var",
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.VIOLIN_MODES = exports.VIOLINPLOT_SCALES = exports.VAR_SORT_ORDER = exports.VAR_SORT = exports.UNSELECTED_POLYGON_FILLCOLOR = exports.SELECTION_MODES = exports.SELECTED_POLYGON_FILLCOLOR = exports.OBS_TYPES = exports.MATRIXPLOT_SCALES = exports.LOCAL_STORAGE_KEY = exports.DOTPLOT_SCALES = exports.COLOR_ENCODINGS = void 0;
6
+ exports.VIOLIN_MODES = exports.VIOLINPLOT_SCALES = exports.VAR_SORT_ORDER = exports.VAR_SORT = exports.UNSELECTED_POLYGON_FILLCOLOR = exports.SELECTION_MODES = exports.SELECTED_POLYGON_FILLCOLOR = exports.PSEUDOSPATIAL_PLOT_TYPES = exports.PSEUDOSPATIAL_CATEGORICAL_MODES = exports.OBS_TYPES = exports.MATRIXPLOT_SCALES = exports.LOCAL_STORAGE_KEY = exports.DOTPLOT_SCALES = exports.COLOR_ENCODINGS = void 0;
7
7
  const LOCAL_STORAGE_KEY = exports.LOCAL_STORAGE_KEY = "CHERITA";
8
8
  const COLOR_ENCODINGS = exports.COLOR_ENCODINGS = {
9
9
  VAR: "var",
@@ -71,4 +71,20 @@ const VIOLINPLOT_SCALES = exports.VIOLINPLOT_SCALES = {
71
71
  value: "count",
72
72
  name: "Count"
73
73
  }
74
+ };
75
+ const PSEUDOSPATIAL_PLOT_TYPES = exports.PSEUDOSPATIAL_PLOT_TYPES = {
76
+ GENE: "gene",
77
+ CATEGORICAL: "categorical",
78
+ CONTINUOUS: "continuous",
79
+ MASKS: "masks"
80
+ };
81
+ const PSEUDOSPATIAL_CATEGORICAL_MODES = exports.PSEUDOSPATIAL_CATEGORICAL_MODES = {
82
+ ACROSS: {
83
+ value: "across",
84
+ name: "% across sections"
85
+ },
86
+ WITHIN: {
87
+ value: "within",
88
+ name: "% within section"
89
+ }
74
90
  };
@@ -95,6 +95,14 @@ const initialDataset = {
95
95
  sort: _constants.VAR_SORT.NONE,
96
96
  sortOrder: _constants.VAR_SORT_ORDER.ASC
97
97
  }
98
+ },
99
+ obsCols: null,
100
+ // @TODO: implement specifying groups/categories for dropdowns
101
+ imageUrl: null,
102
+ pseudospatial: {
103
+ maskSet: null,
104
+ maskValues: null,
105
+ categoricalMode: _constants.PSEUDOSPATIAL_CATEGORICAL_MODES.ACROSS.value
98
106
  }
99
107
  };
100
108
  const initializer = initialState => {
@@ -106,8 +114,8 @@ const initializer = initialState => {
106
114
  function DatasetProvider(_ref2) {
107
115
  let {
108
116
  dataset_url,
109
- dataset_params = null,
110
- children
117
+ children,
118
+ ...dataset_params
111
119
  } = _ref2;
112
120
  const [dataset, dispatch] = (0, _react.useReducer)(datasetReducer, _lodash.default.assign(initializer({
113
121
  url: dataset_url,
@@ -527,6 +535,36 @@ function datasetReducer(dataset, action) {
527
535
  }
528
536
  };
529
537
  }
538
+ case "set.pseudospatial.maskSet":
539
+ {
540
+ return {
541
+ ...dataset,
542
+ pseudospatial: {
543
+ ...dataset.pseudospatial,
544
+ maskSet: action.maskSet
545
+ }
546
+ };
547
+ }
548
+ case "set.pseudospatial.maskValues":
549
+ {
550
+ return {
551
+ ...dataset,
552
+ pseudospatial: {
553
+ ...dataset.pseudospatial,
554
+ maskValues: action.maskValues
555
+ }
556
+ };
557
+ }
558
+ case "set.pseudospatial.categoricalMode":
559
+ {
560
+ return {
561
+ ...dataset,
562
+ pseudospatial: {
563
+ ...dataset.pseudospatial,
564
+ categoricalMode: action.categoricalMode
565
+ }
566
+ };
567
+ }
530
568
  default:
531
569
  {
532
570
  throw Error("Unknown action: " + action.type);
@@ -12121,4 +12121,43 @@ textarea.form-control-lg {
12121
12121
  display: none;
12122
12122
  }
12123
12123
 
12124
+ .cherita-pseudospatial {
12125
+ width: 100%;
12126
+ }
12127
+
12128
+ .cherita-pseudospatial-plot {
12129
+ width: 100%;
12130
+ height: 100%;
12131
+ }
12132
+
12133
+ .cherita-pseudospatial-toolbar {
12134
+ display: flex;
12135
+ flex-direction: column;
12136
+ }
12137
+
12138
+ /* Add a bottom border to the last item in the Accordion */
12139
+ .accordion-flush .accordion-item:last-child {
12140
+ border-bottom: 1px solid #dee2e6; /* Adjust the color and width as needed */
12141
+ }
12142
+
12143
+ .var-disease-info-collapse {
12144
+ max-height: 40vh;
12145
+ overflow-y: auto;
12146
+ }
12147
+
12148
+ .cherita-scatterplot #deckgl-wrapper {
12149
+ z-index: 1 !important;
12150
+ }
12151
+
12152
+ .tooltip-grayout {
12153
+ color: #a0a7b4 !important;
12154
+ background-color: #3a424b !important;
12155
+ opacity: 0.8;
12156
+ z-index: 100 !important;
12157
+ }
12158
+
12159
+ .deck-tooltip {
12160
+ z-index: 100 !important;
12161
+ }
12162
+
12124
12163
  /*# sourceMappingURL=cherita.css.map */