@vitessce/scatterplot-gating 3.7.1 → 3.8.1
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/{deflate-DBNG5DrN.js → deflate-BKZQ1leu.js} +1 -1
- package/dist/{index-CQUIaH69.js → index-BtZNxZ-h.js} +85 -44
- package/dist/index.js +1 -1
- package/dist/{jpeg-CdsXFHlP.js → jpeg-DVC1608-.js} +1 -1
- package/dist/{lerc-BI9jJUb4.js → lerc-DNyzMqIs.js} +1 -1
- package/dist/{lzw-C40QIo-x.js → lzw-UI7yv_i_.js} +1 -1
- package/dist/{packbits-DuTPSgqu.js → packbits-9luiYC71.js} +1 -1
- package/dist/{raw-9dT3xwhD.js → raw-CPZ15kc6.js} +1 -1
- package/dist/{webimage-DCRfoRZ7.js → webimage-D6ZE7-4c.js} +1 -1
- package/dist-tsc/GatingScatterplotOptions.d.ts.map +1 -1
- package/dist-tsc/GatingScatterplotOptions.js +15 -24
- package/dist-tsc/GatingSubscriber.d.ts.map +1 -1
- package/dist-tsc/GatingSubscriber.js +27 -14
- package/package.json +9 -9
- package/src/GatingScatterplotOptions.js +45 -25
- package/src/GatingSubscriber.js +38 -12
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { i as inflate_1 } from "./pako.esm-SxljTded.js";
|
|
2
|
-
import { B as BaseDecoder } from "./index-
|
|
2
|
+
import { B as BaseDecoder } from "./index-BtZNxZ-h.js";
|
|
3
3
|
class DeflateDecoder extends BaseDecoder {
|
|
4
4
|
decodeBlock(buffer) {
|
|
5
5
|
return inflate_1(new Uint8Array(buffer)).buffer;
|
|
@@ -4,7 +4,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
4
4
|
var _a2, _b;
|
|
5
5
|
import * as React from "react";
|
|
6
6
|
import React__default, { useLayoutEffect, useEffect, cloneElement, createElement, forwardRef, useState, useRef, useMemo, useImperativeHandle, useContext, createContext, isValidElement, Children, PureComponent, useCallback } from "react";
|
|
7
|
-
import { usePlotOptionsStyles, OptionsContainer, CellColorEncodingOption, OptionSelect, useVitessceContainer, useComponentHover, useComponentViewInfo, useLoaders, useCoordinationScopes, useSetComponentHover, useSetComponentViewInfo, useCoordination, useDeckCanvasSize, useObsSetsData, useFeatureSelection, useObsFeatureMatrixIndices, useReady, useUrls, useUint8FeatureSelection, useExpressionValueGetter, TitleInfo } from "@vitessce/vit-s";
|
|
7
|
+
import { usePlotOptionsStyles, OptionsContainer, CellColorEncodingOption, OptionSelect, useVitessceContainer, useComponentHover, useComponentViewInfo, useLoaders, useCoordinationScopes, useSetComponentHover, useSetComponentViewInfo, useCoordination, useInitialCoordination, useDeckCanvasSize, useObsSetsData, useFeatureSelection, useObsFeatureMatrixIndices, useReady, useUrls, useUint8FeatureSelection, useExpressionValueGetter, TitleInfo } from "@vitessce/vit-s";
|
|
8
8
|
import * as ReactDOM from "react-dom";
|
|
9
9
|
import ReactDOM__default from "react-dom";
|
|
10
10
|
function _mergeNamespaces(n2, m2) {
|
|
@@ -9492,6 +9492,7 @@ const ViewType$1 = {
|
|
|
9492
9492
|
SCATTERPLOT: "scatterplot",
|
|
9493
9493
|
SPATIAL: "spatial",
|
|
9494
9494
|
SPATIAL_BETA: "spatialBeta",
|
|
9495
|
+
// SPATIAL_ACCELERATED: 'spatialAccelerated',
|
|
9495
9496
|
HEATMAP: "heatmap",
|
|
9496
9497
|
LAYER_CONTROLLER: "layerController",
|
|
9497
9498
|
LAYER_CONTROLLER_BETA: "layerControllerBeta",
|
|
@@ -9785,6 +9786,8 @@ const CoordinationType$1 = {
|
|
|
9785
9786
|
// Could be per-image-layer
|
|
9786
9787
|
SPATIAL_TARGET_RESOLUTION: "spatialTargetResolution",
|
|
9787
9788
|
// Per-spatial-layer
|
|
9789
|
+
SPATIAL_MAX_RESOLUTION: "spatialMaxResolution",
|
|
9790
|
+
// Per-image-channel (for spatial-accelerated)
|
|
9788
9791
|
// For clipping plane sliders
|
|
9789
9792
|
SPATIAL_SLICE_X: "spatialSliceX",
|
|
9790
9793
|
SPATIAL_SLICE_Y: "spatialSliceY",
|
|
@@ -10333,6 +10336,7 @@ const COMPONENT_COORDINATION_TYPES = {
|
|
|
10333
10336
|
CoordinationType$1.SPATIAL_RENDERING_MODE,
|
|
10334
10337
|
CoordinationType$1.VOLUMETRIC_RENDERING_ALGORITHM,
|
|
10335
10338
|
CoordinationType$1.SPATIAL_TARGET_RESOLUTION,
|
|
10339
|
+
CoordinationType$1.SPATIAL_MAX_RESOLUTION,
|
|
10336
10340
|
CoordinationType$1.SPATIAL_SLICE_X,
|
|
10337
10341
|
CoordinationType$1.SPATIAL_SLICE_Y,
|
|
10338
10342
|
CoordinationType$1.SPATIAL_SLICE_Z,
|
|
@@ -10506,6 +10510,7 @@ const COMPONENT_COORDINATION_TYPES = {
|
|
|
10506
10510
|
CoordinationType$1.SPATIAL_RENDERING_MODE,
|
|
10507
10511
|
CoordinationType$1.VOLUMETRIC_RENDERING_ALGORITHM,
|
|
10508
10512
|
CoordinationType$1.SPATIAL_TARGET_RESOLUTION,
|
|
10513
|
+
CoordinationType$1.SPATIAL_MAX_RESOLUTION,
|
|
10509
10514
|
CoordinationType$1.SPATIAL_SLICE_X,
|
|
10510
10515
|
CoordinationType$1.SPATIAL_SLICE_Y,
|
|
10511
10516
|
CoordinationType$1.SPATIAL_SLICE_Z,
|
|
@@ -123124,22 +123129,22 @@ function addDecoder(cases, importFn) {
|
|
|
123124
123129
|
}
|
|
123125
123130
|
cases.forEach((c2) => registry$1.set(c2, importFn));
|
|
123126
123131
|
}
|
|
123127
|
-
addDecoder([void 0, 1], () => import("./raw-
|
|
123128
|
-
addDecoder(5, () => import("./lzw-
|
|
123132
|
+
addDecoder([void 0, 1], () => import("./raw-CPZ15kc6.js").then((m2) => m2.default));
|
|
123133
|
+
addDecoder(5, () => import("./lzw-UI7yv_i_.js").then((m2) => m2.default));
|
|
123129
123134
|
addDecoder(6, () => {
|
|
123130
123135
|
throw new Error("old style JPEG compression is not supported.");
|
|
123131
123136
|
});
|
|
123132
|
-
addDecoder(7, () => import("./jpeg-
|
|
123133
|
-
addDecoder([8, 32946], () => import("./deflate-
|
|
123134
|
-
addDecoder(32773, () => import("./packbits-
|
|
123137
|
+
addDecoder(7, () => import("./jpeg-DVC1608-.js").then((m2) => m2.default));
|
|
123138
|
+
addDecoder([8, 32946], () => import("./deflate-BKZQ1leu.js").then((m2) => m2.default));
|
|
123139
|
+
addDecoder(32773, () => import("./packbits-9luiYC71.js").then((m2) => m2.default));
|
|
123135
123140
|
addDecoder(
|
|
123136
123141
|
34887,
|
|
123137
|
-
() => import("./lerc-
|
|
123142
|
+
() => import("./lerc-DNyzMqIs.js").then(async (m2) => {
|
|
123138
123143
|
await m2.zstd.init();
|
|
123139
123144
|
return m2;
|
|
123140
123145
|
}).then((m2) => m2.default)
|
|
123141
123146
|
);
|
|
123142
|
-
addDecoder(50001, () => import("./webimage-
|
|
123147
|
+
addDecoder(50001, () => import("./webimage-D6ZE7-4c.js").then((m2) => m2.default));
|
|
123143
123148
|
function decodeRowAcc(row, stride) {
|
|
123144
123149
|
let length2 = row.length - stride;
|
|
123145
123150
|
let offset2 = 0;
|
|
@@ -158134,13 +158139,13 @@ function IconButton(props) {
|
|
|
158134
158139
|
function ToolMenu(props) {
|
|
158135
158140
|
const pointerIconAltText = "Pointer tool";
|
|
158136
158141
|
const lassoIconAltText = "Select lasso";
|
|
158137
|
-
const { setActiveTool, activeTool, visibleTools = { pan: true, selectLasso: true }, recenterOnClick = () => {
|
|
158142
|
+
const { setActiveTool, activeTool, visibleTools = { pan: true, selectLasso: true, recenter: true }, recenterOnClick = () => {
|
|
158138
158143
|
} } = props;
|
|
158139
158144
|
const { classes } = useStyles$2();
|
|
158140
158145
|
const onRecenterButtonCLick = () => {
|
|
158141
158146
|
recenterOnClick();
|
|
158142
158147
|
};
|
|
158143
|
-
return jsxRuntimeExports.jsxs("div", { className: classes.tool, children: [visibleTools.pan && jsxRuntimeExports.jsx(IconTool, { alt: pointerIconAltText, onClick: () => setActiveTool(null), isActive: activeTool === null, children: jsxRuntimeExports.jsx(SvgNearMe, {}) }), visibleTools.selectLasso ? jsxRuntimeExports.jsx(IconTool, { alt: lassoIconAltText, onClick: () => setActiveTool(distEs6Exports$2.SELECTION_TYPE.POLYGON), isActive: activeTool === distEs6Exports$2.SELECTION_TYPE.POLYGON, children: jsxRuntimeExports.jsx(SvgSelectionLasso, {}) }) : null, jsxRuntimeExports.jsx(IconButton, { alt: "click to recenter", onClick: () => onRecenterButtonCLick(), "aria-label": "Recenter scatterplot view", children: jsxRuntimeExports.jsx(CenterFocusStrong, {}) })] });
|
|
158148
|
+
return jsxRuntimeExports.jsxs("div", { className: classes.tool, children: [visibleTools.pan && jsxRuntimeExports.jsx(IconTool, { alt: pointerIconAltText, onClick: () => setActiveTool(null), isActive: activeTool === null, children: jsxRuntimeExports.jsx(SvgNearMe, {}) }), visibleTools.selectLasso ? jsxRuntimeExports.jsx(IconTool, { alt: lassoIconAltText, onClick: () => setActiveTool(distEs6Exports$2.SELECTION_TYPE.POLYGON), isActive: activeTool === distEs6Exports$2.SELECTION_TYPE.POLYGON, children: jsxRuntimeExports.jsx(SvgSelectionLasso, {}) }) : null, visibleTools.recenter ? jsxRuntimeExports.jsx(IconButton, { alt: "click to recenter", onClick: () => onRecenterButtonCLick(), "aria-label": "Recenter scatterplot view", children: jsxRuntimeExports.jsx(CenterFocusStrong, {}) }) : null] });
|
|
158144
158149
|
}
|
|
158145
158150
|
const getCursorWithTool = () => "crosshair";
|
|
158146
158151
|
const getCursor = (interactionState) => interactionState.isDragging ? "grabbing" : "default";
|
|
@@ -158375,7 +158380,7 @@ class AbstractSpatialOrScatterplot extends PureComponent {
|
|
|
158375
158380
|
*/
|
|
158376
158381
|
render() {
|
|
158377
158382
|
var _a3, _b2, _c, _d;
|
|
158378
|
-
const { deckRef, viewState, uuid, hideTools, orbitAxis } = this.props;
|
|
158383
|
+
const { deckRef, viewState, uuid, hideTools, hideRecenter, orbitAxis } = this.props;
|
|
158379
158384
|
const { gl, tool } = this.state;
|
|
158380
158385
|
const layers = this.getLayers();
|
|
158381
158386
|
const use3d = this.use3d();
|
|
@@ -158384,7 +158389,8 @@ class AbstractSpatialOrScatterplot extends PureComponent {
|
|
|
158384
158389
|
const useDevicePixels = !use3d && (((_b2 = (_a3 = this.obsSegmentationsData) == null ? void 0 : _a3.shape) == null ? void 0 : _b2[0]) < 1e5 || ((_d = (_c = this.obsLocationsData) == null ? void 0 : _c.shape) == null ? void 0 : _d[1]) < 1e5);
|
|
158385
158390
|
return jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx(ToolMenu, { activeTool: tool, setActiveTool: this.onToolChange, visibleTools: {
|
|
158386
158391
|
pan: showPanTool && !hideTools,
|
|
158387
|
-
selectLasso: showCellSelectionTools && !hideTools
|
|
158392
|
+
selectLasso: showCellSelectionTools && !hideTools,
|
|
158393
|
+
recenter: !hideRecenter
|
|
158388
158394
|
}, recenterOnClick: this.recenter }), jsxRuntimeExports.jsx(DeckGL, { id: `deckgl-overlay-${uuid}`, ref: deckRef, views: [
|
|
158389
158395
|
use3d ? new OrbitView({ id: "orbit", controller: true, orbitAxis }) : new OrthographicView({
|
|
158390
158396
|
id: "ortho"
|
|
@@ -159336,21 +159342,14 @@ function GatingScatterplotOptions(props) {
|
|
|
159336
159342
|
transformOptions
|
|
159337
159343
|
} = props;
|
|
159338
159344
|
const gatingScatterplotOptionsId = $bdb11010cef70236$export$f680877a34711e37();
|
|
159345
|
+
const gatingScatterplotGeneXId = $bdb11010cef70236$export$f680877a34711e37();
|
|
159346
|
+
const gatingScatterplotGeneYId = $bdb11010cef70236$export$f680877a34711e37();
|
|
159339
159347
|
const { classes } = usePlotOptionsStyles();
|
|
159340
|
-
const
|
|
159341
|
-
|
|
159342
|
-
|
|
159343
|
-
|
|
159344
|
-
|
|
159345
|
-
newValues.push(options[i2].value);
|
|
159346
|
-
}
|
|
159347
|
-
}
|
|
159348
|
-
if (newValues.length === 1 && gatingFeatureSelectionX && !gatingFeatureSelectionY && newValues[0] !== gatingFeatureSelectionX) {
|
|
159349
|
-
setGatingFeatureSelectionY(newValues[0]);
|
|
159350
|
-
} else if (newValues.length <= 2) {
|
|
159351
|
-
setGatingFeatureSelectionX(newValues[0]);
|
|
159352
|
-
setGatingFeatureSelectionY(newValues[1]);
|
|
159353
|
-
}
|
|
159348
|
+
const handleSelectionX = (event) => {
|
|
159349
|
+
setGatingFeatureSelectionX(event.target.value === "" ? null : event.target.value);
|
|
159350
|
+
};
|
|
159351
|
+
const handleSelectionY = (event) => {
|
|
159352
|
+
setGatingFeatureSelectionY(event.target.value === "" ? null : event.target.value);
|
|
159354
159353
|
};
|
|
159355
159354
|
const handleTransformChange = (event) => {
|
|
159356
159355
|
setGatingFeatureValueTransform(event.target.value === "" ? null : event.target.value);
|
|
@@ -159369,20 +159368,40 @@ function GatingScatterplotOptions(props) {
|
|
|
159369
159368
|
return /* @__PURE__ */ React__default.createElement(React__default.Fragment, null, /* @__PURE__ */ React__default.createElement(TableRow, null, /* @__PURE__ */ React__default.createElement(TableCell, { className: classes.labelCell, variant: "head", scope: "row" }, /* @__PURE__ */ React__default.createElement(
|
|
159370
159369
|
"label",
|
|
159371
159370
|
{
|
|
159372
|
-
htmlFor: `scatterplot-gating-gene-select-${
|
|
159371
|
+
htmlFor: `scatterplot-gating-gene-select-${gatingScatterplotGeneXId}`
|
|
159372
|
+
},
|
|
159373
|
+
capitalize$2(featureType),
|
|
159374
|
+
" along X"
|
|
159375
|
+
)), /* @__PURE__ */ React__default.createElement(TableCell, { className: classes.inputCell, variant: "body" }, /* @__PURE__ */ React__default.createElement(
|
|
159376
|
+
OptionSelect,
|
|
159377
|
+
{
|
|
159378
|
+
className: classes.select,
|
|
159379
|
+
value: gatingFeatureSelectionX ?? "",
|
|
159380
|
+
onChange: handleSelectionX,
|
|
159381
|
+
inputProps: {
|
|
159382
|
+
id: `scatterplot-gating-gene-select-${gatingScatterplotGeneXId}`
|
|
159383
|
+
}
|
|
159384
|
+
},
|
|
159385
|
+
/* @__PURE__ */ React__default.createElement("option", { value: "" }, "None"),
|
|
159386
|
+
geneSelectOptions.map((name2) => /* @__PURE__ */ React__default.createElement("option", { key: name2, value: name2 }, name2))
|
|
159387
|
+
))), /* @__PURE__ */ React__default.createElement(TableRow, null, /* @__PURE__ */ React__default.createElement(TableCell, { className: classes.labelCell, variant: "head", scope: "row" }, /* @__PURE__ */ React__default.createElement(
|
|
159388
|
+
"label",
|
|
159389
|
+
{
|
|
159390
|
+
htmlFor: `scatterplot-gating-gene-select-${gatingScatterplotGeneYId}`
|
|
159373
159391
|
},
|
|
159374
|
-
capitalize$2(
|
|
159392
|
+
capitalize$2(featureType),
|
|
159393
|
+
" along Y"
|
|
159375
159394
|
)), /* @__PURE__ */ React__default.createElement(TableCell, { className: classes.inputCell, variant: "body" }, /* @__PURE__ */ React__default.createElement(
|
|
159376
159395
|
OptionSelect,
|
|
159377
159396
|
{
|
|
159378
|
-
multiple: true,
|
|
159379
159397
|
className: classes.select,
|
|
159380
|
-
value:
|
|
159381
|
-
onChange:
|
|
159398
|
+
value: gatingFeatureSelectionY ?? "",
|
|
159399
|
+
onChange: handleSelectionY,
|
|
159382
159400
|
inputProps: {
|
|
159383
|
-
id: `scatterplot-gating-gene-select-${
|
|
159401
|
+
id: `scatterplot-gating-gene-select-${gatingScatterplotGeneYId}`
|
|
159384
159402
|
}
|
|
159385
159403
|
},
|
|
159404
|
+
/* @__PURE__ */ React__default.createElement("option", { value: "" }, "None"),
|
|
159386
159405
|
geneSelectOptions.map((name2) => /* @__PURE__ */ React__default.createElement("option", { key: name2, value: name2 }, name2))
|
|
159387
159406
|
))), /* @__PURE__ */ React__default.createElement(TableRow, null, /* @__PURE__ */ React__default.createElement(TableCell, { className: classes.labelCell, variant: "head", scope: "row" }, /* @__PURE__ */ React__default.createElement(
|
|
159388
159407
|
"label",
|
|
@@ -159414,7 +159433,7 @@ function GatingScatterplotOptions(props) {
|
|
|
159414
159433
|
type: "number",
|
|
159415
159434
|
onChange: handleTransformCoefficientChange,
|
|
159416
159435
|
value: gatingFeatureValueTransformCoefficient,
|
|
159417
|
-
slotProps: {
|
|
159436
|
+
slotProps: { inputLabel: { shrink: true } },
|
|
159418
159437
|
id: `scatterplot-gating-transform-coefficient-${gatingScatterplotOptionsId}`
|
|
159419
159438
|
}
|
|
159420
159439
|
))));
|
|
@@ -159494,6 +159513,14 @@ function GatingSubscriber(props) {
|
|
|
159494
159513
|
COMPONENT_COORDINATION_TYPES[ViewType$1.GATING],
|
|
159495
159514
|
coordinationScopes
|
|
159496
159515
|
);
|
|
159516
|
+
const {
|
|
159517
|
+
embeddingZoom: initialZoom,
|
|
159518
|
+
embeddingTargetX: initialTargetX,
|
|
159519
|
+
embeddingTargetY: initialTargetY
|
|
159520
|
+
} = useInitialCoordination(
|
|
159521
|
+
COMPONENT_COORDINATION_TYPES[ViewType$1.GATING],
|
|
159522
|
+
coordinationScopes
|
|
159523
|
+
);
|
|
159497
159524
|
const [width2, height2, deckRef] = useDeckCanvasSize();
|
|
159498
159525
|
const title = useMemo(() => {
|
|
159499
159526
|
if (titleOverride) {
|
|
@@ -159617,6 +159644,7 @@ function GatingSubscriber(props) {
|
|
|
159617
159644
|
]);
|
|
159618
159645
|
const [dynamicCellRadius, setDynamicCellRadius] = useState(cellRadiusFixed);
|
|
159619
159646
|
const [dynamicCellOpacity, setDynamicCellOpacity] = useState(cellOpacityFixed);
|
|
159647
|
+
const [originalViewState, setOriginalViewState] = useState(null);
|
|
159620
159648
|
const mergedCellSets = useMemo(() => mergeObsSets(
|
|
159621
159649
|
cellSets,
|
|
159622
159650
|
additionalCellSets
|
|
@@ -159717,13 +159745,20 @@ function GatingSubscriber(props) {
|
|
|
159717
159745
|
averageFillDensity
|
|
159718
159746
|
);
|
|
159719
159747
|
setDynamicCellOpacity(nextCellOpacityScale);
|
|
159720
|
-
if (typeof
|
|
159748
|
+
if (typeof initialTargetX !== "number" || typeof initialTargetY !== "number") {
|
|
159721
159749
|
const newTargetX = xExtent[0] + xRange / 2;
|
|
159722
159750
|
const newTargetY = yExtent[0] + yRange / 2;
|
|
159723
159751
|
const newZoom = Math.log2(Math.min(width2 / xRange, height2 / yRange));
|
|
159724
|
-
|
|
159725
|
-
|
|
159726
|
-
|
|
159752
|
+
const notYetInitialized = typeof targetX !== "number" || typeof targetY !== "number";
|
|
159753
|
+
const stillDefaultInitialized = targetX === newTargetX && targetY === -newTargetY;
|
|
159754
|
+
if (notYetInitialized || stillDefaultInitialized) {
|
|
159755
|
+
setTargetX(newTargetX);
|
|
159756
|
+
setTargetY(-newTargetY);
|
|
159757
|
+
setZoom(newZoom);
|
|
159758
|
+
}
|
|
159759
|
+
setOriginalViewState({ target: [newTargetX, -newTargetY, 0], zoom: newZoom });
|
|
159760
|
+
} else if (!originalViewState) {
|
|
159761
|
+
setOriginalViewState({ target: [initialTargetX, initialTargetY, 0], zoom: initialZoom });
|
|
159727
159762
|
}
|
|
159728
159763
|
}
|
|
159729
159764
|
}, [
|
|
@@ -159735,6 +159770,8 @@ function GatingSubscriber(props) {
|
|
|
159735
159770
|
width2,
|
|
159736
159771
|
height2,
|
|
159737
159772
|
zoom,
|
|
159773
|
+
initialTargetX,
|
|
159774
|
+
initialTargetY,
|
|
159738
159775
|
averageFillDensity
|
|
159739
159776
|
]);
|
|
159740
159777
|
const cellSelectionSet = useMemo(() => new Set(cellSelection), [cellSelection]);
|
|
@@ -159768,6 +159805,12 @@ function GatingSubscriber(props) {
|
|
|
159768
159805
|
gatingFeatureSelectionY,
|
|
159769
159806
|
obsType
|
|
159770
159807
|
]);
|
|
159808
|
+
const setViewState = ({ zoom: newZoom, target }) => {
|
|
159809
|
+
setZoom(newZoom);
|
|
159810
|
+
setTargetX(target[0]);
|
|
159811
|
+
setTargetY(target[1]);
|
|
159812
|
+
setTargetZ(target[2] || 0);
|
|
159813
|
+
};
|
|
159771
159814
|
return /* @__PURE__ */ React__default.createElement(
|
|
159772
159815
|
TitleInfo,
|
|
159773
159816
|
{
|
|
@@ -159843,13 +159886,10 @@ function GatingSubscriber(props) {
|
|
|
159843
159886
|
uuid,
|
|
159844
159887
|
theme,
|
|
159845
159888
|
hideTools: !(gatingFeatureSelectionX && gatingFeatureSelectionY),
|
|
159889
|
+
hideRecenter: !(gatingFeatureSelectionX && gatingFeatureSelectionY),
|
|
159846
159890
|
viewState: { zoom, target: [targetX, targetY, targetZ] },
|
|
159847
|
-
setViewState
|
|
159848
|
-
|
|
159849
|
-
setTargetX(target[0]);
|
|
159850
|
-
setTargetY(target[1]);
|
|
159851
|
-
setTargetZ(target[2] || 0);
|
|
159852
|
-
},
|
|
159891
|
+
setViewState,
|
|
159892
|
+
originalViewState,
|
|
159853
159893
|
obsEmbeddingIndex: obsIndex,
|
|
159854
159894
|
obsEmbedding: obsXY,
|
|
159855
159895
|
cellFilter,
|
|
@@ -159873,7 +159913,8 @@ function GatingSubscriber(props) {
|
|
|
159873
159913
|
},
|
|
159874
159914
|
updateViewInfo: setComponentViewInfo,
|
|
159875
159915
|
getExpressionValue,
|
|
159876
|
-
getCellIsSelected
|
|
159916
|
+
getCellIsSelected,
|
|
159917
|
+
embeddingPointsVisible: true
|
|
159877
159918
|
}
|
|
159878
159919
|
),
|
|
159879
159920
|
!disableTooltip && /* @__PURE__ */ React__default.createElement(
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { i as inflate_1 } from "./pako.esm-SxljTded.js";
|
|
2
|
-
import { g as getDefaultExportFromCjs, B as BaseDecoder } from "./index-
|
|
2
|
+
import { g as getDefaultExportFromCjs, B as BaseDecoder } from "./index-BtZNxZ-h.js";
|
|
3
3
|
const LercParameters = {
|
|
4
4
|
AddCompression: 1
|
|
5
5
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GatingScatterplotOptions.d.ts","sourceRoot":"","sources":["../src/GatingScatterplotOptions.js"],"names":[],"mappings":"AAMA,
|
|
1
|
+
{"version":3,"file":"GatingScatterplotOptions.d.ts","sourceRoot":"","sources":["../src/GatingScatterplotOptions.js"],"names":[],"mappings":"AAMA,0EAwJC"}
|
|
@@ -1,32 +1,21 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import { useId } from 'react-aria';
|
|
4
4
|
import { TableCell, TableRow, TextField } from '@vitessce/styles';
|
|
5
5
|
import { usePlotOptionsStyles, OptionSelect } from '@vitessce/vit-s';
|
|
6
|
-
import { capitalize
|
|
6
|
+
import { capitalize } from '@vitessce/utils';
|
|
7
7
|
export default function GatingScatterplotOptions(props) {
|
|
8
8
|
const { featureType, gatingFeatureSelectionX, setGatingFeatureSelectionX, gatingFeatureSelectionY, setGatingFeatureSelectionY, gatingFeatureValueTransform, setGatingFeatureValueTransform, gatingFeatureValueTransformCoefficient, setGatingFeatureValueTransformCoefficient, geneSelectOptions, transformOptions, } = props;
|
|
9
9
|
const gatingScatterplotOptionsId = useId();
|
|
10
|
+
const gatingScatterplotGeneXId = useId();
|
|
11
|
+
const gatingScatterplotGeneYId = useId();
|
|
10
12
|
const { classes } = usePlotOptionsStyles();
|
|
11
13
|
// Handlers for custom option field changes.
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
newValues.push(options[i].value);
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
if (newValues.length === 1
|
|
21
|
-
&& gatingFeatureSelectionX
|
|
22
|
-
&& !gatingFeatureSelectionY
|
|
23
|
-
&& newValues[0] !== gatingFeatureSelectionX) {
|
|
24
|
-
setGatingFeatureSelectionY(newValues[0]);
|
|
25
|
-
}
|
|
26
|
-
else if (newValues.length <= 2) {
|
|
27
|
-
setGatingFeatureSelectionX(newValues[0]);
|
|
28
|
-
setGatingFeatureSelectionY(newValues[1]);
|
|
29
|
-
}
|
|
14
|
+
const handleSelectionX = (event) => {
|
|
15
|
+
setGatingFeatureSelectionX(event.target.value === '' ? null : event.target.value);
|
|
16
|
+
};
|
|
17
|
+
const handleSelectionY = (event) => {
|
|
18
|
+
setGatingFeatureSelectionY(event.target.value === '' ? null : event.target.value);
|
|
30
19
|
};
|
|
31
20
|
const handleTransformChange = (event) => {
|
|
32
21
|
setGatingFeatureValueTransform(event.target.value === '' ? null : event.target.value);
|
|
@@ -45,9 +34,11 @@ export default function GatingScatterplotOptions(props) {
|
|
|
45
34
|
}
|
|
46
35
|
}
|
|
47
36
|
};
|
|
48
|
-
return (_jsxs(_Fragment, { children: [_jsxs(TableRow, { children: [_jsx(TableCell, { className: classes.labelCell, variant: "head", scope: "row", children:
|
|
49
|
-
id: `scatterplot-gating-gene-select-${
|
|
50
|
-
}, children: geneSelectOptions.map(name => (_jsx("option", { value: name, children: name }, name))) }) })] }), _jsxs(TableRow, { children: [_jsx(TableCell, { className: classes.labelCell, variant: "head", scope: "row", children:
|
|
37
|
+
return (_jsxs(_Fragment, { children: [_jsxs(TableRow, { children: [_jsx(TableCell, { className: classes.labelCell, variant: "head", scope: "row", children: _jsxs("label", { htmlFor: `scatterplot-gating-gene-select-${gatingScatterplotGeneXId}`, children: [capitalize(featureType), " along X"] }) }), _jsx(TableCell, { className: classes.inputCell, variant: "body", children: _jsxs(OptionSelect, { className: classes.select, value: gatingFeatureSelectionX ?? '', onChange: handleSelectionX, inputProps: {
|
|
38
|
+
id: `scatterplot-gating-gene-select-${gatingScatterplotGeneXId}`,
|
|
39
|
+
}, children: [_jsx("option", { value: "", children: "None" }), geneSelectOptions.map(name => (_jsx("option", { value: name, children: name }, name)))] }) })] }), _jsxs(TableRow, { children: [_jsx(TableCell, { className: classes.labelCell, variant: "head", scope: "row", children: _jsxs("label", { htmlFor: `scatterplot-gating-gene-select-${gatingScatterplotGeneYId}`, children: [capitalize(featureType), " along Y"] }) }), _jsx(TableCell, { className: classes.inputCell, variant: "body", children: _jsxs(OptionSelect, { className: classes.select, value: gatingFeatureSelectionY ?? '', onChange: handleSelectionY, inputProps: {
|
|
40
|
+
id: `scatterplot-gating-gene-select-${gatingScatterplotGeneYId}`,
|
|
41
|
+
}, children: [_jsx("option", { value: "", children: "None" }), geneSelectOptions.map(name => (_jsx("option", { value: name, children: name }, name)))] }) })] }), _jsxs(TableRow, { children: [_jsx(TableCell, { className: classes.labelCell, variant: "head", scope: "row", children: _jsx("label", { htmlFor: `scatterplot-gating-transform-select-${gatingScatterplotOptionsId}`, children: "Transform" }) }), _jsx(TableCell, { className: classes.inputCell, variant: "body", children: _jsx(OptionSelect, { className: classes.select, value: gatingFeatureValueTransform === null ? '' : gatingFeatureValueTransform, onChange: handleTransformChange, inputProps: {
|
|
51
42
|
id: `scatterplot-gating-transform-select-${gatingScatterplotOptionsId}`,
|
|
52
|
-
}, children: transformOptions.map(opt => (_jsx("option", { value: opt.value === null ? '' : opt.value, children: opt.name }, opt.name))) }) })] }), _jsxs(TableRow, { children: [_jsx(TableCell, { className: classes.labelCell, variant: "head", scope: "row", children: _jsx("label", { htmlFor: `scatterplot-gating-transform-coefficient-${gatingScatterplotOptionsId}`, children: "Transform Coefficient" }) }), _jsx(TableCell, { className: classes.inputCell, variant: "body", children: _jsx(TextField, { label: "Transform Coefficient", type: "number", onChange: handleTransformCoefficientChange, value: gatingFeatureValueTransformCoefficient, slotProps: {
|
|
43
|
+
}, children: transformOptions.map(opt => (_jsx("option", { value: opt.value === null ? '' : opt.value, children: opt.name }, opt.name))) }) })] }), _jsxs(TableRow, { children: [_jsx(TableCell, { className: classes.labelCell, variant: "head", scope: "row", children: _jsx("label", { htmlFor: `scatterplot-gating-transform-coefficient-${gatingScatterplotOptionsId}`, children: "Transform Coefficient" }) }), _jsx(TableCell, { className: classes.inputCell, variant: "body", children: _jsx(TextField, { label: "Transform Coefficient", type: "number", onChange: handleTransformCoefficientChange, value: gatingFeatureValueTransformCoefficient, slotProps: { inputLabel: { shrink: true } }, id: `scatterplot-gating-transform-coefficient-${gatingScatterplotOptionsId}` }) })] })] }));
|
|
53
44
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GatingSubscriber.d.ts","sourceRoot":"","sources":["../src/GatingSubscriber.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"GatingSubscriber.d.ts","sourceRoot":"","sources":["../src/GatingSubscriber.js"],"names":[],"mappings":"AAqCA;;;;;;;;;;;;KAYK;AACL,wCAVK;IAAsB,IAAI,EAAlB,MAAM;IACQ,KAAK,EAAnB,MAAM;IACQ,kBAAkB,EAAhC,MAAM;IAES,cAAc,EAA7B,OAAO;IACS,mBAAmB;IAErB,kBAAkB,EAAhC,MAAM;CAEhB,eA6cF"}
|
|
@@ -3,7 +3,7 @@ import React, { useState, useEffect, useCallback, useMemo, } from 'react';
|
|
|
3
3
|
import { extent } from 'd3-array';
|
|
4
4
|
import { isEqual } from 'lodash-es';
|
|
5
5
|
import { pluralize as plur, capitalize, commaNumber, getValueTransformFunction, VALUE_TRANSFORM_OPTIONS, } from '@vitessce/utils';
|
|
6
|
-
import { TitleInfo, useDeckCanvasSize, useReady, useUrls, useUint8FeatureSelection, useExpressionValueGetter, useObsSetsData, useFeatureSelection, useObsFeatureMatrixIndices, useCoordination, useLoaders, useSetComponentHover, useSetComponentViewInfo, useCoordinationScopes, } from '@vitessce/vit-s';
|
|
6
|
+
import { TitleInfo, useDeckCanvasSize, useReady, useUrls, useUint8FeatureSelection, useExpressionValueGetter, useObsSetsData, useFeatureSelection, useObsFeatureMatrixIndices, useCoordination, useInitialCoordination, useLoaders, useSetComponentHover, useSetComponentViewInfo, useCoordinationScopes, } from '@vitessce/vit-s';
|
|
7
7
|
import { getCellSetPolygons, mergeObsSets, setObsSelection, getCellColors, } from '@vitessce/sets-utils';
|
|
8
8
|
import { Scatterplot, ScatterplotTooltipSubscriber, ScatterplotOptions, getPointSizeDevicePixels, getPointOpacity, EmptyMessage, } from '@vitessce/scatterplot';
|
|
9
9
|
import { ViewType, COMPONENT_COORDINATION_TYPES, ViewHelpMapping } from '@vitessce/constants-internal';
|
|
@@ -31,6 +31,7 @@ export function GatingSubscriber(props) {
|
|
|
31
31
|
const setComponentViewInfo = useSetComponentViewInfo(uuid);
|
|
32
32
|
// Get "props" from the coordination space.
|
|
33
33
|
const [{ dataset, obsType, featureType, featureValueType, embeddingZoom: zoom, embeddingTargetX: targetX, embeddingTargetY: targetY, embeddingTargetZ: targetZ, obsFilter: cellFilter, obsHighlight: cellHighlight, obsSetSelection: cellSetSelection, obsSetColor: cellSetColor, obsColorEncoding: cellColorEncoding, additionalObsSets: additionalCellSets, embeddingObsSetPolygonsVisible: cellSetPolygonsVisible, embeddingObsSetLabelsVisible: cellSetLabelsVisible, embeddingObsSetLabelSize: cellSetLabelSize, embeddingObsRadius: cellRadiusFixed, embeddingObsRadiusMode: cellRadiusMode, embeddingObsOpacity: cellOpacityFixed, embeddingObsOpacityMode: cellOpacityMode, featureValueColormap: geneExpressionColormap, featureValueColormapRange: geneExpressionColormapRange, featureSelection: gatingFeatureSelectionColor, featureValueTransform, featureValueTransformCoefficient, gatingFeatureSelectionX, gatingFeatureSelectionY, }, { setEmbeddingZoom: setZoom, setEmbeddingTargetX: setTargetX, setEmbeddingTargetY: setTargetY, setEmbeddingTargetZ: setTargetZ, setObsFilter: setCellFilter, setObsSetSelection: setCellSetSelection, setObsHighlight: setCellHighlight, setObsSetColor: setCellSetColor, setObsColorEncoding: setCellColorEncoding, setAdditionalObsSets: setAdditionalCellSets, setEmbeddingObsSetPolygonsVisible: setCellSetPolygonsVisible, setEmbeddingObsSetLabelsVisible: setCellSetLabelsVisible, setEmbeddingObsSetLabelSize: setCellSetLabelSize, setEmbeddingObsRadius: setCellRadiusFixed, setEmbeddingObsRadiusMode: setCellRadiusMode, setEmbeddingObsOpacity: setCellOpacityFixed, setEmbeddingObsOpacityMode: setCellOpacityMode, setFeatureValueColormap: setGeneExpressionColormap, setFeatureValueColormapRange: setGeneExpressionColormapRange, setFeatureValueTransform, setFeatureValueTransformCoefficient, setGatingFeatureSelectionX, setGatingFeatureSelectionY, }] = useCoordination(COMPONENT_COORDINATION_TYPES[ViewType.GATING], coordinationScopes);
|
|
34
|
+
const { embeddingZoom: initialZoom, embeddingTargetX: initialTargetX, embeddingTargetY: initialTargetY, } = useInitialCoordination(COMPONENT_COORDINATION_TYPES[ViewType.GATING], coordinationScopes);
|
|
34
35
|
const [width, height, deckRef] = useDeckCanvasSize();
|
|
35
36
|
const title = useMemo(() => {
|
|
36
37
|
if (titleOverride) {
|
|
@@ -105,6 +106,7 @@ export function GatingSubscriber(props) {
|
|
|
105
106
|
]);
|
|
106
107
|
const [dynamicCellRadius, setDynamicCellRadius] = useState(cellRadiusFixed);
|
|
107
108
|
const [dynamicCellOpacity, setDynamicCellOpacity] = useState(cellOpacityFixed);
|
|
109
|
+
const [originalViewState, setOriginalViewState] = useState(null);
|
|
108
110
|
const mergedCellSets = useMemo(() => mergeObsSets(cellSets, additionalCellSets), [cellSets, additionalCellSets]);
|
|
109
111
|
const setCellSelectionProp = useCallback((v) => {
|
|
110
112
|
setObsSelection(v, additionalCellSets, cellSetColor, setCellSetSelection, setAdditionalCellSets, setCellSetColor, setCellColorEncoding);
|
|
@@ -165,19 +167,29 @@ export function GatingSubscriber(props) {
|
|
|
165
167
|
setDynamicCellRadius(pointSizeDevicePixels);
|
|
166
168
|
const nextCellOpacityScale = getPointOpacity(zoom, xRange, yRange, width, height, numCells, averageFillDensity);
|
|
167
169
|
setDynamicCellOpacity(nextCellOpacityScale);
|
|
168
|
-
if (typeof
|
|
170
|
+
if (typeof initialTargetX !== 'number' || typeof initialTargetY !== 'number') {
|
|
169
171
|
const newTargetX = xExtent[0] + xRange / 2;
|
|
170
172
|
const newTargetY = yExtent[0] + yRange / 2;
|
|
171
173
|
const newZoom = Math.log2(Math.min(width / xRange, height / yRange));
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
174
|
+
const notYetInitialized = (typeof targetX !== 'number' || typeof targetY !== 'number');
|
|
175
|
+
const stillDefaultInitialized = (targetX === newTargetX && targetY === -newTargetY);
|
|
176
|
+
if (notYetInitialized || stillDefaultInitialized) {
|
|
177
|
+
setTargetX(newTargetX);
|
|
178
|
+
// Graphics rendering has the y-axis going south so we need to multiply by negative one.
|
|
179
|
+
setTargetY(-newTargetY);
|
|
180
|
+
setZoom(newZoom);
|
|
181
|
+
}
|
|
182
|
+
setOriginalViewState({ target: [newTargetX, -newTargetY, 0], zoom: newZoom });
|
|
183
|
+
}
|
|
184
|
+
else if (!originalViewState) {
|
|
185
|
+
// originalViewState has not yet been set and
|
|
186
|
+
// the view config defined an initial viewState.
|
|
187
|
+
setOriginalViewState({ target: [initialTargetX, initialTargetY, 0], zoom: initialZoom });
|
|
176
188
|
}
|
|
177
189
|
}
|
|
178
190
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
179
191
|
}, [xRange, yRange, xExtent, yExtent, numCells,
|
|
180
|
-
width, height, zoom, averageFillDensity]);
|
|
192
|
+
width, height, zoom, initialTargetX, initialTargetY, averageFillDensity]);
|
|
181
193
|
const cellSelectionSet = useMemo(() => new Set(cellSelection), [cellSelection]);
|
|
182
194
|
const getCellIsSelected = useCallback((object, { index }) => ((cellSelectionSet || new Set([])).has(obsIndex[index]) ? 1.0 : 0.0), [cellSelectionSet, obsIndex]);
|
|
183
195
|
const cellRadius = (cellRadiusMode === 'manual' ? cellRadiusFixed : dynamicCellRadius);
|
|
@@ -204,17 +216,18 @@ export function GatingSubscriber(props) {
|
|
|
204
216
|
}, [obsXY, obsIndex, featureValueTransform,
|
|
205
217
|
gatingFeatureSelectionX, gatingFeatureSelectionY, obsType,
|
|
206
218
|
]);
|
|
219
|
+
const setViewState = ({ zoom: newZoom, target }) => {
|
|
220
|
+
setZoom(newZoom);
|
|
221
|
+
setTargetX(target[0]);
|
|
222
|
+
setTargetY(target[1]);
|
|
223
|
+
setTargetZ(target[2] || 0);
|
|
224
|
+
};
|
|
207
225
|
return (_jsxs(TitleInfo, { title: title, info: `${commaNumber(cellsCount)} ${plur(obsType, cellsCount)}`, closeButtonVisible: closeButtonVisible, downloadButtonVisible: downloadButtonVisible, removeGridComponent: removeGridComponent, urls: urls, theme: theme, isReady: isReady, helpText: helpText, errors: errors, options: (_jsx(ScatterplotOptions, { observationsLabel: obsType, cellRadius: cellRadiusFixed, setCellRadius: setCellRadiusFixed, cellRadiusMode: cellRadiusMode, setCellRadiusMode: setCellRadiusMode, cellOpacity: cellOpacityFixed, setCellOpacity: setCellOpacityFixed, cellOpacityMode: cellOpacityMode, setCellOpacityMode: setCellOpacityMode, cellSetLabelsVisible: cellSetLabelsVisible, setCellSetLabelsVisible: setCellSetLabelsVisible, cellSetLabelSize: cellSetLabelSize, setCellSetLabelSize: setCellSetLabelSize, cellSetPolygonsVisible: cellSetPolygonsVisible, setCellSetPolygonsVisible: setCellSetPolygonsVisible, cellColorEncoding: cellColorEncoding, setCellColorEncoding: setCellColorEncoding, geneExpressionColormap: geneExpressionColormap, setGeneExpressionColormap: setGeneExpressionColormap, geneExpressionColormapRange: geneExpressionColormapRange, setGeneExpressionColormapRange: setGeneExpressionColormapRange, children: _jsx(GatingScatterplotOptions, { featureType: featureType, gatingFeatureSelectionX: gatingFeatureSelectionX, setGatingFeatureSelectionX: setGatingFeatureSelectionX, gatingFeatureSelectionY: gatingFeatureSelectionY, setGatingFeatureSelectionY: setGatingFeatureSelectionY, gatingFeatureValueTransform: featureValueTransform, setGatingFeatureValueTransform: (newValue) => {
|
|
208
226
|
setFeatureValueTransform(newValue);
|
|
209
227
|
setTargetX(null);
|
|
210
228
|
setTargetY(null);
|
|
211
229
|
setZoom(null);
|
|
212
|
-
}, gatingFeatureValueTransformCoefficient: featureValueTransformCoefficient, setGatingFeatureValueTransformCoefficient: setFeatureValueTransformCoefficient, geneSelectOptions: featureIndex, transformOptions: VALUE_TRANSFORM_OPTIONS }) })), children: [_jsx(EmptyMessage, { visible: !(gatingFeatureSelectionX && gatingFeatureSelectionY), message: `Select two ${plur(featureType, 2)} in the plot settings.` }), _jsx(Scatterplot, { ref: deckRef, uuid: uuid, theme: theme, hideTools: !(gatingFeatureSelectionX && gatingFeatureSelectionY), viewState: { zoom, target: [targetX, targetY, targetZ] }, setViewState:
|
|
213
|
-
setZoom(newZoom);
|
|
214
|
-
setTargetX(target[0]);
|
|
215
|
-
setTargetY(target[1]);
|
|
216
|
-
setTargetZ(target[2] || 0);
|
|
217
|
-
}, obsEmbeddingIndex: obsIndex, obsEmbedding: obsXY, cellFilter: cellFilter, cellSelection: cellSelection, cellHighlight: cellHighlight, cellColors: cellColors, cellSetPolygons: cellSetPolygons, cellSetLabelSize: cellSetLabelSize, cellSetLabelsVisible: cellSetLabelsVisible, cellSetPolygonsVisible: cellSetPolygonsVisible, setCellFilter: setCellFilter, setCellSelection: setCellSelectionProp, setCellHighlight: setCellHighlight, cellRadius: cellRadius, cellOpacity: cellOpacity, cellColorEncoding: cellColorEncoding, geneExpressionColormap: geneExpressionColormap, geneExpressionColormapRange: geneExpressionColormapRange, setComponentHover: () => {
|
|
230
|
+
}, gatingFeatureValueTransformCoefficient: featureValueTransformCoefficient, setGatingFeatureValueTransformCoefficient: setFeatureValueTransformCoefficient, geneSelectOptions: featureIndex, transformOptions: VALUE_TRANSFORM_OPTIONS }) })), children: [_jsx(EmptyMessage, { visible: !(gatingFeatureSelectionX && gatingFeatureSelectionY), message: `Select two ${plur(featureType, 2)} in the plot settings.` }), _jsx(Scatterplot, { ref: deckRef, uuid: uuid, theme: theme, hideTools: !(gatingFeatureSelectionX && gatingFeatureSelectionY), hideRecenter: !(gatingFeatureSelectionX && gatingFeatureSelectionY), viewState: { zoom, target: [targetX, targetY, targetZ] }, setViewState: setViewState, originalViewState: originalViewState, obsEmbeddingIndex: obsIndex, obsEmbedding: obsXY, cellFilter: cellFilter, cellSelection: cellSelection, cellHighlight: cellHighlight, cellColors: cellColors, cellSetPolygons: cellSetPolygons, cellSetLabelSize: cellSetLabelSize, cellSetLabelsVisible: cellSetLabelsVisible, cellSetPolygonsVisible: cellSetPolygonsVisible, setCellFilter: setCellFilter, setCellSelection: setCellSelectionProp, setCellHighlight: setCellHighlight, cellRadius: cellRadius, cellOpacity: cellOpacity, cellColorEncoding: cellColorEncoding, geneExpressionColormap: geneExpressionColormap, geneExpressionColormapRange: geneExpressionColormapRange, setComponentHover: () => {
|
|
218
231
|
setComponentHover(uuid);
|
|
219
|
-
}, updateViewInfo: setComponentViewInfo, getExpressionValue: getExpressionValue, getCellIsSelected: getCellIsSelected }), !disableTooltip && (_jsx(ScatterplotTooltipSubscriber, { parentUuid: uuid, obsHighlight: cellHighlight, width: width, height: height, getObsInfo: getObsInfo }))] }));
|
|
232
|
+
}, updateViewInfo: setComponentViewInfo, getExpressionValue: getExpressionValue, getCellIsSelected: getCellIsSelected, embeddingPointsVisible: true }), !disableTooltip && (_jsx(ScatterplotTooltipSubscriber, { parentUuid: uuid, obsHighlight: cellHighlight, width: width, height: height, getObsInfo: getObsInfo }))] }));
|
|
220
233
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vitessce/scatterplot-gating",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.8.1",
|
|
4
4
|
"author": "HIDIVE Lab at HMS",
|
|
5
5
|
"homepage": "http://vitessce.io",
|
|
6
6
|
"repository": {
|
|
@@ -19,16 +19,16 @@
|
|
|
19
19
|
"d3-array": "^2.4.0",
|
|
20
20
|
"lodash-es": "^4.17.21",
|
|
21
21
|
"react-aria": "^3.28.0",
|
|
22
|
-
"@vitessce/styles": "3.
|
|
23
|
-
"@vitessce/constants-internal": "3.
|
|
24
|
-
"@vitessce/scatterplot": "3.
|
|
25
|
-
"@vitessce/sets-utils": "3.
|
|
26
|
-
"@vitessce/
|
|
27
|
-
"@vitessce/
|
|
22
|
+
"@vitessce/styles": "3.8.1",
|
|
23
|
+
"@vitessce/constants-internal": "3.8.1",
|
|
24
|
+
"@vitessce/scatterplot": "3.8.1",
|
|
25
|
+
"@vitessce/sets-utils": "3.8.1",
|
|
26
|
+
"@vitessce/utils": "3.8.1",
|
|
27
|
+
"@vitessce/vit-s": "3.8.1"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
|
-
"react": "
|
|
31
|
-
"react-dom": "
|
|
30
|
+
"react": "18.3.1",
|
|
31
|
+
"react-dom": "18.3.1",
|
|
32
32
|
"vite": "^7.0.0",
|
|
33
33
|
"vitest": "^3.1.4"
|
|
34
34
|
},
|
|
@@ -2,7 +2,7 @@ import React from 'react';
|
|
|
2
2
|
import { useId } from 'react-aria';
|
|
3
3
|
import { TableCell, TableRow, TextField } from '@vitessce/styles';
|
|
4
4
|
import { usePlotOptionsStyles, OptionSelect } from '@vitessce/vit-s';
|
|
5
|
-
import { capitalize
|
|
5
|
+
import { capitalize } from '@vitessce/utils';
|
|
6
6
|
|
|
7
7
|
export default function GatingScatterplotOptions(props) {
|
|
8
8
|
const {
|
|
@@ -20,28 +20,18 @@ export default function GatingScatterplotOptions(props) {
|
|
|
20
20
|
} = props;
|
|
21
21
|
|
|
22
22
|
const gatingScatterplotOptionsId = useId();
|
|
23
|
+
const gatingScatterplotGeneXId = useId();
|
|
24
|
+
const gatingScatterplotGeneYId = useId();
|
|
23
25
|
|
|
24
26
|
const { classes } = usePlotOptionsStyles();
|
|
25
27
|
|
|
26
28
|
// Handlers for custom option field changes.
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
for (let i = 0, l = options.length; i < l; i += 1) {
|
|
31
|
-
if (options[i].selected) {
|
|
32
|
-
newValues.push(options[i].value);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
29
|
+
const handleSelectionX = (event) => {
|
|
30
|
+
setGatingFeatureSelectionX(event.target.value === '' ? null : event.target.value);
|
|
31
|
+
};
|
|
35
32
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
&& !gatingFeatureSelectionY
|
|
39
|
-
&& newValues[0] !== gatingFeatureSelectionX) {
|
|
40
|
-
setGatingFeatureSelectionY(newValues[0]);
|
|
41
|
-
} else if (newValues.length <= 2) {
|
|
42
|
-
setGatingFeatureSelectionX(newValues[0]);
|
|
43
|
-
setGatingFeatureSelectionY(newValues[1]);
|
|
44
|
-
}
|
|
33
|
+
const handleSelectionY = (event) => {
|
|
34
|
+
setGatingFeatureSelectionY(event.target.value === '' ? null : event.target.value);
|
|
45
35
|
};
|
|
46
36
|
|
|
47
37
|
const handleTransformChange = (event) => {
|
|
@@ -67,21 +57,51 @@ export default function GatingScatterplotOptions(props) {
|
|
|
67
57
|
<TableRow>
|
|
68
58
|
<TableCell className={classes.labelCell} variant="head" scope="row">
|
|
69
59
|
<label
|
|
70
|
-
htmlFor={`scatterplot-gating-gene-select-${
|
|
60
|
+
htmlFor={`scatterplot-gating-gene-select-${gatingScatterplotGeneXId}`}
|
|
61
|
+
>
|
|
62
|
+
{capitalize(featureType)} along X
|
|
63
|
+
</label>
|
|
64
|
+
</TableCell>
|
|
65
|
+
<TableCell className={classes.inputCell} variant="body">
|
|
66
|
+
<OptionSelect
|
|
67
|
+
className={classes.select}
|
|
68
|
+
value={gatingFeatureSelectionX ?? ''}
|
|
69
|
+
onChange={handleSelectionX}
|
|
70
|
+
inputProps={{
|
|
71
|
+
id: `scatterplot-gating-gene-select-${gatingScatterplotGeneXId}`,
|
|
72
|
+
}}
|
|
73
|
+
>
|
|
74
|
+
<option value="">
|
|
75
|
+
None
|
|
76
|
+
</option>
|
|
77
|
+
{geneSelectOptions.map(name => (
|
|
78
|
+
<option key={name} value={name}>
|
|
79
|
+
{name}
|
|
80
|
+
</option>
|
|
81
|
+
))}
|
|
82
|
+
</OptionSelect>
|
|
83
|
+
</TableCell>
|
|
84
|
+
</TableRow>
|
|
85
|
+
<TableRow>
|
|
86
|
+
<TableCell className={classes.labelCell} variant="head" scope="row">
|
|
87
|
+
<label
|
|
88
|
+
htmlFor={`scatterplot-gating-gene-select-${gatingScatterplotGeneYId}`}
|
|
71
89
|
>
|
|
72
|
-
{capitalize(
|
|
90
|
+
{capitalize(featureType)} along Y
|
|
73
91
|
</label>
|
|
74
92
|
</TableCell>
|
|
75
93
|
<TableCell className={classes.inputCell} variant="body">
|
|
76
94
|
<OptionSelect
|
|
77
|
-
multiple
|
|
78
95
|
className={classes.select}
|
|
79
|
-
value={
|
|
80
|
-
onChange={
|
|
96
|
+
value={gatingFeatureSelectionY ?? ''}
|
|
97
|
+
onChange={handleSelectionY}
|
|
81
98
|
inputProps={{
|
|
82
|
-
id: `scatterplot-gating-gene-select-${
|
|
99
|
+
id: `scatterplot-gating-gene-select-${gatingScatterplotGeneYId}`,
|
|
83
100
|
}}
|
|
84
101
|
>
|
|
102
|
+
<option value="">
|
|
103
|
+
None
|
|
104
|
+
</option>
|
|
85
105
|
{geneSelectOptions.map(name => (
|
|
86
106
|
<option key={name} value={name}>
|
|
87
107
|
{name}
|
|
@@ -129,7 +149,7 @@ export default function GatingScatterplotOptions(props) {
|
|
|
129
149
|
type="number"
|
|
130
150
|
onChange={handleTransformCoefficientChange}
|
|
131
151
|
value={gatingFeatureValueTransformCoefficient}
|
|
132
|
-
slotProps={{
|
|
152
|
+
slotProps={{ inputLabel: { shrink: true } }}
|
|
133
153
|
id={`scatterplot-gating-transform-coefficient-${gatingScatterplotOptionsId}`}
|
|
134
154
|
/>
|
|
135
155
|
</TableCell>
|
package/src/GatingSubscriber.js
CHANGED
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
useFeatureSelection,
|
|
18
18
|
useObsFeatureMatrixIndices,
|
|
19
19
|
useCoordination,
|
|
20
|
+
useInitialCoordination,
|
|
20
21
|
useLoaders,
|
|
21
22
|
useSetComponentHover,
|
|
22
23
|
useSetComponentViewInfo,
|
|
@@ -126,6 +127,14 @@ export function GatingSubscriber(props) {
|
|
|
126
127
|
coordinationScopes,
|
|
127
128
|
);
|
|
128
129
|
|
|
130
|
+
const {
|
|
131
|
+
embeddingZoom: initialZoom,
|
|
132
|
+
embeddingTargetX: initialTargetX,
|
|
133
|
+
embeddingTargetY: initialTargetY,
|
|
134
|
+
} = useInitialCoordination(
|
|
135
|
+
COMPONENT_COORDINATION_TYPES[ViewType.GATING], coordinationScopes,
|
|
136
|
+
);
|
|
137
|
+
|
|
129
138
|
const [width, height, deckRef] = useDeckCanvasSize();
|
|
130
139
|
|
|
131
140
|
const title = useMemo(() => {
|
|
@@ -244,6 +253,8 @@ export function GatingSubscriber(props) {
|
|
|
244
253
|
const [dynamicCellRadius, setDynamicCellRadius] = useState(cellRadiusFixed);
|
|
245
254
|
const [dynamicCellOpacity, setDynamicCellOpacity] = useState(cellOpacityFixed);
|
|
246
255
|
|
|
256
|
+
const [originalViewState, setOriginalViewState] = useState(null);
|
|
257
|
+
|
|
247
258
|
const mergedCellSets = useMemo(() => mergeObsSets(
|
|
248
259
|
cellSets, additionalCellSets,
|
|
249
260
|
), [cellSets, additionalCellSets]);
|
|
@@ -323,19 +334,28 @@ export function GatingSubscriber(props) {
|
|
|
323
334
|
);
|
|
324
335
|
setDynamicCellOpacity(nextCellOpacityScale);
|
|
325
336
|
|
|
326
|
-
if (typeof
|
|
337
|
+
if (typeof initialTargetX !== 'number' || typeof initialTargetY !== 'number') {
|
|
327
338
|
const newTargetX = xExtent[0] + xRange / 2;
|
|
328
339
|
const newTargetY = yExtent[0] + yRange / 2;
|
|
329
340
|
const newZoom = Math.log2(Math.min(width / xRange, height / yRange));
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
341
|
+
const notYetInitialized = (typeof targetX !== 'number' || typeof targetY !== 'number');
|
|
342
|
+
const stillDefaultInitialized = (targetX === newTargetX && targetY === -newTargetY);
|
|
343
|
+
if (notYetInitialized || stillDefaultInitialized) {
|
|
344
|
+
setTargetX(newTargetX);
|
|
345
|
+
// Graphics rendering has the y-axis going south so we need to multiply by negative one.
|
|
346
|
+
setTargetY(-newTargetY);
|
|
347
|
+
setZoom(newZoom);
|
|
348
|
+
}
|
|
349
|
+
setOriginalViewState({ target: [newTargetX, -newTargetY, 0], zoom: newZoom });
|
|
350
|
+
} else if (!originalViewState) {
|
|
351
|
+
// originalViewState has not yet been set and
|
|
352
|
+
// the view config defined an initial viewState.
|
|
353
|
+
setOriginalViewState({ target: [initialTargetX, initialTargetY, 0], zoom: initialZoom });
|
|
334
354
|
}
|
|
335
355
|
}
|
|
336
356
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
337
357
|
}, [xRange, yRange, xExtent, yExtent, numCells,
|
|
338
|
-
width, height, zoom, averageFillDensity]);
|
|
358
|
+
width, height, zoom, initialTargetX, initialTargetY, averageFillDensity]);
|
|
339
359
|
|
|
340
360
|
const cellSelectionSet = useMemo(() => new Set(cellSelection), [cellSelection]);
|
|
341
361
|
const getCellIsSelected = useCallback((object, { index }) => (
|
|
@@ -372,6 +392,13 @@ export function GatingSubscriber(props) {
|
|
|
372
392
|
gatingFeatureSelectionX, gatingFeatureSelectionY, obsType,
|
|
373
393
|
]);
|
|
374
394
|
|
|
395
|
+
const setViewState = ({ zoom: newZoom, target }) => {
|
|
396
|
+
setZoom(newZoom);
|
|
397
|
+
setTargetX(target[0]);
|
|
398
|
+
setTargetY(target[1]);
|
|
399
|
+
setTargetZ(target[2] || 0);
|
|
400
|
+
};
|
|
401
|
+
|
|
375
402
|
return (
|
|
376
403
|
<TitleInfo
|
|
377
404
|
title={title}
|
|
@@ -438,13 +465,10 @@ export function GatingSubscriber(props) {
|
|
|
438
465
|
uuid={uuid}
|
|
439
466
|
theme={theme}
|
|
440
467
|
hideTools={!(gatingFeatureSelectionX && gatingFeatureSelectionY)}
|
|
468
|
+
hideRecenter={!(gatingFeatureSelectionX && gatingFeatureSelectionY)}
|
|
441
469
|
viewState={{ zoom, target: [targetX, targetY, targetZ] }}
|
|
442
|
-
setViewState={
|
|
443
|
-
|
|
444
|
-
setTargetX(target[0]);
|
|
445
|
-
setTargetY(target[1]);
|
|
446
|
-
setTargetZ(target[2] || 0);
|
|
447
|
-
}}
|
|
470
|
+
setViewState={setViewState}
|
|
471
|
+
originalViewState={originalViewState}
|
|
448
472
|
obsEmbeddingIndex={obsIndex}
|
|
449
473
|
obsEmbedding={obsXY}
|
|
450
474
|
cellFilter={cellFilter}
|
|
@@ -470,6 +494,8 @@ export function GatingSubscriber(props) {
|
|
|
470
494
|
getExpressionValue={getExpressionValue}
|
|
471
495
|
getCellIsSelected={getCellIsSelected}
|
|
472
496
|
|
|
497
|
+
embeddingPointsVisible
|
|
498
|
+
|
|
473
499
|
/>
|
|
474
500
|
{!disableTooltip && (
|
|
475
501
|
<ScatterplotTooltipSubscriber
|