@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
|
@@ -85,7 +85,8 @@ export function Pseudospatial(_ref) {
|
|
|
85
85
|
setPlotType
|
|
86
86
|
} = _ref;
|
|
87
87
|
const {
|
|
88
|
-
imageUrl
|
|
88
|
+
imageUrl,
|
|
89
|
+
valueLabel
|
|
89
90
|
} = useDataset();
|
|
90
91
|
const settings = useSettings();
|
|
91
92
|
const dispatch = useSettingsDispatch();
|
|
@@ -93,7 +94,9 @@ export function Pseudospatial(_ref) {
|
|
|
93
94
|
const [layout, setLayout] = useState({});
|
|
94
95
|
const {
|
|
95
96
|
getColor
|
|
96
|
-
} = useColor(
|
|
97
|
+
} = useColor({
|
|
98
|
+
isCategorical: false
|
|
99
|
+
});
|
|
97
100
|
const colorscale = useRef(settings.controls.colorScale);
|
|
98
101
|
const {
|
|
99
102
|
valueMin,
|
|
@@ -129,7 +132,7 @@ export function Pseudospatial(_ref) {
|
|
|
129
132
|
return trace;
|
|
130
133
|
}
|
|
131
134
|
const color = rgbToHex(getColor({
|
|
132
|
-
value: (v - min) / (max - min)
|
|
135
|
+
value: (v - min) / Math.max(max - min, 1e-6)
|
|
133
136
|
}));
|
|
134
137
|
return _objectSpread(_objectSpread({}, trace), {}, {
|
|
135
138
|
fillcolor: color,
|
|
@@ -172,7 +175,7 @@ export function Pseudospatial(_ref) {
|
|
|
172
175
|
return trace;
|
|
173
176
|
}
|
|
174
177
|
const color = rgbToHex(getColor({
|
|
175
|
-
value: (v - min) / (max - min)
|
|
178
|
+
value: (v - min) / Math.max(max - min, 1e-6)
|
|
176
179
|
}));
|
|
177
180
|
return _objectSpread(_objectSpread({}, trace), {}, {
|
|
178
181
|
fillcolor: color,
|
|
@@ -271,7 +274,7 @@ export function Pseudospatial(_ref) {
|
|
|
271
274
|
}), hasSelections && showLegend && /*#__PURE__*/_jsx(Legend, {
|
|
272
275
|
min: layout === null || layout === void 0 || (_layout$coloraxis5 = layout.coloraxis) === null || _layout$coloraxis5 === void 0 ? void 0 : _layout$coloraxis5.cmin,
|
|
273
276
|
max: layout === null || layout === void 0 || (_layout$coloraxis6 = layout.coloraxis) === null || _layout$coloraxis6 === void 0 ? void 0 : _layout$coloraxis6.cmax,
|
|
274
|
-
addText: plotType === PLOT_TYPES.GENE ?
|
|
277
|
+
addText: plotType === PLOT_TYPES.GENE ? " - Mean ".concat(valueLabel) : plotType === PLOT_TYPES.CATEGORICAL ? ' - %' : plotType === PLOT_TYPES.CONTINUOUS ? ' - Mean value' : ''
|
|
275
278
|
})]
|
|
276
279
|
})
|
|
277
280
|
});
|
|
@@ -5,7 +5,6 @@ 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 { useCallback, useDeferredValue, useEffect, useMemo, useRef, useState } from 'react';
|
|
7
7
|
import { LinearInterpolator } from '@deck.gl/core';
|
|
8
|
-
import { ScatterplotLayer } from '@deck.gl/layers';
|
|
9
8
|
import { DeckGL } from '@deck.gl/react';
|
|
10
9
|
import { faTriangleExclamation } from '@fortawesome/free-solid-svg-icons';
|
|
11
10
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
@@ -13,9 +12,10 @@ import { ViewMode } from '@nebula.gl/edit-modes';
|
|
|
13
12
|
import { EditableGeoJsonLayer } from '@nebula.gl/layers';
|
|
14
13
|
import _ from 'lodash';
|
|
15
14
|
import { Alert } from 'react-bootstrap';
|
|
15
|
+
import { ScatterplotLayer } from './ScatterplotLayer';
|
|
16
16
|
import { SpatialControls } from './SpatialControls';
|
|
17
17
|
import { Toolbox } from './Toolbox';
|
|
18
|
-
import { COLOR_ENCODINGS, OBS_TYPES, SELECTED_POLYGON_FILLCOLOR, UNSELECTED_POLYGON_FILLCOLOR } from '../../constants/constants';
|
|
18
|
+
import { COLOR_ENCODINGS, OBS_TYPES, PLOT_TYPES, SELECTED_POLYGON_FILLCOLOR, UNSELECTED_POLYGON_FILLCOLOR, GRAY } from '../../constants/constants';
|
|
19
19
|
import { useDataset } from '../../context/DatasetContext';
|
|
20
20
|
import { useFilteredData } from '../../context/FilterContext';
|
|
21
21
|
import { useSettings, useSettingsDispatch } from '../../context/SettingsContext';
|
|
@@ -28,6 +28,7 @@ import { useSelectedObs } from '../../utils/Resolver';
|
|
|
28
28
|
import { formatNumerical } from '../../utils/string';
|
|
29
29
|
import usePlotVisibility from '../../utils/usePlotVisibility';
|
|
30
30
|
import { useLabelObsData } from '../../utils/zarrData';
|
|
31
|
+
import { createScatterplotWorker } from '../../workers/scatterplotData.js';
|
|
31
32
|
import { PlotAlert } from '../plot/PlotAlert';
|
|
32
33
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
33
34
|
window.deck.log.level = 1;
|
|
@@ -48,15 +49,15 @@ const getRadiusScale = bounds => {
|
|
|
48
49
|
return rs;
|
|
49
50
|
};
|
|
50
51
|
export function Scatterplot(_ref) {
|
|
51
|
-
var _features$features2, _obsmData$serverError, _labelObsData$serverE, _settings$selectedVar, _data$
|
|
52
|
+
var _data$positions5, _features$features2, _obsmData$serverError, _labelObsData$serverE, _settings$selectedVar, _data$positions6;
|
|
52
53
|
let {
|
|
54
|
+
pointInteractionEnabled = false,
|
|
55
|
+
showSpatialControls = true,
|
|
53
56
|
setShowCategories,
|
|
54
57
|
setShowSearch,
|
|
55
|
-
plotType,
|
|
56
58
|
setPlotType,
|
|
57
59
|
isFullscreen = false,
|
|
58
|
-
|
|
59
|
-
showSpatialControls = true
|
|
60
|
+
isSearchObs
|
|
60
61
|
} = _ref;
|
|
61
62
|
const {
|
|
62
63
|
useUnsColors
|
|
@@ -69,9 +70,6 @@ export function Scatterplot(_ref) {
|
|
|
69
70
|
slicedLength
|
|
70
71
|
} = useFilteredData();
|
|
71
72
|
const dispatch = useSettingsDispatch();
|
|
72
|
-
const {
|
|
73
|
-
getColor
|
|
74
|
-
} = useColor();
|
|
75
73
|
const deckRef = useRef(null);
|
|
76
74
|
const [viewport, setViewport] = useState(null);
|
|
77
75
|
const [viewState, setViewState] = useState(INITIAL_VIEW_STATE);
|
|
@@ -87,8 +85,6 @@ export function Scatterplot(_ref) {
|
|
|
87
85
|
const radiusScale = settings.controls.radiusScale[settings.selectedObsm] || 1;
|
|
88
86
|
const selectedObs = useSelectedObs();
|
|
89
87
|
const selectedObsIndex = settings.selectedObsIndex;
|
|
90
|
-
const [hoveredIndex, setHoveredIndex] = useState(null);
|
|
91
|
-
const [isHoveringPoint, setIsHoveringPoint] = useState(false);
|
|
92
88
|
const {
|
|
93
89
|
showSearchBtn
|
|
94
90
|
} = usePlotVisibility(isFullscreen);
|
|
@@ -107,6 +103,22 @@ export function Scatterplot(_ref) {
|
|
|
107
103
|
} = useZarrData();
|
|
108
104
|
const labelObsData = useLabelObsData();
|
|
109
105
|
const clickedInsideRef = useRef(false);
|
|
106
|
+
const workerRef = useRef(null);
|
|
107
|
+
const [scatterplotAttributes, setScatterplotAttributes] = useState(null);
|
|
108
|
+
const isCategorical = useMemo(() => {
|
|
109
|
+
if (settings.colorEncoding === COLOR_ENCODINGS.OBS) {
|
|
110
|
+
return (selectedObs === null || selectedObs === void 0 ? void 0 : selectedObs.type) === OBS_TYPES.CATEGORICAL || (selectedObs === null || selectedObs === void 0 ? void 0 : selectedObs.type) === OBS_TYPES.BOOLEAN;
|
|
111
|
+
} else {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
}, [settings.colorEncoding, selectedObs === null || selectedObs === void 0 ? void 0 : selectedObs.type]);
|
|
115
|
+
const {
|
|
116
|
+
colormap,
|
|
117
|
+
getColor
|
|
118
|
+
} = useColor({
|
|
119
|
+
isCategorical,
|
|
120
|
+
colorscale: useUnsColors && settings.colorEncoding === COLOR_ENCODINGS.OBS ? selectedObs === null || selectedObs === void 0 ? void 0 : selectedObs.colors : null
|
|
121
|
+
});
|
|
110
122
|
|
|
111
123
|
// @TODO: assert length of obsmData, xData, obsData is equal
|
|
112
124
|
|
|
@@ -156,7 +168,8 @@ export function Scatterplot(_ref) {
|
|
|
156
168
|
}
|
|
157
169
|
}, [obsData.data, obsData.isPending, obsData.serverError, obsmData.data, obsmData.isPending, obsmData.serverError, settings.colorEncoding, xData.data, xData.isPending, xData.serverError]);
|
|
158
170
|
useEffect(() => {
|
|
159
|
-
|
|
171
|
+
var _data$positions;
|
|
172
|
+
if ((_data$positions = data.positions) !== null && _data$positions !== void 0 && _data$positions.length) {
|
|
160
173
|
var _deckRef$current, _deckRef$current2;
|
|
161
174
|
const mapHelper = new MapHelper();
|
|
162
175
|
const {
|
|
@@ -191,10 +204,10 @@ export function Scatterplot(_ref) {
|
|
|
191
204
|
}
|
|
192
205
|
}, [dispatch, settings.controls.radiusScale, settings.selectedObsm, viewport === null || viewport === void 0 ? void 0 : viewport.bounds]);
|
|
193
206
|
useEffect(() => {
|
|
194
|
-
var _data$
|
|
207
|
+
var _data$positions2;
|
|
195
208
|
if (!pointInteractionEnabled) return;
|
|
196
209
|
if (selectedObsIndex == null) return;
|
|
197
|
-
if (!((_data$
|
|
210
|
+
if (!((_data$positions2 = data.positions) !== null && _data$positions2 !== void 0 && _data$positions2.length)) return;
|
|
198
211
|
|
|
199
212
|
// If the selection came from a click inside this plot, skip recentering
|
|
200
213
|
if (clickedInsideRef.current) {
|
|
@@ -229,116 +242,110 @@ export function Scatterplot(_ref) {
|
|
|
229
242
|
zoom
|
|
230
243
|
};
|
|
231
244
|
}, [data.positions]);
|
|
232
|
-
|
|
233
|
-
// Make stable references for getOriginalIndex and sortedIndexMap
|
|
234
|
-
const identityGetOriginalIndex = useCallback(i => i, []);
|
|
235
|
-
const identitySortedIndexMap = useMemo(() => ({
|
|
236
|
-
get: key => key
|
|
237
|
-
}), []);
|
|
238
|
-
const {
|
|
239
|
-
sortedData,
|
|
240
|
-
getOriginalIndex,
|
|
241
|
-
sortedIndexMap
|
|
242
|
-
} = useMemo(() => {
|
|
243
|
-
if ((settings.colorEncoding === COLOR_ENCODINGS.VAR || settings.colorEncoding === COLOR_ENCODINGS.OBS && (selectedObs === null || selectedObs === void 0 ? void 0 : selectedObs.type) === OBS_TYPES.CONTINUOUS) && data.positions && data.values && data.positions.length === data.values.length) {
|
|
244
|
-
const sortedIndices = _.map(data.values, (_v, i) => i).sort((a, b) => data.values[a] - data.values[b]);
|
|
245
|
-
const sortedIndexMap = new Map(_.map(sortedIndices, (originalIndex, sortedIndex) => [originalIndex, sortedIndex]));
|
|
246
|
-
return {
|
|
247
|
-
sortedData: _.mapValues(data, (v, _k) => {
|
|
248
|
-
return v ? _.at(v, sortedIndices) : v;
|
|
249
|
-
}),
|
|
250
|
-
getOriginalIndex: i => sortedIndices[i],
|
|
251
|
-
sortedIndexMap: sortedIndexMap
|
|
252
|
-
};
|
|
253
|
-
}
|
|
254
|
-
return {
|
|
255
|
-
sortedData: data,
|
|
256
|
-
getOriginalIndex: identityGetOriginalIndex,
|
|
257
|
-
// return original index
|
|
258
|
-
sortedIndexMap: identitySortedIndexMap // return original index
|
|
259
|
-
};
|
|
260
|
-
}, [data, identityGetOriginalIndex, identitySortedIndexMap, selectedObs === null || selectedObs === void 0 ? void 0 : selectedObs.type, settings.colorEncoding]);
|
|
261
|
-
const hoverLayer = typeof hoveredIndex === 'number' && Array.isArray(sortedData === null || sortedData === void 0 ? void 0 : sortedData.positions) && hoveredIndex < sortedData.positions.length ? new ScatterplotLayer({
|
|
262
|
-
id: 'hover-highlight',
|
|
263
|
-
data: [sortedData.positions[hoveredIndex]],
|
|
264
|
-
getPosition: d => d,
|
|
265
|
-
getFillColor: [255, 215, 0, 180],
|
|
266
|
-
getRadius: 10,
|
|
267
|
-
radiusMinPixels: 15,
|
|
268
|
-
radiusScale: 1,
|
|
269
|
-
pointSizeUnits: 'pixels',
|
|
270
|
-
pickable: false,
|
|
271
|
-
parameters: {
|
|
272
|
-
depthTest: false
|
|
273
|
-
}
|
|
274
|
-
}) : null;
|
|
275
|
-
const sortedObsIndices = useMemo(() => {
|
|
276
|
-
return obsIndices ? new Set(Array.from(obsIndices, i => sortedIndexMap.get(i))) : obsIndices;
|
|
277
|
-
}, [obsIndices, sortedIndexMap]);
|
|
278
|
-
const isCategorical = useMemo(() => {
|
|
279
|
-
if (settings.colorEncoding === COLOR_ENCODINGS.OBS) {
|
|
280
|
-
return (selectedObs === null || selectedObs === void 0 ? void 0 : selectedObs.type) === OBS_TYPES.CATEGORICAL || (selectedObs === null || selectedObs === void 0 ? void 0 : selectedObs.type) === OBS_TYPES.BOOLEAN;
|
|
281
|
-
} else {
|
|
282
|
-
return false;
|
|
283
|
-
}
|
|
284
|
-
}, [settings.colorEncoding, selectedObs === null || selectedObs === void 0 ? void 0 : selectedObs.type]);
|
|
285
245
|
const {
|
|
286
246
|
min,
|
|
287
247
|
max
|
|
288
|
-
} = {
|
|
248
|
+
} = useMemo(() => ({
|
|
289
249
|
min: settings.controls.range[0] * (valueMax - valueMin) + valueMin,
|
|
290
250
|
max: settings.controls.range[1] * (valueMax - valueMin) + valueMin
|
|
291
|
-
};
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
251
|
+
}), [settings.controls.range, valueMax, valueMin]);
|
|
252
|
+
useEffect(() => {
|
|
253
|
+
workerRef.current = createScatterplotWorker();
|
|
254
|
+
workerRef.current.onmessage = _ref2 => {
|
|
255
|
+
let {
|
|
256
|
+
data
|
|
257
|
+
} = _ref2;
|
|
258
|
+
setScatterplotAttributes(p => _objectSpread(_objectSpread({}, p), data));
|
|
259
|
+
};
|
|
260
|
+
workerRef.current.onerror = e => {
|
|
261
|
+
console.error('Worker error:', e);
|
|
262
|
+
};
|
|
263
|
+
return () => {
|
|
264
|
+
var _workerRef$current;
|
|
265
|
+
(_workerRef$current = workerRef.current) === null || _workerRef$current === void 0 || _workerRef$current.terminate();
|
|
266
|
+
};
|
|
267
|
+
}, []);
|
|
268
|
+
useEffect(() => {
|
|
269
|
+
var _data$positions3;
|
|
270
|
+
if (workerRef.current && (_data$positions3 = data.positions) !== null && _data$positions3 !== void 0 && _data$positions3.length) {
|
|
271
|
+
workerRef.current.postMessage({
|
|
272
|
+
positions: data.positions
|
|
273
|
+
});
|
|
299
274
|
}
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
275
|
+
}, [data.positions]);
|
|
276
|
+
useEffect(() => {
|
|
277
|
+
var _data$values;
|
|
278
|
+
if (workerRef.current && (_data$values = data.values) !== null && _data$values !== void 0 && _data$values.length) {
|
|
279
|
+
workerRef.current.postMessage({
|
|
280
|
+
values: data.values
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
}, [data.values]);
|
|
284
|
+
useEffect(() => {
|
|
285
|
+
var _data$positions4;
|
|
286
|
+
if (workerRef.current && (_data$positions4 = data.positions) !== null && _data$positions4 !== void 0 && _data$positions4.length && obsIndices !== undefined) {
|
|
287
|
+
workerRef.current.postMessage({
|
|
288
|
+
obsIndices,
|
|
289
|
+
length: data.positions.length
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
}, [obsIndices, (_data$positions5 = data.positions) === null || _data$positions5 === void 0 ? void 0 : _data$positions5.length]);
|
|
293
|
+
const getFillColor = useCallback((_d, _ref3) => {
|
|
311
294
|
let {
|
|
312
295
|
index
|
|
313
296
|
} = _ref3;
|
|
314
|
-
const grayOut =
|
|
315
|
-
if (pointInteractionEnabled &&
|
|
316
|
-
return
|
|
297
|
+
const grayOut = isPending || obsIndices && !obsIndices.has(index);
|
|
298
|
+
if (pointInteractionEnabled && index === selectedObsIndex) {
|
|
299
|
+
return [255, 215, 0, 255];
|
|
317
300
|
}
|
|
318
|
-
return (
|
|
319
|
-
|
|
301
|
+
return getColor({
|
|
302
|
+
value: (data.values[index] - min) / Math.max(max - min, 1e-6),
|
|
303
|
+
grayOut: grayOut
|
|
304
|
+
}) || [0, 0, 0, 100];
|
|
305
|
+
}, [isPending, obsIndices, pointInteractionEnabled, selectedObsIndex, getColor, data.values, min, max]);
|
|
320
306
|
const memoizedLayers = useMemo(() => {
|
|
307
|
+
const hasSelection = settings.colorEncoding === COLOR_ENCODINGS.VAR && settings.selectedVar || settings.colorEncoding === COLOR_ENCODINGS.OBS && selectedObs;
|
|
321
308
|
return [new ScatterplotLayer({
|
|
322
309
|
id: 'cherita-layer-scatterplot',
|
|
323
310
|
pickable: true,
|
|
324
|
-
|
|
311
|
+
autoHighlight: true,
|
|
312
|
+
highlightColor: pointInteractionEnabled ? [255, 215, 0, 255] : [0, 0, 0, 0],
|
|
313
|
+
data: {
|
|
314
|
+
length: (scatterplotAttributes === null || scatterplotAttributes === void 0 ? void 0 : scatterplotAttributes.count) || 0,
|
|
315
|
+
attributes: {
|
|
316
|
+
getPosition: {
|
|
317
|
+
value: (scatterplotAttributes === null || scatterplotAttributes === void 0 ? void 0 : scatterplotAttributes.positions) || new Float32Array(0),
|
|
318
|
+
size: 2
|
|
319
|
+
},
|
|
320
|
+
getValues: {
|
|
321
|
+
value: scatterplotAttributes === null || scatterplotAttributes === void 0 ? void 0 : scatterplotAttributes.values,
|
|
322
|
+
size: 1
|
|
323
|
+
},
|
|
324
|
+
getEnabled: {
|
|
325
|
+
value: scatterplotAttributes === null || scatterplotAttributes === void 0 ? void 0 : scatterplotAttributes.indexEnabledBitmask,
|
|
326
|
+
size: 1
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
},
|
|
325
330
|
radiusScale: radiusScale,
|
|
326
331
|
radiusMinPixels: 1,
|
|
327
|
-
getPosition: d => d,
|
|
328
|
-
getFillColor: getFillColor,
|
|
329
|
-
getRadius: getRadius,
|
|
330
332
|
updateTriggers: {
|
|
331
|
-
|
|
332
|
-
getRadius: [getRadius, hoveredIndex, selectedObsIndex]
|
|
333
|
+
colormap: [colormap]
|
|
333
334
|
},
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
335
|
+
colormap: isPending ? ["".concat(rgbToHex(GRAY), "aa")] : hasSelection ? colormap : ['#000000aa'],
|
|
336
|
+
isCategorical,
|
|
337
|
+
valueMin: min,
|
|
338
|
+
valueMax: max,
|
|
339
|
+
selectedIndex: pointInteractionEnabled ? selectedObsIndex !== null && selectedObsIndex !== void 0 ? selectedObsIndex : -1 : -1,
|
|
340
|
+
pointInteractionEnabled,
|
|
341
|
+
highlightMultiplier: pointInteractionEnabled ? 1.5 : 1.0
|
|
338
342
|
}), new EditableGeoJsonLayer({
|
|
339
343
|
id: 'cherita-layer-draw',
|
|
340
344
|
data: features,
|
|
341
345
|
mode: mode,
|
|
346
|
+
parameters: {
|
|
347
|
+
depthTest: false
|
|
348
|
+
},
|
|
342
349
|
selectedFeatureIndexes,
|
|
343
350
|
onEdit: _ref4 => {
|
|
344
351
|
let {
|
|
@@ -369,12 +376,9 @@ export function Scatterplot(_ref) {
|
|
|
369
376
|
}
|
|
370
377
|
}
|
|
371
378
|
})];
|
|
372
|
-
}, [
|
|
379
|
+
}, [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]);
|
|
380
|
+
const layers = useDeferredValue(mode === ViewMode ? [...memoizedLayers].reverse() : memoizedLayers); // draw scatterplot on top of polygons when in ViewMode
|
|
373
381
|
|
|
374
|
-
// const layers = useDeferredValue(
|
|
375
|
-
// mode === ViewMode ? memoizedLayers.reverse() : memoizedLayers,
|
|
376
|
-
// ); // draw scatterplot on top of polygons when in ViewMode
|
|
377
|
-
const layers = useDeferredValue([...memoizedLayers, hoverLayer].filter(Boolean));
|
|
378
382
|
useEffect(() => {
|
|
379
383
|
var _features$features;
|
|
380
384
|
if (!(features !== null && features !== void 0 && (_features$features = features.features) !== null && _features$features !== void 0 && _features$features.length)) {
|
|
@@ -391,22 +395,22 @@ export function Scatterplot(_ref) {
|
|
|
391
395
|
});
|
|
392
396
|
}, [settings.selectedObsm, dispatch, features.features]);
|
|
393
397
|
function onLayerClick(info) {
|
|
398
|
+
var _info$layer, _info$layer2;
|
|
394
399
|
if (mode !== ViewMode) return;
|
|
395
|
-
if (
|
|
400
|
+
if (info.index === undefined || info.index === null) {
|
|
396
401
|
// clicked empty space
|
|
397
402
|
setSelectedFeatureIndexes([]);
|
|
398
403
|
return;
|
|
399
404
|
}
|
|
400
|
-
if (info.layer.id === 'cherita-layer-draw') {
|
|
405
|
+
if (((_info$layer = info.layer) === null || _info$layer === void 0 ? void 0 : _info$layer.id) === 'cherita-layer-draw') {
|
|
401
406
|
// clicked a drawn polygon
|
|
402
407
|
setSelectedFeatureIndexes([info.index]);
|
|
403
|
-
} else if (info.layer.id === 'cherita-layer-scatterplot' && pointInteractionEnabled) {
|
|
408
|
+
} else if (((_info$layer2 = info.layer) === null || _info$layer2 === void 0 ? void 0 : _info$layer2.id) === 'cherita-layer-scatterplot' && pointInteractionEnabled) {
|
|
404
409
|
// clicked a scatterplot point
|
|
405
410
|
clickedInsideRef.current = true;
|
|
406
|
-
const originalIndex = getOriginalIndex(info.index);
|
|
407
411
|
dispatch({
|
|
408
412
|
type: 'set.selectedObsIndex',
|
|
409
|
-
index:
|
|
413
|
+
index: info.index
|
|
410
414
|
});
|
|
411
415
|
// in collapsed view, open offcanvas
|
|
412
416
|
if (pointInteractionEnabled && showSearchBtn) {
|
|
@@ -431,25 +435,26 @@ export function Scatterplot(_ref) {
|
|
|
431
435
|
object,
|
|
432
436
|
index
|
|
433
437
|
} = _ref5;
|
|
434
|
-
if (
|
|
438
|
+
if ((object === null || object === void 0 ? void 0 : object.type) === 'Feature') return;
|
|
439
|
+
if (index < 0 || index === null) return;
|
|
435
440
|
const text = [];
|
|
436
441
|
if (settings.colorEncoding === COLOR_ENCODINGS.OBS && selectedObs && !_.includes(settings.labelObs, selectedObs.name)) {
|
|
437
|
-
var _data$
|
|
438
|
-
text.push(getLabel(selectedObs, (_data$
|
|
442
|
+
var _data$values2;
|
|
443
|
+
text.push(getLabel(selectedObs, (_data$values2 = data.values) === null || _data$values2 === void 0 ? void 0 : _data$values2[index]));
|
|
439
444
|
}
|
|
440
445
|
if (settings.colorEncoding === COLOR_ENCODINGS.VAR && settings.selectedVar) {
|
|
441
|
-
var _data$
|
|
442
|
-
text.push(getLabel(settings.selectedVar, (_data$
|
|
446
|
+
var _data$values3;
|
|
447
|
+
text.push(getLabel(settings.selectedVar, (_data$values3 = data.values) === null || _data$values3 === void 0 ? void 0 : _data$values3[index], true));
|
|
443
448
|
}
|
|
444
449
|
if (settings.labelObs.length) {
|
|
445
450
|
text.push(..._.map(labelObsData.data, (v, k) => {
|
|
446
451
|
if (!v) return;
|
|
447
452
|
const labelObs = settings.data.obs[k];
|
|
448
|
-
return getLabel(labelObs, v[
|
|
453
|
+
return getLabel(labelObs, v[index]);
|
|
449
454
|
}));
|
|
450
455
|
}
|
|
451
456
|
if (!text.length) return;
|
|
452
|
-
const grayOut =
|
|
457
|
+
const grayOut = obsIndices && !obsIndices.has(index);
|
|
453
458
|
return {
|
|
454
459
|
text: text.length ? _.compact(text).join('\n') : null,
|
|
455
460
|
className: grayOut ? 'tooltip-grayout' : 'deck-tooltip',
|
|
@@ -467,7 +472,7 @@ export function Scatterplot(_ref) {
|
|
|
467
472
|
return /*#__PURE__*/_jsx(PlotAlert, {
|
|
468
473
|
variant: "info",
|
|
469
474
|
heading: "Scatterplot unavailable for this dataset",
|
|
470
|
-
plotType:
|
|
475
|
+
plotType: PLOT_TYPES.SCATTERPLOT,
|
|
471
476
|
setPlotType: setPlotType,
|
|
472
477
|
children: "This dataset does not include any embeddings, so a scatterplot cannot be displayed. Please choose a different plot type to explore the data."
|
|
473
478
|
});
|
|
@@ -491,22 +496,14 @@ export function Scatterplot(_ref) {
|
|
|
491
496
|
setIsRendering(false);
|
|
492
497
|
},
|
|
493
498
|
useDevicePixels: false,
|
|
494
|
-
|
|
499
|
+
getCursor: _ref6 => {
|
|
495
500
|
let {
|
|
496
|
-
|
|
497
|
-
|
|
501
|
+
isDragging,
|
|
502
|
+
isHovering
|
|
498
503
|
} = _ref6;
|
|
499
|
-
const active = pointInteractionEnabled && !!object;
|
|
500
|
-
setHoveredIndex(active ? index : null);
|
|
501
|
-
setIsHoveringPoint(active);
|
|
502
|
-
},
|
|
503
|
-
getCursor: _ref7 => {
|
|
504
|
-
let {
|
|
505
|
-
isDragging
|
|
506
|
-
} = _ref7;
|
|
507
504
|
if (mode !== ViewMode) return 'crosshair';
|
|
508
505
|
if (isDragging) return 'grabbing';
|
|
509
|
-
if (
|
|
506
|
+
if (isHovering && pointInteractionEnabled) return 'pointer';
|
|
510
507
|
return 'grab';
|
|
511
508
|
},
|
|
512
509
|
ref: deckRef
|
|
@@ -525,7 +522,8 @@ export function Scatterplot(_ref) {
|
|
|
525
522
|
})),
|
|
526
523
|
setShowCategories: setShowCategories,
|
|
527
524
|
setShowSearch: setShowSearch,
|
|
528
|
-
isFullscreen: isFullscreen
|
|
525
|
+
isFullscreen: isFullscreen,
|
|
526
|
+
isSearchObs: isSearchObs
|
|
529
527
|
}), /*#__PURE__*/_jsxs("div", {
|
|
530
528
|
className: "cherita-spatial-footer",
|
|
531
529
|
children: [/*#__PURE__*/_jsxs("div", {
|
|
@@ -542,7 +540,7 @@ export function Scatterplot(_ref) {
|
|
|
542
540
|
})]
|
|
543
541
|
}), /*#__PURE__*/_jsx(Toolbox, {
|
|
544
542
|
mode: settings.colorEncoding === COLOR_ENCODINGS.VAR ? (_settings$selectedVar = settings.selectedVar) === null || _settings$selectedVar === void 0 ? void 0 : _settings$selectedVar.name : settings.colorEncoding === COLOR_ENCODINGS.OBS ? selectedObs === null || selectedObs === void 0 ? void 0 : selectedObs.name : null,
|
|
545
|
-
obsLength: parseInt((_data$
|
|
543
|
+
obsLength: parseInt((_data$positions6 = data.positions) === null || _data$positions6 === void 0 ? void 0 : _data$positions6.length),
|
|
546
544
|
slicedLength: parseInt(slicedLength),
|
|
547
545
|
setHasObsm: setHasObsm
|
|
548
546
|
})]
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
2
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
3
|
+
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
|
|
4
|
+
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
|
|
5
|
+
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
6
|
+
import { Texture2D } from '@luma.gl/core';
|
|
7
|
+
import { ScatterplotLayer as BaseLayer } from 'deck.gl';
|
|
8
|
+
import { GRAY, GRAY_ALPHA, GRAY_MIX } from '../../constants/constants';
|
|
9
|
+
export class ScatterplotLayer extends BaseLayer {
|
|
10
|
+
getShaders() {
|
|
11
|
+
const shaders = super.getShaders();
|
|
12
|
+
return _objectSpread(_objectSpread({}, shaders), {}, {
|
|
13
|
+
inject: {
|
|
14
|
+
'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 ",
|
|
15
|
+
// add z-axis position based on sortValue, zMin, and zMax
|
|
16
|
+
// to draw higher sortValue points above lower sortValue points
|
|
17
|
+
// and picked points at the front
|
|
18
|
+
'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 ",
|
|
19
|
+
// increase point size for hovered points
|
|
20
|
+
'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 ",
|
|
21
|
+
// Pass colorValue to fragment shader
|
|
22
|
+
'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 ",
|
|
23
|
+
'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 ",
|
|
24
|
+
// Sample color from texture in fragment shader
|
|
25
|
+
'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 "
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
initializeState() {
|
|
30
|
+
super.initializeState();
|
|
31
|
+
this.getAttributeManager().addInstanced({
|
|
32
|
+
value: {
|
|
33
|
+
size: 1,
|
|
34
|
+
accessor: 'getValues',
|
|
35
|
+
defaultValue: 0.0
|
|
36
|
+
},
|
|
37
|
+
indexEnabled: {
|
|
38
|
+
size: 1,
|
|
39
|
+
accessor: 'getEnabled',
|
|
40
|
+
defaultValue: 1.0
|
|
41
|
+
},
|
|
42
|
+
instanceIndex: {
|
|
43
|
+
size: 1,
|
|
44
|
+
accessor: (_, _ref) => {
|
|
45
|
+
let {
|
|
46
|
+
index
|
|
47
|
+
} = _ref;
|
|
48
|
+
return index;
|
|
49
|
+
},
|
|
50
|
+
defaultValue: 0
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
updateState(params) {
|
|
55
|
+
super.updateState(params);
|
|
56
|
+
const {
|
|
57
|
+
props,
|
|
58
|
+
oldProps,
|
|
59
|
+
changeFlags
|
|
60
|
+
} = params;
|
|
61
|
+
if (props.colormap !== oldProps.colormap || changeFlags.extensionsChanged) {
|
|
62
|
+
this._updateColorTexture(props.colormap);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
_updateColorTexture(colormap) {
|
|
66
|
+
const {
|
|
67
|
+
gl
|
|
68
|
+
} = this.context;
|
|
69
|
+
|
|
70
|
+
// colormap is an array of hex strings
|
|
71
|
+
const colors = colormap.flatMap(hex => {
|
|
72
|
+
const r = parseInt(hex.slice(1, 3), 16);
|
|
73
|
+
const g = parseInt(hex.slice(3, 5), 16);
|
|
74
|
+
const b = parseInt(hex.slice(5, 7), 16);
|
|
75
|
+
const a = parseInt(hex.slice(7, 9) || 'ff', 16);
|
|
76
|
+
return [r, g, b, a];
|
|
77
|
+
});
|
|
78
|
+
if (this.state.colorTexture) {
|
|
79
|
+
this.state.colorTexture.delete();
|
|
80
|
+
}
|
|
81
|
+
const texture = new Texture2D(gl, {
|
|
82
|
+
data: new Uint8Array(colors),
|
|
83
|
+
width: colormap === null || colormap === void 0 ? void 0 : colormap.length,
|
|
84
|
+
height: 1,
|
|
85
|
+
format: gl.RGBA,
|
|
86
|
+
type: gl.UNSIGNED_BYTE,
|
|
87
|
+
parameters: {
|
|
88
|
+
[gl.TEXTURE_MIN_FILTER]: gl.LINEAR,
|
|
89
|
+
[gl.TEXTURE_MAG_FILTER]: gl.LINEAR,
|
|
90
|
+
[gl.TEXTURE_WRAP_S]: gl.CLAMP_TO_EDGE,
|
|
91
|
+
[gl.TEXTURE_WRAP_T]: gl.CLAMP_TO_EDGE
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
this.setState({
|
|
95
|
+
colorTexture: texture
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
draw(params) {
|
|
99
|
+
var _this$props$colormap$, _this$props$colormap;
|
|
100
|
+
const {
|
|
101
|
+
highlightMultiplier = 1.0,
|
|
102
|
+
isCategorical = false,
|
|
103
|
+
valueMin = 0,
|
|
104
|
+
valueMax = 0,
|
|
105
|
+
pointInteractionEnabled = false,
|
|
106
|
+
selectedIndex = -1,
|
|
107
|
+
gray = [...GRAY, 255 * GRAY_ALPHA],
|
|
108
|
+
grayMix = GRAY_MIX
|
|
109
|
+
} = this.props;
|
|
110
|
+
const {
|
|
111
|
+
colorTexture
|
|
112
|
+
} = this.state;
|
|
113
|
+
const model = this.state.model;
|
|
114
|
+
if (!model) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
model.setUniforms({
|
|
118
|
+
highlightMultiplier,
|
|
119
|
+
colorTexture: colorTexture || null,
|
|
120
|
+
useTexture: !!colorTexture,
|
|
121
|
+
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,
|
|
122
|
+
isCategorical,
|
|
123
|
+
valueMin: isNaN(valueMin) ? 0 : valueMin,
|
|
124
|
+
valueMax: isNaN(valueMax) ? 0 : valueMax,
|
|
125
|
+
pointInteractionEnabled,
|
|
126
|
+
selectedIndex,
|
|
127
|
+
gray,
|
|
128
|
+
grayMix
|
|
129
|
+
});
|
|
130
|
+
super.draw(params);
|
|
131
|
+
}
|
|
132
|
+
finalizeState(context) {
|
|
133
|
+
var _this$state$colorText;
|
|
134
|
+
super.finalizeState(context);
|
|
135
|
+
(_this$state$colorText = this.state.colorTexture) === null || _this$state$colorText === void 0 || _this$state$colorText.delete();
|
|
136
|
+
}
|
|
137
|
+
}
|
|
@@ -8,6 +8,7 @@ import Button from 'react-bootstrap/Button';
|
|
|
8
8
|
import ButtonGroup from 'react-bootstrap/ButtonGroup';
|
|
9
9
|
import Dropdown from 'react-bootstrap/Dropdown';
|
|
10
10
|
import { ScatterplotControls } from './ScatterplotControls';
|
|
11
|
+
import { useDataset } from '../../context/DatasetContext';
|
|
11
12
|
import { useSettings, useSettingsDispatch } from '../../context/SettingsContext';
|
|
12
13
|
import usePlotVisibility from '../../utils/usePlotVisibility';
|
|
13
14
|
import { OffcanvasControls } from '../offcanvas/OffCanvas';
|
|
@@ -25,8 +26,10 @@ export function SpatialControls(_ref) {
|
|
|
25
26
|
decreaseZoom,
|
|
26
27
|
setShowCategories,
|
|
27
28
|
setShowSearch,
|
|
28
|
-
isFullscreen
|
|
29
|
+
isFullscreen,
|
|
30
|
+
isSearchObs = false
|
|
29
31
|
} = _ref;
|
|
32
|
+
const dataset = useDataset();
|
|
30
33
|
const settings = useSettings();
|
|
31
34
|
const dispatch = useSettingsDispatch();
|
|
32
35
|
const [showControls, setShowControls] = useState(false);
|
|
@@ -106,7 +109,7 @@ export function SpatialControls(_ref) {
|
|
|
106
109
|
placement: "right",
|
|
107
110
|
overlay: /*#__PURE__*/_jsx(Tooltip, {
|
|
108
111
|
id: "tooltip-obs",
|
|
109
|
-
children: "
|
|
112
|
+
children: "Explore categories"
|
|
110
113
|
}),
|
|
111
114
|
children: /*#__PURE__*/_jsx(Button, {
|
|
112
115
|
size: isCompact && 'sm',
|
|
@@ -117,9 +120,9 @@ export function SpatialControls(_ref) {
|
|
|
117
120
|
})
|
|
118
121
|
}), showSearchBtn && /*#__PURE__*/_jsx(OverlayTrigger, {
|
|
119
122
|
placement: "right",
|
|
120
|
-
overlay: /*#__PURE__*/
|
|
123
|
+
overlay: /*#__PURE__*/_jsxs(Tooltip, {
|
|
121
124
|
id: "tooltip-vars",
|
|
122
|
-
children: "Search
|
|
125
|
+
children: ["Search", ' ', isSearchObs ? dataset.obsLabel.plural : dataset.varLabel.plural]
|
|
123
126
|
}),
|
|
124
127
|
children: /*#__PURE__*/_jsx(Button, {
|
|
125
128
|
size: isCompact && 'sm',
|