@vitessce/scatterplot-embedding 3.0.0 → 3.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/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { E } from "./index-50142996.js";
1
+ import { E } from "./index-d8ac68c1.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-d8ac68c1.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-d8ac68c1.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-d8ac68c1.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-d8ac68c1.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-d8ac68c1.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-d8ac68c1.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.1.0",
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.1.0",
24
+ "@vitessce/legend": "3.1.0",
25
+ "@vitessce/scatterplot": "3.1.0",
26
+ "@vitessce/sets-utils": "3.1.0",
27
+ "@vitessce/utils": "3.1.0",
28
+ "@vitessce/vit-s": "3.1.0"
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,