@vitessce/heatmap 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/src/Heatmap.js CHANGED
@@ -65,22 +65,22 @@ function shouldUsePaddedImplementation(dataLength) {
65
65
  * for DeckGL.
66
66
  * @param {number} props.width The width of the canvas.
67
67
  * @param {number} props.height The height of the canvas.
68
- * @param {object} props.expressionMatrix An object { rows, cols, matrix },
69
- * where matrix is a flat Uint8Array, rows is a list of cell ID strings,
70
- * and cols is a list of gene ID strings.
68
+ * @param {null|Uint8Array} props.uint8ObsFeatureMatrix A flat Uint8Array
69
+ * containing the expression data.
71
70
  * @param {Map} props.cellColors Map of cell ID to color. Optional.
72
71
  * If defined, the key ordering is used to order the cell axis of the heatmap.
73
72
  * @param {array} props.cellColorLabels array of labels to place beside cell color
74
73
  * tracks. Only works for transpose=true.
75
- * @param {function} props.clearPleaseWait The clear please wait callback,
76
- * called when the expression matrix has loaded (is not null).
77
74
  * @param {function} props.setCellHighlight Callback function called on
78
75
  * hover with the cell ID. Optional.
79
76
  * @param {function} props.setGeneHighlight Callback function called on
80
77
  * hover with the gene ID. Optional.
81
78
  * @param {function} props.updateViewInfo Callback function that gets called with an
82
- * object { uuid, project() } where project is a function that maps (cellId, geneId)
83
- * to canvas (x,y) coordinates. Used to show tooltips. Optional.
79
+ * object { uuid, project(), projectFromId() } where
80
+ * project is the DeckGL Viewport.project function, and
81
+ * projectFromId is a wrapper around project that
82
+ * takes (cellId, geneId) as parameters and returns
83
+ * canvas (x,y) pixel coordinates. Used to show tooltips. Optional.
84
84
  * @param {boolean} props.transpose By default, false.
85
85
  * @param {string} props.variablesTitle By default, 'Genes'.
86
86
  * @param {string} props.observationsTitle By default, 'Cells'.
@@ -91,6 +91,9 @@ function shouldUsePaddedImplementation(dataLength) {
91
91
  * @param {string} props.colormap The name of the colormap function to use.
92
92
  * @param {array} props.colormapRange A tuple [lower, upper] to adjust the color scale.
93
93
  * @param {function} props.setColormapRange The setter function for colormapRange.
94
+ * @param {string[]} props.obsIndex The cell ID list.
95
+ * @param {string[]} props.featureIndex The gene ID list.
96
+ * @param {null|Map<string,string>} props.featureLabelsMap A map of featureIndex to featureLabel.
94
97
  */
95
98
  const Heatmap = forwardRef((props, deckRef) => {
96
99
  const {
@@ -100,12 +103,11 @@ const Heatmap = forwardRef((props, deckRef) => {
100
103
  setViewState,
101
104
  width: viewWidth,
102
105
  height: viewHeight,
103
- expressionMatrix: expression,
106
+ uint8ObsFeatureMatrix,
104
107
  cellColors,
105
108
  cellColorLabels = [''],
106
109
  colormap,
107
110
  colormapRange,
108
- clearPleaseWait,
109
111
  setComponentHover,
110
112
  setCellHighlight = createDefaultUpdateCellsHover('Heatmap'),
111
113
  setGeneHighlight = createDefaultUpdateGenesHover('Heatmap'),
@@ -122,7 +124,9 @@ const Heatmap = forwardRef((props, deckRef) => {
122
124
  hideVariableLabels = false,
123
125
  onHeatmapClick,
124
126
  setColorEncoding,
127
+ obsIndex,
125
128
  featureIndex,
129
+ featureLabelsMap,
126
130
  } = props;
127
131
 
128
132
  const viewState = {
@@ -136,12 +140,6 @@ const Heatmap = forwardRef((props, deckRef) => {
136
140
 
137
141
  const workerPool = useMemo(() => new HeatmapWorkerPool(), []);
138
142
 
139
- useEffect(() => {
140
- if (clearPleaseWait && expression) {
141
- clearPleaseWait('expression-matrix');
142
- }
143
- }, [clearPleaseWait, expression]);
144
-
145
143
  const tilesRef = useRef();
146
144
  const dataRef = useRef();
147
145
  const [axisLeftLabels, setAxisLeftLabels] = useState([]);
@@ -164,23 +162,23 @@ const Heatmap = forwardRef((props, deckRef) => {
164
162
  // it back and forth from the worker thread.
165
163
  useEffect(() => {
166
164
  // Store the expression matrix Uint8Array in the dataRef.
167
- if (expression && expression.matrix
168
- && !shouldUsePaddedImplementation(expression.matrix.length)
165
+ if (uint8ObsFeatureMatrix
166
+ && !shouldUsePaddedImplementation(uint8ObsFeatureMatrix.length)
169
167
  ) {
170
- dataRef.current = copyUint8Array(expression.matrix);
168
+ dataRef.current = copyUint8Array(uint8ObsFeatureMatrix);
171
169
  }
172
- }, [dataRef, expression]);
170
+ }, [dataRef, uint8ObsFeatureMatrix]);
173
171
 
174
172
  // Check if the ordering of axis labels needs to be changed,
175
173
  // for example if the cells "selected" (technically just colored)
176
174
  // have changed.
177
175
  useEffect(() => {
178
- if (!expression) {
176
+ if (!obsIndex) {
179
177
  return;
180
178
  }
181
179
 
182
180
  const newCellOrdering = (!cellColors || cellColors.size === 0
183
- ? expression.rows
181
+ ? obsIndex
184
182
  : Array.from(cellColors.keys())
185
183
  );
186
184
 
@@ -193,41 +191,41 @@ const Heatmap = forwardRef((props, deckRef) => {
193
191
  setAxisLeftLabels(newCellOrdering);
194
192
  }
195
193
  }
196
- }, [expression, cellColors, axisTopLabels, axisLeftLabels, transpose]);
194
+ }, [obsIndex, cellColors, axisTopLabels, axisLeftLabels, transpose]);
197
195
 
198
196
  // Set the genes ordering.
199
197
  useEffect(() => {
200
- if (!expression) {
198
+ if (!featureIndex) {
201
199
  return;
202
200
  }
203
201
  if (transpose) {
204
- setAxisLeftLabels(expression.cols);
202
+ setAxisLeftLabels(featureIndex);
205
203
  } else {
206
- setAxisTopLabels(expression.cols);
204
+ setAxisTopLabels(featureIndex);
207
205
  }
208
- }, [expression, transpose]);
206
+ }, [featureIndex, transpose]);
209
207
 
210
208
  const [longestCellLabel, longestGeneLabel] = useMemo(() => {
211
- if (!expression) {
209
+ if (!obsIndex || !featureIndex) {
212
210
  return ['', ''];
213
211
  }
214
212
 
215
213
  return [
216
- getLongestString(expression.rows),
217
- getLongestString([...expression.cols, ...cellColorLabels]),
214
+ getLongestString(obsIndex),
215
+ getLongestString([...featureIndex, ...cellColorLabels]),
218
216
  ];
219
- }, [expression, cellColorLabels]);
217
+ }, [featureIndex, cellColorLabels, obsIndex]);
220
218
 
221
219
  // Creating a look up dictionary once is faster than calling indexOf many times
222
220
  // i.e when cell ordering changes.
223
221
  const expressionRowLookUp = useMemo(() => {
224
222
  const lookUp = new Map();
225
- if (expression?.rows) {
223
+ if (obsIndex) {
226
224
  // eslint-disable-next-line no-return-assign
227
- expression.rows.forEach((cell, j) => (lookUp.set(cell, j)));
225
+ obsIndex.forEach((cell, j) => (lookUp.set(cell, j)));
228
226
  }
229
227
  return lookUp;
230
- }, [expression]);
228
+ }, [obsIndex]);
231
229
 
232
230
  const width = axisTopLabels.length;
233
231
  const height = axisLeftLabels.length;
@@ -274,7 +272,7 @@ const Heatmap = forwardRef((props, deckRef) => {
274
272
  useEffect(() => {
275
273
  updateViewInfo({
276
274
  uuid,
277
- project: (cellId, geneId) => {
275
+ projectFromId: (cellId, geneId) => {
278
276
  const colI = transpose ? axisTopLabels.indexOf(cellId) : axisTopLabels.indexOf(geneId);
279
277
  const rowI = transpose ? axisLeftLabels.indexOf(geneId) : axisLeftLabels.indexOf(cellId);
280
278
  return heatmapToMousePosition(
@@ -324,7 +322,7 @@ const Heatmap = forwardRef((props, deckRef) => {
324
322
  // then new tiles need to be generated,
325
323
  // so add a new task to the backlog.
326
324
  useEffect(() => {
327
- if (!expression || !expression.matrix || expression.matrix.length < DATA_TEXTURE_SIZE ** 2) {
325
+ if (!uint8ObsFeatureMatrix || uint8ObsFeatureMatrix.length < DATA_TEXTURE_SIZE ** 2) {
328
326
  return;
329
327
  }
330
328
  // Use a uuid to give the task a unique ID,
@@ -336,7 +334,7 @@ const Heatmap = forwardRef((props, deckRef) => {
336
334
  ) {
337
335
  setBacklog(prev => [...prev, uuidv4()]);
338
336
  }
339
- }, [dataRef, expression, axisTopLabels, axisLeftLabels, xTiles, yTiles]);
337
+ }, [dataRef, uint8ObsFeatureMatrix, axisTopLabels, axisLeftLabels, xTiles, yTiles]);
340
338
 
341
339
  // When the backlog has updated, a new worker job can be submitted if:
342
340
  // - the backlog has length >= 1 (at least one job is waiting), and
@@ -349,16 +347,15 @@ const Heatmap = forwardRef((props, deckRef) => {
349
347
  if (dataRef.current
350
348
  && dataRef.current.buffer.byteLength && expressionRowLookUp.size > 0
351
349
  && !shouldUsePaddedImplementation(dataRef.current.length)) {
352
- const { cols, matrix } = expression;
353
350
  const promises = range(yTiles).map(i => range(xTiles).map(async j => workerPool.process({
354
351
  curr,
355
352
  tileI: i,
356
353
  tileJ: j,
357
354
  tileSize: TILE_SIZE,
358
355
  cellOrdering: transpose ? axisTopLabels : axisLeftLabels,
359
- cols,
356
+ cols: featureIndex,
360
357
  transpose,
361
- data: matrix.buffer.slice(),
358
+ data: uint8ObsFeatureMatrix.buffer.slice(),
362
359
  expressionRowLookUp,
363
360
  })));
364
361
  const process = async () => {
@@ -374,8 +371,8 @@ const Heatmap = forwardRef((props, deckRef) => {
374
371
  };
375
372
  process();
376
373
  }
377
- }, [axisLeftLabels, axisTopLabels, backlog, expression, transpose,
378
- xTiles, yTiles, workerPool, expressionRowLookUp]);
374
+ }, [axisLeftLabels, axisTopLabels, backlog, uint8ObsFeatureMatrix, transpose,
375
+ xTiles, yTiles, workerPool, expressionRowLookUp, featureIndex]);
379
376
 
380
377
  useEffect(() => {
381
378
  setIsRendering(backlog.length > 0);
@@ -384,8 +381,8 @@ const Heatmap = forwardRef((props, deckRef) => {
384
381
  // Create the padded expression matrix for holding data which can then be bound to the GPU.
385
382
  const paddedExpressions = useMemo(() => {
386
383
  const cellOrdering = transpose ? axisTopLabels : axisLeftLabels;
387
- if (expression?.matrix && cellOrdering.length
388
- && gl && shouldUsePaddedImplementation(expression.matrix.length)) {
384
+ if (uint8ObsFeatureMatrix && cellOrdering.length
385
+ && gl && shouldUsePaddedImplementation(uint8ObsFeatureMatrix.length)) {
389
386
  let newIndex = 0;
390
387
  for (
391
388
  let cellOrderingIndex = 0;
@@ -397,13 +394,13 @@ const Heatmap = forwardRef((props, deckRef) => {
397
394
  const cellIndex = expressionRowLookUp.get(cell);
398
395
  for (
399
396
  let geneIndex = 0;
400
- geneIndex < expression.cols.length;
397
+ geneIndex < featureIndex.length;
401
398
  geneIndex += 1
402
399
  ) {
403
- const index = cellIndex * expression.cols.length + geneIndex;
400
+ const index = cellIndex * featureIndex.length + geneIndex;
404
401
  paddedExpressionContainer[
405
402
  newIndex % (DATA_TEXTURE_SIZE * DATA_TEXTURE_SIZE)
406
- ] = expression.matrix[index];
403
+ ] = uint8ObsFeatureMatrix[index];
407
404
  newIndex = transpose ? newIndex + cellOrdering.length : newIndex + 1;
408
405
  }
409
406
  }
@@ -425,8 +422,9 @@ const Heatmap = forwardRef((props, deckRef) => {
425
422
  transpose,
426
423
  axisTopLabels,
427
424
  axisLeftLabels,
428
- expression,
425
+ uint8ObsFeatureMatrix,
429
426
  expressionRowLookUp,
427
+ featureIndex,
430
428
  gl,
431
429
  ]);
432
430
 
@@ -436,8 +434,8 @@ const Heatmap = forwardRef((props, deckRef) => {
436
434
  // - the `aggSizeX` or `aggSizeY` have changed, or
437
435
  // - the cell ordering has changed.
438
436
  const heatmapLayers = useMemo(() => {
439
- const usePaddedExpressions = expression?.matrix
440
- && shouldUsePaddedImplementation(expression?.matrix.length);
437
+ const usePaddedExpressions = uint8ObsFeatureMatrix
438
+ && shouldUsePaddedImplementation(uint8ObsFeatureMatrix.length);
441
439
  if ((!tilesRef.current || backlog.length) && !usePaddedExpressions) {
442
440
  return [];
443
441
  }
@@ -445,7 +443,6 @@ const Heatmap = forwardRef((props, deckRef) => {
445
443
  const cellOrdering = transpose ? axisTopLabels : axisLeftLabels;
446
444
  // eslint-disable-next-line no-inner-declarations, no-shadow
447
445
  function getLayer(i, j) {
448
- const { cols } = expression;
449
446
  return new PaddedExpressionHeatmapBitmapLayer({
450
447
  id: `heatmapLayer-${i}-${j}`,
451
448
  image: paddedExpressions,
@@ -460,8 +457,8 @@ const Heatmap = forwardRef((props, deckRef) => {
460
457
  numXTiles: xTiles,
461
458
  numYTiles: yTiles,
462
459
  origDataSize: transpose
463
- ? [cols.length, cellOrdering.length]
464
- : [cellOrdering.length, cols.length],
460
+ ? [featureIndex.length, cellOrdering.length]
461
+ : [cellOrdering.length, featureIndex.length],
465
462
  aggSizeX,
466
463
  aggSizeY,
467
464
  colormap,
@@ -503,16 +500,24 @@ const Heatmap = forwardRef((props, deckRef) => {
503
500
  (tile, index) => getLayer(Math.floor(index / xTiles), index % xTiles, tile),
504
501
  );
505
502
  return layers;
506
- }, [expression, backlog.length, transpose, axisTopLabels, axisLeftLabels, yTiles, xTiles,
507
- paddedExpressions, matrixLeft, tileWidth, matrixTop, tileHeight,
508
- aggSizeX, aggSizeY, colormap, colormapRange, tileIteration]);
503
+ }, [uint8ObsFeatureMatrix, backlog.length, transpose, axisTopLabels, axisLeftLabels,
504
+ paddedExpressions, matrixLeft, tileWidth, matrixTop, tileHeight, yTiles, xTiles,
505
+ aggSizeX, aggSizeY, colormap, colormapRange, tileIteration, featureIndex]);
509
506
  const axisLeftDashes = (transpose ? variablesDashes : observationsDashes);
510
507
  const axisTopDashes = (transpose ? observationsDashes : variablesDashes);
511
508
 
512
509
  // Map cell and gene names to arrays with indices,
513
510
  // to prepare to render the names in TextLayers.
514
- const axisTopLabelData = useMemo(() => axisTopLabels.map((d, i) => [i, (axisTopDashes ? `- ${d}` : d)]), [axisTopLabels, axisTopDashes]);
515
- const axisLeftLabelData = useMemo(() => axisLeftLabels.map((d, i) => [i, (axisLeftDashes ? `${d} -` : d)]), [axisLeftLabels, axisLeftDashes]);
511
+ // We do the mapping with featureLabelsMap here at one of the final steps before rendering
512
+ // since it is for presentational purposes.
513
+ const axisTopLabelData = useMemo(() => (!transpose && featureLabelsMap
514
+ ? axisTopLabels.map(d => featureLabelsMap.get(d) || d)
515
+ : axisTopLabels
516
+ ).map((d, i) => [i, (axisTopDashes ? `- ${d}` : d)]), [axisTopLabels, axisTopDashes, transpose, featureLabelsMap]);
517
+ const axisLeftLabelData = useMemo(() => (transpose && featureLabelsMap
518
+ ? axisLeftLabels.map(d => featureLabelsMap.get(d) || d)
519
+ : axisLeftLabels
520
+ ).map((d, i) => [i, (axisLeftDashes ? `${d} -` : d)]), [axisLeftLabels, axisLeftDashes, transpose, featureLabelsMap]);
516
521
  const cellColorLabelsData = useMemo(() => cellColorLabels.map((d, i) => [i, d && (transpose ? `${d} -` : `- ${d}`)]), [cellColorLabels, transpose]);
517
522
 
518
523
  const hideTopLabels = (transpose ? hideObservationLabels : hideVariableLabels);
@@ -697,7 +702,7 @@ const Heatmap = forwardRef((props, deckRef) => {
697
702
 
698
703
  // Set up the onHover function.
699
704
  function onHover(info, event) {
700
- if (!expression) {
705
+ if (!uint8ObsFeatureMatrix) {
701
706
  return;
702
707
  }
703
708
 
@@ -728,10 +733,10 @@ const Heatmap = forwardRef((props, deckRef) => {
728
733
  setTrackHighlight(null);
729
734
  setColorEncoding('geneSelection');
730
735
  } else { // we are hovering over a cell colored track
731
- const obsI = expression.rows.indexOf(transpose
736
+ const obsI = obsIndex.indexOf(transpose
732
737
  ? axisTopLabels[trackColI]
733
738
  : axisLeftLabels[trackColI]);
734
- const cellIndex = expression.rows[obsI];
739
+ const cellIndex = obsIndex[obsI];
735
740
  setTrackHighlight([cellIndex, trackI, mouseX, mouseY]);
736
741
  highlightedCell = cellIndex;
737
742
  setColorEncoding('cellSelection');
@@ -749,17 +754,17 @@ const Heatmap = forwardRef((props, deckRef) => {
749
754
  numCols: width,
750
755
  });
751
756
 
752
- const obsI = expression.rows.indexOf(transpose
757
+ const obsI = obsIndex.indexOf(transpose
753
758
  ? axisTopLabels[colI]
754
759
  : axisLeftLabels[rowI]);
755
- const varI = expression.cols.indexOf(transpose
760
+ const varI = featureIndex.indexOf(transpose
756
761
  ? axisLeftLabels[rowI]
757
762
  : axisTopLabels[colI]);
758
763
 
759
- const obsId = expression.rows[obsI];
764
+ const obsId = obsIndex[obsI];
760
765
 
761
766
  // We need to use featureIndex here,
762
- // because expression.cols may be mapped to
767
+ // because featureIndex may be mapped to
763
768
  // use featureLabels (if those were available in the dataset).
764
769
  // Highlights and selections are assumed to be in terms of
765
770
  // obsIndex/featureIndex (as opposed to obsLabels/featureLabels).
@@ -1,7 +1,7 @@
1
1
  /* eslint-disable func-names */
2
+ import { describe, it, expect, afterEach } from 'vitest';
2
3
  import '@testing-library/jest-dom';
3
4
  import { cleanup, render } from '@testing-library/react';
4
- import { afterEach } from 'vitest';
5
5
  import React from 'react';
6
6
 
7
7
  import Heatmap from './Heatmap.js';
@@ -101,24 +101,25 @@ export function HeatmapSubscriber(props) {
101
101
  // setObsColorEncoding with 'geneSelection' or 'cellSetSelection' upon a click.
102
102
  const [hoveredColorEncoding, setHoveredColorEncoding] = useState('geneSelection');
103
103
 
104
- const [urls, addUrl] = useUrls(loaders, dataset);
105
104
  const [width, height, deckRef] = useDeckCanvasSize();
106
105
 
107
106
  // Get data from loaders using the data hooks.
108
107
  const [obsLabelsTypes, obsLabelsData] = useMultiObsLabels(
109
- coordinationScopes, obsType, loaders, dataset, addUrl,
108
+ coordinationScopes, obsType, loaders, dataset,
110
109
  );
111
110
  // TODO: support multiple feature labels using featureLabelsType coordination values.
112
- const [{ featureLabelsMap }, featureLabelsStatus] = useFeatureLabelsData(
113
- loaders, dataset, addUrl, false, {}, {},
111
+ const [{ featureLabelsMap }, featureLabelsStatus, featureLabelsUrls] = useFeatureLabelsData(
112
+ loaders, dataset, false, {}, {},
114
113
  { featureType },
115
114
  );
116
- const [{ obsIndex, featureIndex, obsFeatureMatrix }, matrixStatus] = useObsFeatureMatrixData(
117
- loaders, dataset, addUrl, true, {}, {},
115
+ const [
116
+ { obsIndex, featureIndex, obsFeatureMatrix }, matrixStatus, matrixUrls,
117
+ ] = useObsFeatureMatrixData(
118
+ loaders, dataset, true, {}, {},
118
119
  { obsType, featureType, featureValueType },
119
120
  );
120
- const [{ obsSets: cellSets, obsSetsMembership }, obsSetsStatus] = useObsSetsData(
121
- loaders, dataset, addUrl, false,
121
+ const [{ obsSets: cellSets, obsSetsMembership }, obsSetsStatus, obsSetsUrls] = useObsSetsData(
122
+ loaders, dataset, false,
122
123
  { setObsSetSelection: setCellSetSelection, setObsSetColor: setCellSetColor },
123
124
  { obsSetSelection: cellSetSelection, obsSetColor: cellSetColor },
124
125
  { obsType },
@@ -128,6 +129,11 @@ export function HeatmapSubscriber(props) {
128
129
  matrixStatus,
129
130
  obsSetsStatus,
130
131
  ]);
132
+ const urls = useUrls([
133
+ featureLabelsUrls,
134
+ matrixUrls,
135
+ obsSetsUrls,
136
+ ]);
131
137
 
132
138
  const [uint8ObsFeatureMatrix, obsFeatureMatrixExtent] = useUint8ObsFeatureMatrix(
133
139
  { obsFeatureMatrix },
@@ -160,20 +166,6 @@ export function HeatmapSubscriber(props) {
160
166
  return null;
161
167
  }, [variablesLabel, featureLabelsMap]);
162
168
 
163
- const expressionMatrix = useMemo(() => {
164
- if (obsIndex && featureIndex && uint8ObsFeatureMatrix) {
165
- return {
166
- rows: obsIndex,
167
- cols: (featureLabelsMap
168
- ? featureIndex.map(key => featureLabelsMap.get(key) || key)
169
- : featureIndex
170
- ),
171
- matrix: uint8ObsFeatureMatrix.data,
172
- };
173
- }
174
- return null;
175
- }, [obsIndex, featureIndex, uint8ObsFeatureMatrix, featureLabelsMap]);
176
-
177
169
  const cellsCount = obsIndex ? obsIndex.length : 0;
178
170
  const genesCount = featureIndex ? featureIndex.length : 0;
179
171
 
@@ -239,12 +231,14 @@ export function HeatmapSubscriber(props) {
239
231
  width={width}
240
232
  theme={theme}
241
233
  uuid={uuid}
242
- expressionMatrix={expressionMatrix}
234
+ uint8ObsFeatureMatrix={uint8ObsFeatureMatrix?.data}
243
235
  cellColors={cellColors}
244
236
  colormap={geneExpressionColormap}
245
237
  setIsRendering={setIsRendering}
246
238
  setCellHighlight={setCellHighlight}
247
239
  setGeneHighlight={setGeneHighlight}
240
+ featureLabelsMap={featureLabelsMap}
241
+ obsIndex={obsIndex}
248
242
  featureIndex={featureIndex}
249
243
  setTrackHighlight={setTrackHighlight}
250
244
  setComponentHover={() => {
@@ -16,8 +16,8 @@ export default function HeatmapTooltipSubscriber(props) {
16
16
  const [cellInfo, cellCoord] = (obsHighlight && getObsInfo ? (
17
17
  [
18
18
  getObsInfo(obsHighlight),
19
- (viewInfo && viewInfo.project
20
- ? viewInfo.project(obsHighlight, null)[(transpose ? 0 : 1)]
19
+ (viewInfo && viewInfo.projectFromId
20
+ ? viewInfo.projectFromId(obsHighlight, null)[(transpose ? 0 : 1)]
21
21
  : null),
22
22
  ]
23
23
  ) : ([null, null]));
@@ -25,8 +25,8 @@ export default function HeatmapTooltipSubscriber(props) {
25
25
  const [geneInfo, geneCoord] = (featureHighlight && getFeatureInfo ? (
26
26
  [
27
27
  getFeatureInfo(featureHighlight),
28
- (viewInfo && viewInfo.project
29
- ? viewInfo.project(null, featureHighlight)[(transpose ? 1 : 0)]
28
+ (viewInfo && viewInfo.projectFromId
29
+ ? viewInfo.projectFromId(null, featureHighlight)[(transpose ? 1 : 0)]
30
30
  : null),
31
31
  ]
32
32
  ) : ([null, null]));
package/src/utils.test.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { describe, it, expect } from 'vitest';
1
2
  import { mouseToHeatmapPosition, heatmapToMousePosition } from './utils.js';
2
3
 
3
4
  describe('heatmap tooltip utils', () => {