@vitessce/scatterplot-embedding 3.0.0 → 3.0.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.
@@ -1,5 +1,5 @@
1
1
  import { i as inflate_1 } from "./pako.esm-68f84e2a.js";
2
- import { B as BaseDecoder } from "./index-50142996.js";
2
+ import { B as BaseDecoder } from "./index-b3472cce.js";
3
3
  import "react";
4
4
  import "@vitessce/vit-s";
5
5
  import "react-dom";
@@ -1,6 +1,6 @@
1
1
  import * as React from "react";
2
2
  import React__default, { useLayoutEffect, useEffect, cloneElement, createElement, forwardRef, useState, useRef, useMemo, useImperativeHandle, Children, isValidElement, PureComponent, useCallback } from "react";
3
- import { usePlotOptionsStyles, OptionsContainer, CellColorEncodingOption, OptionSelect, useVitessceContainer, useComponentHover, useComponentViewInfo, useLoaders, useSetComponentHover, useSetComponentViewInfo, useCoordination, useUrls, useDeckCanvasSize, useMultiObsLabels, useObsEmbeddingData, useObsSetsData, useFeatureSelection, useObsFeatureMatrixIndices, useFeatureLabelsData, useReady, useGetObsInfo, useUint8FeatureSelection, useExpressionValueGetter, TitleInfo } from "@vitessce/vit-s";
3
+ import { usePlotOptionsStyles, OptionsContainer, CellColorEncodingOption, OptionSelect, useVitessceContainer, useComponentHover, useComponentViewInfo, useLoaders, useSetComponentHover, useSetComponentViewInfo, useCoordination, useInitialCoordination, useDeckCanvasSize, useMultiObsLabels, useObsEmbeddingData, useObsSetsData, useFeatureSelection, useObsFeatureMatrixIndices, useFeatureLabelsData, useReady, useUrls, useGetObsInfo, useUint8FeatureSelection, useExpressionValueGetter, TitleInfo } from "@vitessce/vit-s";
4
4
  import * as ReactDOM from "react-dom";
5
5
  function _mergeNamespaces(n2, m2) {
6
6
  for (var i2 = 0; i2 < m2.length; i2++) {
@@ -121236,16 +121236,16 @@ function addDecoder(cases, importFn) {
121236
121236
  }
121237
121237
  cases.forEach((c2) => registry$1.set(c2, importFn));
121238
121238
  }
121239
- addDecoder([void 0, 1], () => import("./raw-09626c2a.js").then((m2) => m2.default));
121240
- addDecoder(5, () => import("./lzw-91ba018e.js").then((m2) => m2.default));
121239
+ addDecoder([void 0, 1], () => import("./raw-f14877a3.js").then((m2) => m2.default));
121240
+ addDecoder(5, () => import("./lzw-abc3998f.js").then((m2) => m2.default));
121241
121241
  addDecoder(6, () => {
121242
121242
  throw new Error("old style JPEG compression is not supported.");
121243
121243
  });
121244
- addDecoder(7, () => import("./jpeg-da9c788c.js").then((m2) => m2.default));
121245
- addDecoder([8, 32946], () => import("./deflate-42fdcd50.js").then((m2) => m2.default));
121246
- addDecoder(32773, () => import("./packbits-45ead78a.js").then((m2) => m2.default));
121247
- addDecoder(34887, () => import("./lerc-86149bd3.js").then((m2) => m2.default));
121248
- addDecoder(50001, () => import("./webimage-d82eb077.js").then((m2) => m2.default));
121244
+ addDecoder(7, () => import("./jpeg-b8a2012a.js").then((m2) => m2.default));
121245
+ addDecoder([8, 32946], () => import("./deflate-3356a57c.js").then((m2) => m2.default));
121246
+ addDecoder(32773, () => import("./packbits-f739d6c6.js").then((m2) => m2.default));
121247
+ addDecoder(34887, () => import("./lerc-3fc6f6c4.js").then((m2) => m2.default));
121248
+ addDecoder(50001, () => import("./webimage-be9ed9e6.js").then((m2) => m2.default));
121249
121249
  function decodeRowAcc(row, stride) {
121250
121250
  let length2 = row.length - stride;
121251
121251
  let offset5 = 0;
@@ -141929,7 +141929,7 @@ const CenterFocusStrong = createSvgIcon(/* @__PURE__ */ React.createElement("pat
141929
141929
  d: "M12 8c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm-7 7H3v4c0 1.1.9 2 2 2h4v-2H5v-4zM5 5h4V3H5c-1.1 0-2 .9-2 2v4h2V5zm14-2h-4v2h4v4h2V5c0-1.1-.9-2-2-2zm0 16h-4v2h4c1.1 0 2-.9 2-2v-4h-2v4z"
141930
141930
  }), "CenterFocusStrong");
141931
141931
  const useStyles$2 = makeStyles(() => ({
141932
- button: {
141932
+ toolButton: {
141933
141933
  display: "inline-flex",
141934
141934
  "&:active": {
141935
141935
  opacity: ".65",
@@ -141952,7 +141952,7 @@ const useStyles$2 = makeStyles(() => ({
141952
141952
  transform: "scale(0.98)"
141953
141953
  // make the button slightly smaller
141954
141954
  },
141955
- icon: {
141955
+ toolIcon: {
141956
141956
  // btn btn-outline-secondary mr-2 icon
141957
141957
  padding: "0",
141958
141958
  height: "2em",
@@ -141990,12 +141990,12 @@ const useStyles$2 = makeStyles(() => ({
141990
141990
  function IconTool(props2) {
141991
141991
  const { alt, onClick, isActive, children: children2 } = props2;
141992
141992
  const classes = useStyles$2();
141993
- return jsxRuntimeExports.jsx("button", { className: clsx(classes.icon, { [classes.toolActive]: isActive }), onClick, type: "button", title: alt, children: children2 });
141993
+ return jsxRuntimeExports.jsx("button", { className: clsx(classes.toolIcon, { [classes.toolActive]: isActive }), onClick, type: "button", title: alt, children: children2 });
141994
141994
  }
141995
141995
  function IconButton2(props2) {
141996
141996
  const { alt, onClick, children: children2 } = props2;
141997
141997
  const classes = useStyles$2();
141998
- return jsxRuntimeExports.jsx("button", { className: clsx(classes.icon, classes.button), onClick, type: "button", title: alt, children: children2 });
141998
+ return jsxRuntimeExports.jsx("button", { className: clsx(classes.toolIcon, classes.toolButton), onClick, type: "button", title: alt, children: children2 });
141999
141999
  }
142000
142000
  function ToolMenu(props2) {
142001
142001
  const { setActiveTool, activeTool, visibleTools = { pan: true, selectLasso: true }, recenterOnClick = () => {
@@ -144802,31 +144802,39 @@ function EmbeddingScatterplotSubscriber(props2) {
144802
144802
  setFeatureValueColormapRange: setGeneExpressionColormapRange,
144803
144803
  setTooltipsVisible
144804
144804
  }] = useCoordination(COMPONENT_COORDINATION_TYPES[ViewType$1.SCATTERPLOT], coordinationScopes);
144805
+ const {
144806
+ embeddingZoom: initialZoom,
144807
+ embeddingTargetX: initialTargetX,
144808
+ embeddingTargetY: initialTargetY
144809
+ } = useInitialCoordination(
144810
+ COMPONENT_COORDINATION_TYPES[ViewType$1.SCATTERPLOT],
144811
+ coordinationScopes
144812
+ );
144805
144813
  const observationsLabel = observationsLabelOverride || obsType;
144806
- const [urls, addUrl] = useUrls(loaders, dataset);
144807
144814
  const [width, height, deckRef] = useDeckCanvasSize();
144808
144815
  const title = titleOverride || `Scatterplot (${mapping})`;
144809
144816
  const [obsLabelsTypes, obsLabelsData] = useMultiObsLabels(
144810
144817
  coordinationScopes,
144811
144818
  obsType,
144812
144819
  loaders,
144813
- dataset,
144814
- addUrl
144820
+ dataset
144815
144821
  );
144816
- const [{ obsIndex: obsEmbeddingIndex, obsEmbedding }, obsEmbeddingStatus] = useObsEmbeddingData(
144822
+ const [
144823
+ { obsIndex: obsEmbeddingIndex, obsEmbedding },
144824
+ obsEmbeddingStatus,
144825
+ obsEmbeddingUrls
144826
+ ] = useObsEmbeddingData(
144817
144827
  loaders,
144818
144828
  dataset,
144819
- addUrl,
144820
144829
  true,
144821
144830
  {},
144822
144831
  {},
144823
144832
  { obsType, embeddingType: mapping }
144824
144833
  );
144825
144834
  const cellsCount = (obsEmbeddingIndex == null ? void 0 : obsEmbeddingIndex.length) || 0;
144826
- const [{ obsSets: cellSets, obsSetsMembership }, obsSetsStatus] = useObsSetsData(
144835
+ const [{ obsSets: cellSets, obsSetsMembership }, obsSetsStatus, obsSetsUrls] = useObsSetsData(
144827
144836
  loaders,
144828
144837
  dataset,
144829
- addUrl,
144830
144838
  false,
144831
144839
  { setObsSetSelection: setCellSetSelection, setObsSetColor: setCellSetColor },
144832
144840
  { obsSetSelection: cellSetSelection, obsSetColor: cellSetColor },
@@ -144839,17 +144847,19 @@ function EmbeddingScatterplotSubscriber(props2) {
144839
144847
  geneSelection,
144840
144848
  { obsType, featureType, featureValueType }
144841
144849
  );
144842
- const [{ obsIndex: matrixObsIndex }, matrixIndicesStatus] = useObsFeatureMatrixIndices(
144850
+ const [
144851
+ { obsIndex: matrixObsIndex },
144852
+ matrixIndicesStatus,
144853
+ matrixIndicesUrls
144854
+ ] = useObsFeatureMatrixIndices(
144843
144855
  loaders,
144844
144856
  dataset,
144845
- addUrl,
144846
144857
  false,
144847
144858
  { obsType, featureType, featureValueType }
144848
144859
  );
144849
- const [{ featureLabelsMap }, featureLabelsStatus] = useFeatureLabelsData(
144860
+ const [{ featureLabelsMap }, featureLabelsStatus, featureLabelsUrls] = useFeatureLabelsData(
144850
144861
  loaders,
144851
144862
  dataset,
144852
- addUrl,
144853
144863
  false,
144854
144864
  {},
144855
144865
  {},
@@ -144862,6 +144872,12 @@ function EmbeddingScatterplotSubscriber(props2) {
144862
144872
  featureLabelsStatus,
144863
144873
  matrixIndicesStatus
144864
144874
  ]);
144875
+ const urls = useUrls([
144876
+ obsEmbeddingUrls,
144877
+ obsSetsUrls,
144878
+ matrixIndicesUrls,
144879
+ featureLabelsUrls
144880
+ ]);
144865
144881
  const [dynamicCellRadius, setDynamicCellRadius] = useState(cellRadiusFixed);
144866
144882
  const [dynamicCellOpacity, setDynamicCellOpacity] = useState(cellOpacityFixed);
144867
144883
  const [originalViewState, setOriginalViewState] = useState(null);
@@ -144945,7 +144961,7 @@ function EmbeddingScatterplotSubscriber(props2) {
144945
144961
  return [null, null, null, null, null];
144946
144962
  }, [obsEmbedding]);
144947
144963
  useEffect(() => {
144948
- if (xRange && yRange && isReady) {
144964
+ if (xRange && yRange) {
144949
144965
  const pointSizeDevicePixels = getPointSizeDevicePixels(
144950
144966
  window.devicePixelRatio,
144951
144967
  zoom,
@@ -144965,28 +144981,34 @@ function EmbeddingScatterplotSubscriber(props2) {
144965
144981
  averageFillDensity
144966
144982
  );
144967
144983
  setDynamicCellOpacity(nextCellOpacityScale);
144968
- if (typeof targetX !== "number" || typeof targetY !== "number") {
144984
+ if (typeof initialTargetX !== "number" || typeof initialTargetY !== "number") {
144969
144985
  const newTargetX = xExtent[0] + xRange / 2;
144970
144986
  const newTargetY = yExtent[0] + yRange / 2;
144971
144987
  const newZoom = Math.log2(Math.min(width / xRange, height / yRange));
144972
- setTargetX(newTargetX);
144973
- setTargetY(-newTargetY);
144974
- setZoom(newZoom);
144988
+ const notYetInitialized = typeof targetX !== "number" || typeof targetY !== "number";
144989
+ const stillDefaultInitialized = targetX === newTargetX && targetY === -newTargetY;
144990
+ if (notYetInitialized || stillDefaultInitialized) {
144991
+ setTargetX(newTargetX);
144992
+ setTargetY(-newTargetY);
144993
+ setZoom(newZoom);
144994
+ }
144975
144995
  setOriginalViewState({ target: [newTargetX, -newTargetY, 0], zoom: newZoom });
144976
144996
  } else if (!originalViewState) {
144977
- setOriginalViewState({ target: [targetX, targetY, 0], zoom });
144997
+ setOriginalViewState({ target: [initialTargetX, initialTargetY, 0], zoom: initialZoom });
144978
144998
  }
144979
144999
  }
144980
145000
  }, [
144981
145001
  xRange,
144982
145002
  yRange,
144983
- isReady,
144984
145003
  xExtent,
144985
145004
  yExtent,
144986
145005
  numCells,
144987
145006
  width,
144988
145007
  height,
145008
+ initialZoom,
144989
145009
  zoom,
145010
+ initialTargetX,
145011
+ initialTargetY,
144990
145012
  averageFillDensity
144991
145013
  ]);
144992
145014
  const getObsInfo = useGetObsInfo(
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { E } from "./index-50142996.js";
1
+ import { E } from "./index-b3472cce.js";
2
2
  import "react";
3
3
  import "@vitessce/vit-s";
4
4
  import "react-dom";
@@ -1,4 +1,4 @@
1
- import { B as BaseDecoder } from "./index-50142996.js";
1
+ import { B as BaseDecoder } from "./index-b3472cce.js";
2
2
  import "react";
3
3
  import "@vitessce/vit-s";
4
4
  import "react-dom";
@@ -1,5 +1,5 @@
1
1
  import { i as inflate_1 } from "./pako.esm-68f84e2a.js";
2
- import { g as getDefaultExportFromCjs, B as BaseDecoder } from "./index-50142996.js";
2
+ import { g as getDefaultExportFromCjs, B as BaseDecoder } from "./index-b3472cce.js";
3
3
  import "react";
4
4
  import "@vitessce/vit-s";
5
5
  import "react-dom";
@@ -1,4 +1,4 @@
1
- import { B as BaseDecoder } from "./index-50142996.js";
1
+ import { B as BaseDecoder } from "./index-b3472cce.js";
2
2
  import "react";
3
3
  import "@vitessce/vit-s";
4
4
  import "react-dom";
@@ -1,4 +1,4 @@
1
- import { B as BaseDecoder } from "./index-50142996.js";
1
+ import { B as BaseDecoder } from "./index-b3472cce.js";
2
2
  import "react";
3
3
  import "@vitessce/vit-s";
4
4
  import "react-dom";
@@ -1,4 +1,4 @@
1
- import { B as BaseDecoder } from "./index-50142996.js";
1
+ import { B as BaseDecoder } from "./index-b3472cce.js";
2
2
  import "react";
3
3
  import "@vitessce/vit-s";
4
4
  import "react-dom";
@@ -1,4 +1,4 @@
1
- import { B as BaseDecoder } from "./index-50142996.js";
1
+ import { B as BaseDecoder } from "./index-b3472cce.js";
2
2
  import "react";
3
3
  import "@vitessce/vit-s";
4
4
  import "react-dom";
@@ -1 +1 @@
1
- {"version":3,"file":"EmbeddingScatterplotSubscriber.d.ts","sourceRoot":"","sources":["../src/EmbeddingScatterplotSubscriber.js"],"names":[],"mappings":"AAkCA;;;;;;;;;;;;GAYG;AACH;IAVyB,IAAI,EAAlB,MAAM;IACQ,KAAK,EAAnB,MAAM;IACQ,kBAAkB,EAAhC,MAAM;IAEU,mBAAmB;IAErB,KAAK,EAAnB,MAAM;IACQ,kBAAkB,EAAhC,MAAM;gBA4VhB"}
1
+ {"version":3,"file":"EmbeddingScatterplotSubscriber.d.ts","sourceRoot":"","sources":["../src/EmbeddingScatterplotSubscriber.js"],"names":[],"mappings":"AAmCA;;;;;;;;;;;;GAYG;AACH;IAVyB,IAAI,EAAlB,MAAM;IACQ,KAAK,EAAnB,MAAM;IACQ,kBAAkB,EAAhC,MAAM;IAEU,mBAAmB;IAErB,KAAK,EAAnB,MAAM;IACQ,kBAAkB,EAAhC,MAAM;gBA0WhB"}
@@ -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 plur from 'plur';
6
- import { TitleInfo, useReady, useUrls, useDeckCanvasSize, useUint8FeatureSelection, useExpressionValueGetter, useGetObsInfo, useObsEmbeddingData, useObsSetsData, useFeatureSelection, useObsFeatureMatrixIndices, useFeatureLabelsData, useMultiObsLabels, useCoordination, useLoaders, useSetComponentHover, useSetComponentViewInfo, } from '@vitessce/vit-s';
6
+ import { TitleInfo, useReady, useUrls, useDeckCanvasSize, useUint8FeatureSelection, useExpressionValueGetter, useGetObsInfo, useObsEmbeddingData, useObsSetsData, useFeatureSelection, useObsFeatureMatrixIndices, useFeatureLabelsData, useMultiObsLabels, useCoordination, useLoaders, useSetComponentHover, useSetComponentViewInfo, useInitialCoordination, } from '@vitessce/vit-s';
7
7
  import { setObsSelection, mergeObsSets, getCellSetPolygons } from '@vitessce/sets-utils';
8
8
  import { getCellColors, commaNumber } from '@vitessce/utils';
9
9
  import { Scatterplot, ScatterplotTooltipSubscriber, ScatterplotOptions, getPointSizeDevicePixels, getPointOpacity, } from '@vitessce/scatterplot';
@@ -31,19 +31,19 @@ export function EmbeddingScatterplotSubscriber(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, embeddingType: mapping, obsFilter: cellFilter, obsHighlight: cellHighlight, featureSelection: geneSelection, 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, tooltipsVisible, }, { 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, setTooltipsVisible, }] = useCoordination(COMPONENT_COORDINATION_TYPES[ViewType.SCATTERPLOT], coordinationScopes);
34
+ const { embeddingZoom: initialZoom, embeddingTargetX: initialTargetX, embeddingTargetY: initialTargetY, } = useInitialCoordination(COMPONENT_COORDINATION_TYPES[ViewType.SCATTERPLOT], coordinationScopes);
34
35
  const observationsLabel = observationsLabelOverride || obsType;
35
- const [urls, addUrl] = useUrls(loaders, dataset);
36
36
  const [width, height, deckRef] = useDeckCanvasSize();
37
37
  const title = titleOverride || `Scatterplot (${mapping})`;
38
- const [obsLabelsTypes, obsLabelsData] = useMultiObsLabels(coordinationScopes, obsType, loaders, dataset, addUrl);
38
+ const [obsLabelsTypes, obsLabelsData] = useMultiObsLabels(coordinationScopes, obsType, loaders, dataset);
39
39
  // Get data from loaders using the data hooks.
40
- const [{ obsIndex: obsEmbeddingIndex, obsEmbedding }, obsEmbeddingStatus] = useObsEmbeddingData(loaders, dataset, addUrl, true, {}, {}, { obsType, embeddingType: mapping });
40
+ const [{ obsIndex: obsEmbeddingIndex, obsEmbedding }, obsEmbeddingStatus, obsEmbeddingUrls,] = useObsEmbeddingData(loaders, dataset, true, {}, {}, { obsType, embeddingType: mapping });
41
41
  const cellsCount = obsEmbeddingIndex?.length || 0;
42
- const [{ obsSets: cellSets, obsSetsMembership }, obsSetsStatus] = useObsSetsData(loaders, dataset, addUrl, false, { setObsSetSelection: setCellSetSelection, setObsSetColor: setCellSetColor }, { obsSetSelection: cellSetSelection, obsSetColor: cellSetColor }, { obsType });
42
+ const [{ obsSets: cellSets, obsSetsMembership }, obsSetsStatus, obsSetsUrls] = useObsSetsData(loaders, dataset, false, { setObsSetSelection: setCellSetSelection, setObsSetColor: setCellSetColor }, { obsSetSelection: cellSetSelection, obsSetColor: cellSetColor }, { obsType });
43
43
  // eslint-disable-next-line no-unused-vars
44
44
  const [expressionData, loadedFeatureSelection, featureSelectionStatus] = useFeatureSelection(loaders, dataset, false, geneSelection, { obsType, featureType, featureValueType });
45
- const [{ obsIndex: matrixObsIndex }, matrixIndicesStatus] = useObsFeatureMatrixIndices(loaders, dataset, addUrl, false, { obsType, featureType, featureValueType });
46
- const [{ featureLabelsMap }, featureLabelsStatus] = useFeatureLabelsData(loaders, dataset, addUrl, false, {}, {}, { featureType });
45
+ const [{ obsIndex: matrixObsIndex }, matrixIndicesStatus, matrixIndicesUrls,] = useObsFeatureMatrixIndices(loaders, dataset, false, { obsType, featureType, featureValueType });
46
+ const [{ featureLabelsMap }, featureLabelsStatus, featureLabelsUrls] = useFeatureLabelsData(loaders, dataset, false, {}, {}, { featureType });
47
47
  const isReady = useReady([
48
48
  obsEmbeddingStatus,
49
49
  obsSetsStatus,
@@ -51,6 +51,12 @@ export function EmbeddingScatterplotSubscriber(props) {
51
51
  featureLabelsStatus,
52
52
  matrixIndicesStatus,
53
53
  ]);
54
+ const urls = useUrls([
55
+ obsEmbeddingUrls,
56
+ obsSetsUrls,
57
+ matrixIndicesUrls,
58
+ featureLabelsUrls,
59
+ ]);
54
60
  const [dynamicCellRadius, setDynamicCellRadius] = useState(cellRadiusFixed);
55
61
  const [dynamicCellOpacity, setDynamicCellOpacity] = useState(cellOpacityFixed);
56
62
  const [originalViewState, setOriginalViewState] = useState(null);
@@ -109,39 +115,36 @@ export function EmbeddingScatterplotSubscriber(props) {
109
115
  // compute the cell radius scale based on the
110
116
  // extents of the cell coordinates on the x/y axes.
111
117
  useEffect(() => {
112
- // We do not really need isReady here, since the above useMemo that
113
- // computes xRange and yRange will only run after obsEmbedding has loaded anyway.
114
- // However, we include it here to ensure this effect waits as long as possible to run;
115
- // For some reason, otherwise, in some cases this effect will run before the react-grid-layout
116
- // initialization animation has finished,
117
- // prior to `height` and `width` reaching their ultimate values, resulting in
118
- // an initial viewState for that small view size, which looks bad.
119
- if (xRange && yRange && isReady) {
118
+ if (xRange && yRange) {
120
119
  const pointSizeDevicePixels = getPointSizeDevicePixels(window.devicePixelRatio, zoom, xRange, yRange, width, height);
121
120
  setDynamicCellRadius(pointSizeDevicePixels);
122
121
  const nextCellOpacityScale = getPointOpacity(zoom, xRange, yRange, width, height, numCells, averageFillDensity);
123
122
  setDynamicCellOpacity(nextCellOpacityScale);
124
- if (typeof targetX !== 'number' || typeof targetY !== 'number') {
123
+ if (typeof initialTargetX !== 'number' || typeof initialTargetY !== 'number') {
125
124
  // The view config did not define an initial viewState so
126
125
  // we calculate one based on the data and set it.
127
126
  const newTargetX = xExtent[0] + xRange / 2;
128
127
  const newTargetY = yExtent[0] + yRange / 2;
129
128
  const newZoom = Math.log2(Math.min(width / xRange, height / yRange));
130
- setTargetX(newTargetX);
131
- // Graphics rendering has the y-axis going south so we need to multiply by negative one.
132
- setTargetY(-newTargetY);
133
- setZoom(newZoom);
129
+ const notYetInitialized = (typeof targetX !== 'number' || typeof targetY !== 'number');
130
+ const stillDefaultInitialized = (targetX === newTargetX && targetY === -newTargetY);
131
+ if (notYetInitialized || stillDefaultInitialized) {
132
+ setTargetX(newTargetX);
133
+ // Graphics rendering has the y-axis going south so we need to multiply by negative one.
134
+ setTargetY(-newTargetY);
135
+ setZoom(newZoom);
136
+ }
134
137
  setOriginalViewState({ target: [newTargetX, -newTargetY, 0], zoom: newZoom });
135
138
  }
136
139
  else if (!originalViewState) {
137
140
  // originalViewState has not yet been set and
138
141
  // the view config defined an initial viewState.
139
- setOriginalViewState({ target: [targetX, targetY, 0], zoom });
142
+ setOriginalViewState({ target: [initialTargetX, initialTargetY, 0], zoom: initialZoom });
140
143
  }
141
144
  }
142
145
  // eslint-disable-next-line react-hooks/exhaustive-deps
143
- }, [xRange, yRange, isReady, xExtent, yExtent, numCells,
144
- width, height, zoom, averageFillDensity]);
146
+ }, [xRange, yRange, xExtent, yExtent, numCells,
147
+ width, height, initialZoom, zoom, initialTargetX, initialTargetY, averageFillDensity]);
145
148
  const getObsInfo = useGetObsInfo(observationsLabel, obsLabelsTypes, obsLabelsData, obsSetsMembership);
146
149
  const cellSelectionSet = useMemo(() => new Set(cellSelection), [cellSelection]);
147
150
  const getCellIsSelected = useCallback((object, { index }) => ((cellSelectionSet || new Set([])).has(obsEmbeddingIndex[index]) ? 1.0 : 0.0), [cellSelectionSet, obsEmbeddingIndex]);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vitessce/scatterplot-embedding",
3
- "version": "3.0.0",
3
+ "version": "3.0.1",
4
4
  "author": "Gehlenborg Lab",
5
5
  "homepage": "http://vitessce.io",
6
6
  "repository": {
@@ -20,24 +20,24 @@
20
20
  "d3-array": "^2.4.0",
21
21
  "lodash-es": "^4.17.21",
22
22
  "plur": "^5.1.0",
23
- "@vitessce/constants-internal": "3.0.0",
24
- "@vitessce/legend": "3.0.0",
25
- "@vitessce/scatterplot": "3.0.0",
26
- "@vitessce/sets-utils": "3.0.0",
27
- "@vitessce/utils": "3.0.0",
28
- "@vitessce/vit-s": "3.0.0"
23
+ "@vitessce/constants-internal": "3.0.1",
24
+ "@vitessce/legend": "3.0.1",
25
+ "@vitessce/scatterplot": "3.0.1",
26
+ "@vitessce/sets-utils": "3.0.1",
27
+ "@vitessce/utils": "3.0.1",
28
+ "@vitessce/vit-s": "3.0.1"
29
29
  },
30
30
  "devDependencies": {
31
31
  "react": "^18.0.0",
32
32
  "vite": "^4.3.0",
33
- "vitest": "^0.23.4"
33
+ "vitest": "^0.32.2"
34
34
  },
35
35
  "peerDependencies": {
36
36
  "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
37
37
  },
38
38
  "scripts": {
39
39
  "bundle": "pnpm exec vite build -c ../../../scripts/vite.config.js",
40
- "test": "pnpm exec vitest --run -r ../../../ --dir ."
40
+ "test": "pnpm exec vitest --run"
41
41
  },
42
42
  "module": "dist/index.js",
43
43
  "exports": {
@@ -21,6 +21,7 @@ import {
21
21
  useLoaders,
22
22
  useSetComponentHover,
23
23
  useSetComponentViewInfo,
24
+ useInitialCoordination,
24
25
  } from '@vitessce/vit-s';
25
26
  import { setObsSelection, mergeObsSets, getCellSetPolygons } from '@vitessce/sets-utils';
26
27
  import { getCellColors, commaNumber } from '@vitessce/utils';
@@ -112,25 +113,34 @@ export function EmbeddingScatterplotSubscriber(props) {
112
113
  setTooltipsVisible,
113
114
  }] = useCoordination(COMPONENT_COORDINATION_TYPES[ViewType.SCATTERPLOT], coordinationScopes);
114
115
 
116
+ const {
117
+ embeddingZoom: initialZoom,
118
+ embeddingTargetX: initialTargetX,
119
+ embeddingTargetY: initialTargetY,
120
+ } = useInitialCoordination(
121
+ COMPONENT_COORDINATION_TYPES[ViewType.SCATTERPLOT], coordinationScopes,
122
+ );
123
+
115
124
  const observationsLabel = observationsLabelOverride || obsType;
116
125
 
117
- const [urls, addUrl] = useUrls(loaders, dataset);
118
126
  const [width, height, deckRef] = useDeckCanvasSize();
119
127
 
120
128
  const title = titleOverride || `Scatterplot (${mapping})`;
121
129
 
122
130
  const [obsLabelsTypes, obsLabelsData] = useMultiObsLabels(
123
- coordinationScopes, obsType, loaders, dataset, addUrl,
131
+ coordinationScopes, obsType, loaders, dataset,
124
132
  );
125
133
 
126
134
  // Get data from loaders using the data hooks.
127
- const [{ obsIndex: obsEmbeddingIndex, obsEmbedding }, obsEmbeddingStatus] = useObsEmbeddingData(
128
- loaders, dataset, addUrl, true, {}, {},
135
+ const [
136
+ { obsIndex: obsEmbeddingIndex, obsEmbedding }, obsEmbeddingStatus, obsEmbeddingUrls,
137
+ ] = useObsEmbeddingData(
138
+ loaders, dataset, true, {}, {},
129
139
  { obsType, embeddingType: mapping },
130
140
  );
131
141
  const cellsCount = obsEmbeddingIndex?.length || 0;
132
- const [{ obsSets: cellSets, obsSetsMembership }, obsSetsStatus] = useObsSetsData(
133
- loaders, dataset, addUrl, false,
142
+ const [{ obsSets: cellSets, obsSetsMembership }, obsSetsStatus, obsSetsUrls] = useObsSetsData(
143
+ loaders, dataset, false,
134
144
  { setObsSetSelection: setCellSetSelection, setObsSetColor: setCellSetColor },
135
145
  { obsSetSelection: cellSetSelection, obsSetColor: cellSetColor },
136
146
  { obsType },
@@ -140,12 +150,14 @@ export function EmbeddingScatterplotSubscriber(props) {
140
150
  loaders, dataset, false, geneSelection,
141
151
  { obsType, featureType, featureValueType },
142
152
  );
143
- const [{ obsIndex: matrixObsIndex }, matrixIndicesStatus] = useObsFeatureMatrixIndices(
144
- loaders, dataset, addUrl, false,
153
+ const [
154
+ { obsIndex: matrixObsIndex }, matrixIndicesStatus, matrixIndicesUrls,
155
+ ] = useObsFeatureMatrixIndices(
156
+ loaders, dataset, false,
145
157
  { obsType, featureType, featureValueType },
146
158
  );
147
- const [{ featureLabelsMap }, featureLabelsStatus] = useFeatureLabelsData(
148
- loaders, dataset, addUrl, false, {}, {},
159
+ const [{ featureLabelsMap }, featureLabelsStatus, featureLabelsUrls] = useFeatureLabelsData(
160
+ loaders, dataset, false, {}, {},
149
161
  { featureType },
150
162
  );
151
163
 
@@ -156,6 +168,12 @@ export function EmbeddingScatterplotSubscriber(props) {
156
168
  featureLabelsStatus,
157
169
  matrixIndicesStatus,
158
170
  ]);
171
+ const urls = useUrls([
172
+ obsEmbeddingUrls,
173
+ obsSetsUrls,
174
+ matrixIndicesUrls,
175
+ featureLabelsUrls,
176
+ ]);
159
177
 
160
178
  const [dynamicCellRadius, setDynamicCellRadius] = useState(cellRadiusFixed);
161
179
  const [dynamicCellOpacity, setDynamicCellOpacity] = useState(cellOpacityFixed);
@@ -230,14 +248,7 @@ export function EmbeddingScatterplotSubscriber(props) {
230
248
  // compute the cell radius scale based on the
231
249
  // extents of the cell coordinates on the x/y axes.
232
250
  useEffect(() => {
233
- // We do not really need isReady here, since the above useMemo that
234
- // computes xRange and yRange will only run after obsEmbedding has loaded anyway.
235
- // However, we include it here to ensure this effect waits as long as possible to run;
236
- // For some reason, otherwise, in some cases this effect will run before the react-grid-layout
237
- // initialization animation has finished,
238
- // prior to `height` and `width` reaching their ultimate values, resulting in
239
- // an initial viewState for that small view size, which looks bad.
240
- if (xRange && yRange && isReady) {
251
+ if (xRange && yRange) {
241
252
  const pointSizeDevicePixels = getPointSizeDevicePixels(
242
253
  window.devicePixelRatio, zoom, xRange, yRange, width, height,
243
254
  );
@@ -248,26 +259,30 @@ export function EmbeddingScatterplotSubscriber(props) {
248
259
  );
249
260
  setDynamicCellOpacity(nextCellOpacityScale);
250
261
 
251
- if (typeof targetX !== 'number' || typeof targetY !== 'number') {
262
+ if (typeof initialTargetX !== 'number' || typeof initialTargetY !== 'number') {
252
263
  // The view config did not define an initial viewState so
253
264
  // we calculate one based on the data and set it.
254
265
  const newTargetX = xExtent[0] + xRange / 2;
255
266
  const newTargetY = yExtent[0] + yRange / 2;
256
267
  const newZoom = Math.log2(Math.min(width / xRange, height / yRange));
257
- setTargetX(newTargetX);
258
- // Graphics rendering has the y-axis going south so we need to multiply by negative one.
259
- setTargetY(-newTargetY);
260
- setZoom(newZoom);
268
+ const notYetInitialized = (typeof targetX !== 'number' || typeof targetY !== 'number');
269
+ const stillDefaultInitialized = (targetX === newTargetX && targetY === -newTargetY);
270
+ if (notYetInitialized || stillDefaultInitialized) {
271
+ setTargetX(newTargetX);
272
+ // Graphics rendering has the y-axis going south so we need to multiply by negative one.
273
+ setTargetY(-newTargetY);
274
+ setZoom(newZoom);
275
+ }
261
276
  setOriginalViewState({ target: [newTargetX, -newTargetY, 0], zoom: newZoom });
262
277
  } else if (!originalViewState) {
263
278
  // originalViewState has not yet been set and
264
279
  // the view config defined an initial viewState.
265
- setOriginalViewState({ target: [targetX, targetY, 0], zoom });
280
+ setOriginalViewState({ target: [initialTargetX, initialTargetY, 0], zoom: initialZoom });
266
281
  }
267
282
  }
268
283
  // eslint-disable-next-line react-hooks/exhaustive-deps
269
- }, [xRange, yRange, isReady, xExtent, yExtent, numCells,
270
- width, height, zoom, averageFillDensity]);
284
+ }, [xRange, yRange, xExtent, yExtent, numCells,
285
+ width, height, initialZoom, zoom, initialTargetX, initialTargetY, averageFillDensity]);
271
286
 
272
287
  const getObsInfo = useGetObsInfo(
273
288
  observationsLabel, obsLabelsTypes, obsLabelsData, obsSetsMembership,