@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.
- package/dist/cjs/components/dotplot/Dotplot.js +4 -5
- package/dist/cjs/components/dotplot/DotplotControls.js +7 -3
- package/dist/cjs/components/heatmap/Heatmap.js +4 -5
- package/dist/cjs/components/icons/HeatmapIcon.js +2 -2
- package/dist/cjs/components/matrixplot/Matrixplot.js +4 -5
- package/dist/cjs/components/obs-list/ObsItem.js +7 -7
- package/dist/cjs/components/offcanvas/OffCanvas.js +7 -4
- package/dist/cjs/components/plot/PlotTypeSelector.js +49 -10
- package/dist/cjs/components/pseudospatial/Pseudospatial.js +8 -5
- package/dist/cjs/components/scatterplot/Scatterplot.js +134 -136
- package/dist/cjs/components/scatterplot/ScatterplotLayer.js +144 -0
- package/dist/cjs/components/scatterplot/SpatialControls.js +7 -4
- package/dist/cjs/components/scatterplot/Toolbox.js +8 -4
- package/dist/cjs/components/search-bar/SearchBar.js +51 -29
- package/dist/cjs/components/search-bar/SearchInfo.js +2 -2
- package/dist/cjs/components/search-bar/SearchResults.js +9 -6
- package/dist/cjs/components/toolbar/Toolbar.js +10 -65
- package/dist/cjs/components/var-list/VarItem.js +4 -6
- package/dist/cjs/components/var-list/VarList.js +17 -9
- package/dist/cjs/components/var-list/VarListToolbar.js +1 -1
- package/dist/cjs/components/var-list/VarSet.js +7 -5
- package/dist/cjs/components/violin/Violin.js +6 -7
- package/dist/cjs/constants/constants.js +6 -3
- package/dist/cjs/context/DatasetContext.js +11 -2
- package/dist/cjs/context/SettingsContext.js +27 -2
- package/dist/cjs/helpers/color-helper.js +17 -12
- package/dist/cjs/index.js +0 -7
- package/dist/cjs/utils/Legend.js +6 -5
- package/dist/cjs/utils/requests.js +2 -2
- package/dist/cjs/views/ObservationFeature/StandardView.js +1 -1
- package/dist/cjs/views/PerturbationMap/ObsExplorer.js +11 -9
- package/dist/cjs/views/PerturbationMap/StandardView.js +2 -1
- package/dist/cjs/workers/scatterplotData.js +16 -0
- package/dist/esm/components/dotplot/Dotplot.js +5 -6
- package/dist/esm/components/dotplot/DotplotControls.js +6 -3
- package/dist/esm/components/heatmap/Heatmap.js +5 -6
- package/dist/esm/components/icons/HeatmapIcon.js +2 -2
- package/dist/esm/components/matrixplot/Matrixplot.js +5 -6
- package/dist/esm/components/obs-list/ObsItem.js +7 -7
- package/dist/esm/components/offcanvas/OffCanvas.js +7 -4
- package/dist/esm/components/plot/PlotTypeSelector.js +49 -10
- package/dist/esm/components/pseudospatial/Pseudospatial.js +8 -5
- package/dist/esm/components/scatterplot/Scatterplot.js +132 -134
- package/dist/esm/components/scatterplot/ScatterplotLayer.js +137 -0
- package/dist/esm/components/scatterplot/SpatialControls.js +7 -4
- package/dist/esm/components/scatterplot/Toolbox.js +8 -4
- package/dist/esm/components/search-bar/SearchBar.js +52 -30
- package/dist/esm/components/search-bar/SearchInfo.js +2 -2
- package/dist/esm/components/search-bar/SearchResults.js +9 -6
- package/dist/esm/components/toolbar/Toolbar.js +9 -63
- package/dist/esm/components/var-list/VarItem.js +4 -6
- package/dist/esm/components/var-list/VarList.js +17 -9
- package/dist/esm/components/var-list/VarListToolbar.js +1 -1
- package/dist/esm/components/var-list/VarSet.js +7 -5
- package/dist/esm/components/violin/Violin.js +7 -8
- package/dist/esm/constants/constants.js +5 -2
- package/dist/esm/context/DatasetContext.js +11 -2
- package/dist/esm/context/SettingsContext.js +27 -2
- package/dist/esm/helpers/color-helper.js +17 -12
- package/dist/esm/index.js +0 -1
- package/dist/esm/utils/Legend.js +6 -5
- package/dist/esm/utils/requests.js +2 -2
- package/dist/esm/views/ObservationFeature/StandardView.js +1 -1
- package/dist/esm/views/PerturbationMap/ObsExplorer.js +11 -9
- package/dist/esm/views/PerturbationMap/StandardView.js +2 -1
- package/dist/esm/workers/scatterplotData.js +10 -0
- package/package.json +6 -3
|
@@ -6,14 +6,14 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports.Scatterplot = Scatterplot;
|
|
7
7
|
var _react = require("react");
|
|
8
8
|
var _core = require("@deck.gl/core");
|
|
9
|
-
var _layers = require("@deck.gl/layers");
|
|
10
9
|
var _react2 = require("@deck.gl/react");
|
|
11
10
|
var _freeSolidSvgIcons = require("@fortawesome/free-solid-svg-icons");
|
|
12
11
|
var _reactFontawesome = require("@fortawesome/react-fontawesome");
|
|
13
12
|
var _editModes = require("@nebula.gl/edit-modes");
|
|
14
|
-
var
|
|
13
|
+
var _layers = require("@nebula.gl/layers");
|
|
15
14
|
var _lodash = _interopRequireDefault(require("lodash"));
|
|
16
15
|
var _reactBootstrap = require("react-bootstrap");
|
|
16
|
+
var _ScatterplotLayer = require("./ScatterplotLayer");
|
|
17
17
|
var _SpatialControls = require("./SpatialControls");
|
|
18
18
|
var _Toolbox = require("./Toolbox");
|
|
19
19
|
var _constants = require("../../constants/constants");
|
|
@@ -29,6 +29,7 @@ var _Resolver = require("../../utils/Resolver");
|
|
|
29
29
|
var _string = require("../../utils/string");
|
|
30
30
|
var _usePlotVisibility = _interopRequireDefault(require("../../utils/usePlotVisibility"));
|
|
31
31
|
var _zarrData = require("../../utils/zarrData");
|
|
32
|
+
var _scatterplotData = require("../../workers/scatterplotData.js");
|
|
32
33
|
var _PlotAlert = require("../plot/PlotAlert");
|
|
33
34
|
var _jsxRuntime = require("react/jsx-runtime");
|
|
34
35
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
@@ -55,15 +56,15 @@ const getRadiusScale = bounds => {
|
|
|
55
56
|
return rs;
|
|
56
57
|
};
|
|
57
58
|
function Scatterplot(_ref) {
|
|
58
|
-
var _features$features2, _obsmData$serverError, _labelObsData$serverE, _settings$selectedVar, _data$
|
|
59
|
+
var _data$positions5, _features$features2, _obsmData$serverError, _labelObsData$serverE, _settings$selectedVar, _data$positions6;
|
|
59
60
|
let {
|
|
61
|
+
pointInteractionEnabled = false,
|
|
62
|
+
showSpatialControls = true,
|
|
60
63
|
setShowCategories,
|
|
61
64
|
setShowSearch,
|
|
62
|
-
plotType,
|
|
63
65
|
setPlotType,
|
|
64
66
|
isFullscreen = false,
|
|
65
|
-
|
|
66
|
-
showSpatialControls = true
|
|
67
|
+
isSearchObs
|
|
67
68
|
} = _ref;
|
|
68
69
|
const {
|
|
69
70
|
useUnsColors
|
|
@@ -76,9 +77,6 @@ function Scatterplot(_ref) {
|
|
|
76
77
|
slicedLength
|
|
77
78
|
} = (0, _FilterContext.useFilteredData)();
|
|
78
79
|
const dispatch = (0, _SettingsContext.useSettingsDispatch)();
|
|
79
|
-
const {
|
|
80
|
-
getColor
|
|
81
|
-
} = (0, _colorHelper.useColor)();
|
|
82
80
|
const deckRef = (0, _react.useRef)(null);
|
|
83
81
|
const [viewport, setViewport] = (0, _react.useState)(null);
|
|
84
82
|
const [viewState, setViewState] = (0, _react.useState)(INITIAL_VIEW_STATE);
|
|
@@ -94,8 +92,6 @@ function Scatterplot(_ref) {
|
|
|
94
92
|
const radiusScale = settings.controls.radiusScale[settings.selectedObsm] || 1;
|
|
95
93
|
const selectedObs = (0, _Resolver.useSelectedObs)();
|
|
96
94
|
const selectedObsIndex = settings.selectedObsIndex;
|
|
97
|
-
const [hoveredIndex, setHoveredIndex] = (0, _react.useState)(null);
|
|
98
|
-
const [isHoveringPoint, setIsHoveringPoint] = (0, _react.useState)(false);
|
|
99
95
|
const {
|
|
100
96
|
showSearchBtn
|
|
101
97
|
} = (0, _usePlotVisibility.default)(isFullscreen);
|
|
@@ -114,6 +110,22 @@ function Scatterplot(_ref) {
|
|
|
114
110
|
} = (0, _ZarrDataContext.useZarrData)();
|
|
115
111
|
const labelObsData = (0, _zarrData.useLabelObsData)();
|
|
116
112
|
const clickedInsideRef = (0, _react.useRef)(false);
|
|
113
|
+
const workerRef = (0, _react.useRef)(null);
|
|
114
|
+
const [scatterplotAttributes, setScatterplotAttributes] = (0, _react.useState)(null);
|
|
115
|
+
const isCategorical = (0, _react.useMemo)(() => {
|
|
116
|
+
if (settings.colorEncoding === _constants.COLOR_ENCODINGS.OBS) {
|
|
117
|
+
return (selectedObs === null || selectedObs === void 0 ? void 0 : selectedObs.type) === _constants.OBS_TYPES.CATEGORICAL || (selectedObs === null || selectedObs === void 0 ? void 0 : selectedObs.type) === _constants.OBS_TYPES.BOOLEAN;
|
|
118
|
+
} else {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
}, [settings.colorEncoding, selectedObs === null || selectedObs === void 0 ? void 0 : selectedObs.type]);
|
|
122
|
+
const {
|
|
123
|
+
colormap,
|
|
124
|
+
getColor
|
|
125
|
+
} = (0, _colorHelper.useColor)({
|
|
126
|
+
isCategorical,
|
|
127
|
+
colorscale: useUnsColors && settings.colorEncoding === _constants.COLOR_ENCODINGS.OBS ? selectedObs === null || selectedObs === void 0 ? void 0 : selectedObs.colors : null
|
|
128
|
+
});
|
|
117
129
|
|
|
118
130
|
// @TODO: assert length of obsmData, xData, obsData is equal
|
|
119
131
|
|
|
@@ -163,7 +175,8 @@ function Scatterplot(_ref) {
|
|
|
163
175
|
}
|
|
164
176
|
}, [obsData.data, obsData.isPending, obsData.serverError, obsmData.data, obsmData.isPending, obsmData.serverError, settings.colorEncoding, xData.data, xData.isPending, xData.serverError]);
|
|
165
177
|
(0, _react.useEffect)(() => {
|
|
166
|
-
|
|
178
|
+
var _data$positions;
|
|
179
|
+
if ((_data$positions = data.positions) !== null && _data$positions !== void 0 && _data$positions.length) {
|
|
167
180
|
var _deckRef$current, _deckRef$current2;
|
|
168
181
|
const mapHelper = new _mapHelper.MapHelper();
|
|
169
182
|
const {
|
|
@@ -198,10 +211,10 @@ function Scatterplot(_ref) {
|
|
|
198
211
|
}
|
|
199
212
|
}, [dispatch, settings.controls.radiusScale, settings.selectedObsm, viewport === null || viewport === void 0 ? void 0 : viewport.bounds]);
|
|
200
213
|
(0, _react.useEffect)(() => {
|
|
201
|
-
var _data$
|
|
214
|
+
var _data$positions2;
|
|
202
215
|
if (!pointInteractionEnabled) return;
|
|
203
216
|
if (selectedObsIndex == null) return;
|
|
204
|
-
if (!((_data$
|
|
217
|
+
if (!((_data$positions2 = data.positions) !== null && _data$positions2 !== void 0 && _data$positions2.length)) return;
|
|
205
218
|
|
|
206
219
|
// If the selection came from a click inside this plot, skip recentering
|
|
207
220
|
if (clickedInsideRef.current) {
|
|
@@ -236,116 +249,110 @@ function Scatterplot(_ref) {
|
|
|
236
249
|
zoom
|
|
237
250
|
};
|
|
238
251
|
}, [data.positions]);
|
|
239
|
-
|
|
240
|
-
// Make stable references for getOriginalIndex and sortedIndexMap
|
|
241
|
-
const identityGetOriginalIndex = (0, _react.useCallback)(i => i, []);
|
|
242
|
-
const identitySortedIndexMap = (0, _react.useMemo)(() => ({
|
|
243
|
-
get: key => key
|
|
244
|
-
}), []);
|
|
245
|
-
const {
|
|
246
|
-
sortedData,
|
|
247
|
-
getOriginalIndex,
|
|
248
|
-
sortedIndexMap
|
|
249
|
-
} = (0, _react.useMemo)(() => {
|
|
250
|
-
if ((settings.colorEncoding === _constants.COLOR_ENCODINGS.VAR || settings.colorEncoding === _constants.COLOR_ENCODINGS.OBS && (selectedObs === null || selectedObs === void 0 ? void 0 : selectedObs.type) === _constants.OBS_TYPES.CONTINUOUS) && data.positions && data.values && data.positions.length === data.values.length) {
|
|
251
|
-
const sortedIndices = _lodash.default.map(data.values, (_v, i) => i).sort((a, b) => data.values[a] - data.values[b]);
|
|
252
|
-
const sortedIndexMap = new Map(_lodash.default.map(sortedIndices, (originalIndex, sortedIndex) => [originalIndex, sortedIndex]));
|
|
253
|
-
return {
|
|
254
|
-
sortedData: _lodash.default.mapValues(data, (v, _k) => {
|
|
255
|
-
return v ? _lodash.default.at(v, sortedIndices) : v;
|
|
256
|
-
}),
|
|
257
|
-
getOriginalIndex: i => sortedIndices[i],
|
|
258
|
-
sortedIndexMap: sortedIndexMap
|
|
259
|
-
};
|
|
260
|
-
}
|
|
261
|
-
return {
|
|
262
|
-
sortedData: data,
|
|
263
|
-
getOriginalIndex: identityGetOriginalIndex,
|
|
264
|
-
// return original index
|
|
265
|
-
sortedIndexMap: identitySortedIndexMap // return original index
|
|
266
|
-
};
|
|
267
|
-
}, [data, identityGetOriginalIndex, identitySortedIndexMap, selectedObs === null || selectedObs === void 0 ? void 0 : selectedObs.type, settings.colorEncoding]);
|
|
268
|
-
const hoverLayer = typeof hoveredIndex === 'number' && Array.isArray(sortedData === null || sortedData === void 0 ? void 0 : sortedData.positions) && hoveredIndex < sortedData.positions.length ? new _layers.ScatterplotLayer({
|
|
269
|
-
id: 'hover-highlight',
|
|
270
|
-
data: [sortedData.positions[hoveredIndex]],
|
|
271
|
-
getPosition: d => d,
|
|
272
|
-
getFillColor: [255, 215, 0, 180],
|
|
273
|
-
getRadius: 10,
|
|
274
|
-
radiusMinPixels: 15,
|
|
275
|
-
radiusScale: 1,
|
|
276
|
-
pointSizeUnits: 'pixels',
|
|
277
|
-
pickable: false,
|
|
278
|
-
parameters: {
|
|
279
|
-
depthTest: false
|
|
280
|
-
}
|
|
281
|
-
}) : null;
|
|
282
|
-
const sortedObsIndices = (0, _react.useMemo)(() => {
|
|
283
|
-
return obsIndices ? new Set(Array.from(obsIndices, i => sortedIndexMap.get(i))) : obsIndices;
|
|
284
|
-
}, [obsIndices, sortedIndexMap]);
|
|
285
|
-
const isCategorical = (0, _react.useMemo)(() => {
|
|
286
|
-
if (settings.colorEncoding === _constants.COLOR_ENCODINGS.OBS) {
|
|
287
|
-
return (selectedObs === null || selectedObs === void 0 ? void 0 : selectedObs.type) === _constants.OBS_TYPES.CATEGORICAL || (selectedObs === null || selectedObs === void 0 ? void 0 : selectedObs.type) === _constants.OBS_TYPES.BOOLEAN;
|
|
288
|
-
} else {
|
|
289
|
-
return false;
|
|
290
|
-
}
|
|
291
|
-
}, [settings.colorEncoding, selectedObs === null || selectedObs === void 0 ? void 0 : selectedObs.type]);
|
|
292
252
|
const {
|
|
293
253
|
min,
|
|
294
254
|
max
|
|
295
|
-
} = {
|
|
255
|
+
} = (0, _react.useMemo)(() => ({
|
|
296
256
|
min: settings.controls.range[0] * (valueMax - valueMin) + valueMin,
|
|
297
257
|
max: settings.controls.range[1] * (valueMax - valueMin) + valueMin
|
|
298
|
-
};
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
258
|
+
}), [settings.controls.range, valueMax, valueMin]);
|
|
259
|
+
(0, _react.useEffect)(() => {
|
|
260
|
+
workerRef.current = (0, _scatterplotData.createScatterplotWorker)();
|
|
261
|
+
workerRef.current.onmessage = _ref2 => {
|
|
262
|
+
let {
|
|
263
|
+
data
|
|
264
|
+
} = _ref2;
|
|
265
|
+
setScatterplotAttributes(p => _objectSpread(_objectSpread({}, p), data));
|
|
266
|
+
};
|
|
267
|
+
workerRef.current.onerror = e => {
|
|
268
|
+
console.error('Worker error:', e);
|
|
269
|
+
};
|
|
270
|
+
return () => {
|
|
271
|
+
var _workerRef$current;
|
|
272
|
+
(_workerRef$current = workerRef.current) === null || _workerRef$current === void 0 || _workerRef$current.terminate();
|
|
273
|
+
};
|
|
274
|
+
}, []);
|
|
275
|
+
(0, _react.useEffect)(() => {
|
|
276
|
+
var _data$positions3;
|
|
277
|
+
if (workerRef.current && (_data$positions3 = data.positions) !== null && _data$positions3 !== void 0 && _data$positions3.length) {
|
|
278
|
+
workerRef.current.postMessage({
|
|
279
|
+
positions: data.positions
|
|
280
|
+
});
|
|
306
281
|
}
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
282
|
+
}, [data.positions]);
|
|
283
|
+
(0, _react.useEffect)(() => {
|
|
284
|
+
var _data$values;
|
|
285
|
+
if (workerRef.current && (_data$values = data.values) !== null && _data$values !== void 0 && _data$values.length) {
|
|
286
|
+
workerRef.current.postMessage({
|
|
287
|
+
values: data.values
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
}, [data.values]);
|
|
291
|
+
(0, _react.useEffect)(() => {
|
|
292
|
+
var _data$positions4;
|
|
293
|
+
if (workerRef.current && (_data$positions4 = data.positions) !== null && _data$positions4 !== void 0 && _data$positions4.length && obsIndices !== undefined) {
|
|
294
|
+
workerRef.current.postMessage({
|
|
295
|
+
obsIndices,
|
|
296
|
+
length: data.positions.length
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
}, [obsIndices, (_data$positions5 = data.positions) === null || _data$positions5 === void 0 ? void 0 : _data$positions5.length]);
|
|
300
|
+
const getFillColor = (0, _react.useCallback)((_d, _ref3) => {
|
|
318
301
|
let {
|
|
319
302
|
index
|
|
320
303
|
} = _ref3;
|
|
321
|
-
const grayOut =
|
|
322
|
-
if (pointInteractionEnabled &&
|
|
323
|
-
return
|
|
304
|
+
const grayOut = isPending || obsIndices && !obsIndices.has(index);
|
|
305
|
+
if (pointInteractionEnabled && index === selectedObsIndex) {
|
|
306
|
+
return [255, 215, 0, 255];
|
|
324
307
|
}
|
|
325
|
-
return (
|
|
326
|
-
|
|
308
|
+
return getColor({
|
|
309
|
+
value: (data.values[index] - min) / Math.max(max - min, 1e-6),
|
|
310
|
+
grayOut: grayOut
|
|
311
|
+
}) || [0, 0, 0, 100];
|
|
312
|
+
}, [isPending, obsIndices, pointInteractionEnabled, selectedObsIndex, getColor, data.values, min, max]);
|
|
327
313
|
const memoizedLayers = (0, _react.useMemo)(() => {
|
|
328
|
-
|
|
314
|
+
const hasSelection = settings.colorEncoding === _constants.COLOR_ENCODINGS.VAR && settings.selectedVar || settings.colorEncoding === _constants.COLOR_ENCODINGS.OBS && selectedObs;
|
|
315
|
+
return [new _ScatterplotLayer.ScatterplotLayer({
|
|
329
316
|
id: 'cherita-layer-scatterplot',
|
|
330
317
|
pickable: true,
|
|
331
|
-
|
|
318
|
+
autoHighlight: true,
|
|
319
|
+
highlightColor: pointInteractionEnabled ? [255, 215, 0, 255] : [0, 0, 0, 0],
|
|
320
|
+
data: {
|
|
321
|
+
length: (scatterplotAttributes === null || scatterplotAttributes === void 0 ? void 0 : scatterplotAttributes.count) || 0,
|
|
322
|
+
attributes: {
|
|
323
|
+
getPosition: {
|
|
324
|
+
value: (scatterplotAttributes === null || scatterplotAttributes === void 0 ? void 0 : scatterplotAttributes.positions) || new Float32Array(0),
|
|
325
|
+
size: 2
|
|
326
|
+
},
|
|
327
|
+
getValues: {
|
|
328
|
+
value: scatterplotAttributes === null || scatterplotAttributes === void 0 ? void 0 : scatterplotAttributes.values,
|
|
329
|
+
size: 1
|
|
330
|
+
},
|
|
331
|
+
getEnabled: {
|
|
332
|
+
value: scatterplotAttributes === null || scatterplotAttributes === void 0 ? void 0 : scatterplotAttributes.indexEnabledBitmask,
|
|
333
|
+
size: 1
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
},
|
|
332
337
|
radiusScale: radiusScale,
|
|
333
338
|
radiusMinPixels: 1,
|
|
334
|
-
getPosition: d => d,
|
|
335
|
-
getFillColor: getFillColor,
|
|
336
|
-
getRadius: getRadius,
|
|
337
339
|
updateTriggers: {
|
|
338
|
-
|
|
339
|
-
getRadius: [getRadius, hoveredIndex, selectedObsIndex]
|
|
340
|
+
colormap: [colormap]
|
|
340
341
|
},
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
342
|
+
colormap: isPending ? ["".concat((0, _colorHelper.rgbToHex)(_constants.GRAY), "aa")] : hasSelection ? colormap : ['#000000aa'],
|
|
343
|
+
isCategorical,
|
|
344
|
+
valueMin: min,
|
|
345
|
+
valueMax: max,
|
|
346
|
+
selectedIndex: pointInteractionEnabled ? selectedObsIndex !== null && selectedObsIndex !== void 0 ? selectedObsIndex : -1 : -1,
|
|
347
|
+
pointInteractionEnabled,
|
|
348
|
+
highlightMultiplier: pointInteractionEnabled ? 1.5 : 1.0
|
|
349
|
+
}), new _layers.EditableGeoJsonLayer({
|
|
346
350
|
id: 'cherita-layer-draw',
|
|
347
351
|
data: features,
|
|
348
352
|
mode: mode,
|
|
353
|
+
parameters: {
|
|
354
|
+
depthTest: false
|
|
355
|
+
},
|
|
349
356
|
selectedFeatureIndexes,
|
|
350
357
|
onEdit: _ref4 => {
|
|
351
358
|
let {
|
|
@@ -376,12 +383,9 @@ function Scatterplot(_ref) {
|
|
|
376
383
|
}
|
|
377
384
|
}
|
|
378
385
|
})];
|
|
379
|
-
}, [
|
|
386
|
+
}, [settings.colorEncoding, settings.selectedVar, selectedObs, pointInteractionEnabled, scatterplotAttributes === null || scatterplotAttributes === void 0 ? void 0 : scatterplotAttributes.count, scatterplotAttributes === null || scatterplotAttributes === void 0 ? void 0 : scatterplotAttributes.positions, scatterplotAttributes === null || scatterplotAttributes === void 0 ? void 0 : scatterplotAttributes.values, scatterplotAttributes === null || scatterplotAttributes === void 0 ? void 0 : scatterplotAttributes.indexEnabledBitmask, radiusScale, colormap, isPending, isCategorical, min, max, selectedObsIndex, features, mode, selectedFeatureIndexes]);
|
|
387
|
+
const layers = (0, _react.useDeferredValue)(mode === _editModes.ViewMode ? [...memoizedLayers].reverse() : memoizedLayers); // draw scatterplot on top of polygons when in ViewMode
|
|
380
388
|
|
|
381
|
-
// const layers = useDeferredValue(
|
|
382
|
-
// mode === ViewMode ? memoizedLayers.reverse() : memoizedLayers,
|
|
383
|
-
// ); // draw scatterplot on top of polygons when in ViewMode
|
|
384
|
-
const layers = (0, _react.useDeferredValue)([...memoizedLayers, hoverLayer].filter(Boolean));
|
|
385
389
|
(0, _react.useEffect)(() => {
|
|
386
390
|
var _features$features;
|
|
387
391
|
if (!(features !== null && features !== void 0 && (_features$features = features.features) !== null && _features$features !== void 0 && _features$features.length)) {
|
|
@@ -398,22 +402,22 @@ function Scatterplot(_ref) {
|
|
|
398
402
|
});
|
|
399
403
|
}, [settings.selectedObsm, dispatch, features.features]);
|
|
400
404
|
function onLayerClick(info) {
|
|
405
|
+
var _info$layer, _info$layer2;
|
|
401
406
|
if (mode !== _editModes.ViewMode) return;
|
|
402
|
-
if (
|
|
407
|
+
if (info.index === undefined || info.index === null) {
|
|
403
408
|
// clicked empty space
|
|
404
409
|
setSelectedFeatureIndexes([]);
|
|
405
410
|
return;
|
|
406
411
|
}
|
|
407
|
-
if (info.layer.id === 'cherita-layer-draw') {
|
|
412
|
+
if (((_info$layer = info.layer) === null || _info$layer === void 0 ? void 0 : _info$layer.id) === 'cherita-layer-draw') {
|
|
408
413
|
// clicked a drawn polygon
|
|
409
414
|
setSelectedFeatureIndexes([info.index]);
|
|
410
|
-
} else if (info.layer.id === 'cherita-layer-scatterplot' && pointInteractionEnabled) {
|
|
415
|
+
} else if (((_info$layer2 = info.layer) === null || _info$layer2 === void 0 ? void 0 : _info$layer2.id) === 'cherita-layer-scatterplot' && pointInteractionEnabled) {
|
|
411
416
|
// clicked a scatterplot point
|
|
412
417
|
clickedInsideRef.current = true;
|
|
413
|
-
const originalIndex = getOriginalIndex(info.index);
|
|
414
418
|
dispatch({
|
|
415
419
|
type: 'set.selectedObsIndex',
|
|
416
|
-
index:
|
|
420
|
+
index: info.index
|
|
417
421
|
});
|
|
418
422
|
// in collapsed view, open offcanvas
|
|
419
423
|
if (pointInteractionEnabled && showSearchBtn) {
|
|
@@ -438,25 +442,26 @@ function Scatterplot(_ref) {
|
|
|
438
442
|
object,
|
|
439
443
|
index
|
|
440
444
|
} = _ref5;
|
|
441
|
-
if (
|
|
445
|
+
if ((object === null || object === void 0 ? void 0 : object.type) === 'Feature') return;
|
|
446
|
+
if (index < 0 || index === null) return;
|
|
442
447
|
const text = [];
|
|
443
448
|
if (settings.colorEncoding === _constants.COLOR_ENCODINGS.OBS && selectedObs && !_lodash.default.includes(settings.labelObs, selectedObs.name)) {
|
|
444
|
-
var _data$
|
|
445
|
-
text.push(getLabel(selectedObs, (_data$
|
|
449
|
+
var _data$values2;
|
|
450
|
+
text.push(getLabel(selectedObs, (_data$values2 = data.values) === null || _data$values2 === void 0 ? void 0 : _data$values2[index]));
|
|
446
451
|
}
|
|
447
452
|
if (settings.colorEncoding === _constants.COLOR_ENCODINGS.VAR && settings.selectedVar) {
|
|
448
|
-
var _data$
|
|
449
|
-
text.push(getLabel(settings.selectedVar, (_data$
|
|
453
|
+
var _data$values3;
|
|
454
|
+
text.push(getLabel(settings.selectedVar, (_data$values3 = data.values) === null || _data$values3 === void 0 ? void 0 : _data$values3[index], true));
|
|
450
455
|
}
|
|
451
456
|
if (settings.labelObs.length) {
|
|
452
457
|
text.push(..._lodash.default.map(labelObsData.data, (v, k) => {
|
|
453
458
|
if (!v) return;
|
|
454
459
|
const labelObs = settings.data.obs[k];
|
|
455
|
-
return getLabel(labelObs, v[
|
|
460
|
+
return getLabel(labelObs, v[index]);
|
|
456
461
|
}));
|
|
457
462
|
}
|
|
458
463
|
if (!text.length) return;
|
|
459
|
-
const grayOut =
|
|
464
|
+
const grayOut = obsIndices && !obsIndices.has(index);
|
|
460
465
|
return {
|
|
461
466
|
text: text.length ? _lodash.default.compact(text).join('\n') : null,
|
|
462
467
|
className: grayOut ? 'tooltip-grayout' : 'deck-tooltip',
|
|
@@ -474,7 +479,7 @@ function Scatterplot(_ref) {
|
|
|
474
479
|
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_PlotAlert.PlotAlert, {
|
|
475
480
|
variant: "info",
|
|
476
481
|
heading: "Scatterplot unavailable for this dataset",
|
|
477
|
-
plotType:
|
|
482
|
+
plotType: _constants.PLOT_TYPES.SCATTERPLOT,
|
|
478
483
|
setPlotType: setPlotType,
|
|
479
484
|
children: "This dataset does not include any embeddings, so a scatterplot cannot be displayed. Please choose a different plot type to explore the data."
|
|
480
485
|
});
|
|
@@ -498,22 +503,14 @@ function Scatterplot(_ref) {
|
|
|
498
503
|
setIsRendering(false);
|
|
499
504
|
},
|
|
500
505
|
useDevicePixels: false,
|
|
501
|
-
|
|
506
|
+
getCursor: _ref6 => {
|
|
502
507
|
let {
|
|
503
|
-
|
|
504
|
-
|
|
508
|
+
isDragging,
|
|
509
|
+
isHovering
|
|
505
510
|
} = _ref6;
|
|
506
|
-
const active = pointInteractionEnabled && !!object;
|
|
507
|
-
setHoveredIndex(active ? index : null);
|
|
508
|
-
setIsHoveringPoint(active);
|
|
509
|
-
},
|
|
510
|
-
getCursor: _ref7 => {
|
|
511
|
-
let {
|
|
512
|
-
isDragging
|
|
513
|
-
} = _ref7;
|
|
514
511
|
if (mode !== _editModes.ViewMode) return 'crosshair';
|
|
515
512
|
if (isDragging) return 'grabbing';
|
|
516
|
-
if (
|
|
513
|
+
if (isHovering && pointInteractionEnabled) return 'pointer';
|
|
517
514
|
return 'grab';
|
|
518
515
|
},
|
|
519
516
|
ref: deckRef
|
|
@@ -532,7 +529,8 @@ function Scatterplot(_ref) {
|
|
|
532
529
|
})),
|
|
533
530
|
setShowCategories: setShowCategories,
|
|
534
531
|
setShowSearch: setShowSearch,
|
|
535
|
-
isFullscreen: isFullscreen
|
|
532
|
+
isFullscreen: isFullscreen,
|
|
533
|
+
isSearchObs: isSearchObs
|
|
536
534
|
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
|
|
537
535
|
className: "cherita-spatial-footer",
|
|
538
536
|
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
|
|
@@ -549,7 +547,7 @@ function Scatterplot(_ref) {
|
|
|
549
547
|
})]
|
|
550
548
|
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_Toolbox.Toolbox, {
|
|
551
549
|
mode: settings.colorEncoding === _constants.COLOR_ENCODINGS.VAR ? (_settings$selectedVar = settings.selectedVar) === null || _settings$selectedVar === void 0 ? void 0 : _settings$selectedVar.name : settings.colorEncoding === _constants.COLOR_ENCODINGS.OBS ? selectedObs === null || selectedObs === void 0 ? void 0 : selectedObs.name : null,
|
|
552
|
-
obsLength: parseInt((_data$
|
|
550
|
+
obsLength: parseInt((_data$positions6 = data.positions) === null || _data$positions6 === void 0 ? void 0 : _data$positions6.length),
|
|
553
551
|
slicedLength: parseInt(slicedLength),
|
|
554
552
|
setHasObsm: setHasObsm
|
|
555
553
|
})]
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.ScatterplotLayer = void 0;
|
|
7
|
+
var _core = require("@luma.gl/core");
|
|
8
|
+
var _deck = require("deck.gl");
|
|
9
|
+
var _constants = require("../../constants/constants");
|
|
10
|
+
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; }
|
|
11
|
+
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; }
|
|
12
|
+
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; }
|
|
13
|
+
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
|
|
14
|
+
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); }
|
|
15
|
+
class ScatterplotLayer extends _deck.ScatterplotLayer {
|
|
16
|
+
getShaders() {
|
|
17
|
+
const shaders = super.getShaders();
|
|
18
|
+
return _objectSpread(_objectSpread({}, shaders), {}, {
|
|
19
|
+
inject: {
|
|
20
|
+
'vs:#decl': "\n in float value;\n in float indexEnabled;\n in float instanceIndex;\n out float vNormValue;\n out float vSelected;\n out float vEnabled;\n uniform float highlightMultiplier;\n uniform bool isCategorical;\n uniform float valueMin;\n uniform float valueMax;\n uniform bool pointInteractionEnabled;\n uniform float selectedIndex;\n ",
|
|
21
|
+
// add z-axis position based on sortValue, zMin, and zMax
|
|
22
|
+
// to draw higher sortValue points above lower sortValue points
|
|
23
|
+
// and picked points at the front
|
|
24
|
+
'vs:DECKGL_FILTER_GL_POSITION': "\n float normValue = clamp((value - valueMin) / max(valueMax - valueMin, 1e-6), 0.0, 1.0);\n if (isVertexPicked(geometry.pickingColor)) {\n position.z = -position.w;\n }\n else if (indexEnabled < 0.5) {\n position.z = position.w;\n }\n else if (isCategorical) {\n if (value == -1.0) {\n position.z = position.w; // draw invalid at back\n }\n else { position.z = 0.0; }\n }\n else {\n position.z = mix(position.w, -position.w, normValue);\n }\n ",
|
|
25
|
+
// increase point size for hovered points
|
|
26
|
+
'vs:DECKGL_FILTER_SIZE': "\n if (pointInteractionEnabled) {\n size *= 4.0;\n if(instanceIndex == selectedIndex) {\n size *= 3.0;\n }\n }\n if (isVertexPicked(geometry.pickingColor)) {\n size *= highlightMultiplier;\n }\n if (indexEnabled < 0.5) {\n size *= 0.3;\n }\n ",
|
|
27
|
+
// Pass colorValue to fragment shader
|
|
28
|
+
'vs:DECKGL_FILTER_COLOR': "\n float normValue = clamp((value - valueMin) / max(valueMax - valueMin, 1e-6), 0.0, 1.0);\n vNormValue = normValue;\n vEnabled = indexEnabled;\n vSelected = float(instanceIndex == selectedIndex);\n ",
|
|
29
|
+
'fs:#decl': "\n in float vNormValue;\n in float vEnabled;\n in float vSelected;\n uniform sampler2D colorTexture;\n uniform bool useTexture;\n uniform float colormapSize;\n uniform vec4 gray;\n uniform float grayMix;\n ",
|
|
30
|
+
// Sample color from texture in fragment shader
|
|
31
|
+
'fs:DECKGL_FILTER_COLOR': "\n if (useTexture) {\n // Remap to texel centers so sampling matches JS interpolation\n float u = (vNormValue * (colormapSize - 1.0) + 0.5) / colormapSize;\n color = texture(colorTexture, vec2(u, 0.5));\n }\n if (vEnabled < 0.5) {\n color.rgb = mix(color.rgb, gray.rgb / 255.0, grayMix);\n color.a = gray.a / 255.0;\n }\n if(vSelected > 0.5) {\n color = picking_uHighlightColor;\n }\n "
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
initializeState() {
|
|
36
|
+
super.initializeState();
|
|
37
|
+
this.getAttributeManager().addInstanced({
|
|
38
|
+
value: {
|
|
39
|
+
size: 1,
|
|
40
|
+
accessor: 'getValues',
|
|
41
|
+
defaultValue: 0.0
|
|
42
|
+
},
|
|
43
|
+
indexEnabled: {
|
|
44
|
+
size: 1,
|
|
45
|
+
accessor: 'getEnabled',
|
|
46
|
+
defaultValue: 1.0
|
|
47
|
+
},
|
|
48
|
+
instanceIndex: {
|
|
49
|
+
size: 1,
|
|
50
|
+
accessor: (_, _ref) => {
|
|
51
|
+
let {
|
|
52
|
+
index
|
|
53
|
+
} = _ref;
|
|
54
|
+
return index;
|
|
55
|
+
},
|
|
56
|
+
defaultValue: 0
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
updateState(params) {
|
|
61
|
+
super.updateState(params);
|
|
62
|
+
const {
|
|
63
|
+
props,
|
|
64
|
+
oldProps,
|
|
65
|
+
changeFlags
|
|
66
|
+
} = params;
|
|
67
|
+
if (props.colormap !== oldProps.colormap || changeFlags.extensionsChanged) {
|
|
68
|
+
this._updateColorTexture(props.colormap);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
_updateColorTexture(colormap) {
|
|
72
|
+
const {
|
|
73
|
+
gl
|
|
74
|
+
} = this.context;
|
|
75
|
+
|
|
76
|
+
// colormap is an array of hex strings
|
|
77
|
+
const colors = colormap.flatMap(hex => {
|
|
78
|
+
const r = parseInt(hex.slice(1, 3), 16);
|
|
79
|
+
const g = parseInt(hex.slice(3, 5), 16);
|
|
80
|
+
const b = parseInt(hex.slice(5, 7), 16);
|
|
81
|
+
const a = parseInt(hex.slice(7, 9) || 'ff', 16);
|
|
82
|
+
return [r, g, b, a];
|
|
83
|
+
});
|
|
84
|
+
if (this.state.colorTexture) {
|
|
85
|
+
this.state.colorTexture.delete();
|
|
86
|
+
}
|
|
87
|
+
const texture = new _core.Texture2D(gl, {
|
|
88
|
+
data: new Uint8Array(colors),
|
|
89
|
+
width: colormap === null || colormap === void 0 ? void 0 : colormap.length,
|
|
90
|
+
height: 1,
|
|
91
|
+
format: gl.RGBA,
|
|
92
|
+
type: gl.UNSIGNED_BYTE,
|
|
93
|
+
parameters: {
|
|
94
|
+
[gl.TEXTURE_MIN_FILTER]: gl.LINEAR,
|
|
95
|
+
[gl.TEXTURE_MAG_FILTER]: gl.LINEAR,
|
|
96
|
+
[gl.TEXTURE_WRAP_S]: gl.CLAMP_TO_EDGE,
|
|
97
|
+
[gl.TEXTURE_WRAP_T]: gl.CLAMP_TO_EDGE
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
this.setState({
|
|
101
|
+
colorTexture: texture
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
draw(params) {
|
|
105
|
+
var _this$props$colormap$, _this$props$colormap;
|
|
106
|
+
const {
|
|
107
|
+
highlightMultiplier = 1.0,
|
|
108
|
+
isCategorical = false,
|
|
109
|
+
valueMin = 0,
|
|
110
|
+
valueMax = 0,
|
|
111
|
+
pointInteractionEnabled = false,
|
|
112
|
+
selectedIndex = -1,
|
|
113
|
+
gray = [..._constants.GRAY, 255 * _constants.GRAY_ALPHA],
|
|
114
|
+
grayMix = _constants.GRAY_MIX
|
|
115
|
+
} = this.props;
|
|
116
|
+
const {
|
|
117
|
+
colorTexture
|
|
118
|
+
} = this.state;
|
|
119
|
+
const model = this.state.model;
|
|
120
|
+
if (!model) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
model.setUniforms({
|
|
124
|
+
highlightMultiplier,
|
|
125
|
+
colorTexture: colorTexture || null,
|
|
126
|
+
useTexture: !!colorTexture,
|
|
127
|
+
colormapSize: (_this$props$colormap$ = (_this$props$colormap = this.props.colormap) === null || _this$props$colormap === void 0 ? void 0 : _this$props$colormap.length) !== null && _this$props$colormap$ !== void 0 ? _this$props$colormap$ : 1,
|
|
128
|
+
isCategorical,
|
|
129
|
+
valueMin: isNaN(valueMin) ? 0 : valueMin,
|
|
130
|
+
valueMax: isNaN(valueMax) ? 0 : valueMax,
|
|
131
|
+
pointInteractionEnabled,
|
|
132
|
+
selectedIndex,
|
|
133
|
+
gray,
|
|
134
|
+
grayMix
|
|
135
|
+
});
|
|
136
|
+
super.draw(params);
|
|
137
|
+
}
|
|
138
|
+
finalizeState(context) {
|
|
139
|
+
var _this$state$colorText;
|
|
140
|
+
super.finalizeState(context);
|
|
141
|
+
(_this$state$colorText = this.state.colorTexture) === null || _this$state$colorText === void 0 || _this$state$colorText.delete();
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
exports.ScatterplotLayer = ScatterplotLayer;
|
|
@@ -14,6 +14,7 @@ var _Button = _interopRequireDefault(require("react-bootstrap/Button"));
|
|
|
14
14
|
var _ButtonGroup = _interopRequireDefault(require("react-bootstrap/ButtonGroup"));
|
|
15
15
|
var _Dropdown = _interopRequireDefault(require("react-bootstrap/Dropdown"));
|
|
16
16
|
var _ScatterplotControls = require("./ScatterplotControls");
|
|
17
|
+
var _DatasetContext = require("../../context/DatasetContext");
|
|
17
18
|
var _SettingsContext = require("../../context/SettingsContext");
|
|
18
19
|
var _usePlotVisibility = _interopRequireDefault(require("../../utils/usePlotVisibility"));
|
|
19
20
|
var _OffCanvas = require("../offcanvas/OffCanvas");
|
|
@@ -32,8 +33,10 @@ function SpatialControls(_ref) {
|
|
|
32
33
|
decreaseZoom,
|
|
33
34
|
setShowCategories,
|
|
34
35
|
setShowSearch,
|
|
35
|
-
isFullscreen
|
|
36
|
+
isFullscreen,
|
|
37
|
+
isSearchObs = false
|
|
36
38
|
} = _ref;
|
|
39
|
+
const dataset = (0, _DatasetContext.useDataset)();
|
|
37
40
|
const settings = (0, _SettingsContext.useSettings)();
|
|
38
41
|
const dispatch = (0, _SettingsContext.useSettingsDispatch)();
|
|
39
42
|
const [showControls, setShowControls] = (0, _react.useState)(false);
|
|
@@ -113,7 +116,7 @@ function SpatialControls(_ref) {
|
|
|
113
116
|
placement: "right",
|
|
114
117
|
overlay: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactBootstrap.Tooltip, {
|
|
115
118
|
id: "tooltip-obs",
|
|
116
|
-
children: "
|
|
119
|
+
children: "Explore categories"
|
|
117
120
|
}),
|
|
118
121
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Button.default, {
|
|
119
122
|
size: isCompact && 'sm',
|
|
@@ -124,9 +127,9 @@ function SpatialControls(_ref) {
|
|
|
124
127
|
})
|
|
125
128
|
}), showSearchBtn && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactBootstrap.OverlayTrigger, {
|
|
126
129
|
placement: "right",
|
|
127
|
-
overlay: /*#__PURE__*/(0, _jsxRuntime.
|
|
130
|
+
overlay: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactBootstrap.Tooltip, {
|
|
128
131
|
id: "tooltip-vars",
|
|
129
|
-
children: "Search
|
|
132
|
+
children: ["Search", ' ', isSearchObs ? dataset.obsLabel.plural : dataset.varLabel.plural]
|
|
130
133
|
}),
|
|
131
134
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Button.default, {
|
|
132
135
|
size: isCompact && 'sm',
|