@vitessce/statistical-plots 3.4.5 → 3.4.7

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.
Files changed (47) hide show
  1. package/dist/deflate-c8c2f459.js +13 -0
  2. package/dist/index-a1925e78.js +206649 -0
  3. package/dist/index.js +13 -91680
  4. package/dist/jpeg-ffd14ffe.js +840 -0
  5. package/dist/lerc-9d1dd17e.js +2014 -0
  6. package/dist/lzw-3705b408.js +128 -0
  7. package/dist/packbits-6f657116.js +30 -0
  8. package/dist/pako.esm-68f84e2a.js +4022 -0
  9. package/dist/raw-0a76dec9.js +12 -0
  10. package/dist/webimage-fbdf3bdf.js +32 -0
  11. package/dist-tsc/CellSetExpressionPlot.d.ts.map +1 -1
  12. package/dist-tsc/CellSetExpressionPlot.js +207 -106
  13. package/dist-tsc/CellSetExpressionPlotOptions.d.ts.map +1 -1
  14. package/dist-tsc/CellSetExpressionPlotOptions.js +14 -4
  15. package/dist-tsc/CellSetExpressionPlotSubscriber.d.ts.map +1 -1
  16. package/dist-tsc/CellSetExpressionPlotSubscriber.js +15 -31
  17. package/dist-tsc/CellSetSizesPlot.d.ts.map +1 -1
  18. package/dist-tsc/CellSetSizesPlotSubscriber.d.ts.map +1 -1
  19. package/dist-tsc/DotPlot.d.ts +28 -0
  20. package/dist-tsc/DotPlot.d.ts.map +1 -0
  21. package/dist-tsc/DotPlot.js +144 -0
  22. package/dist-tsc/DotPlotSubscriber.d.ts +14 -0
  23. package/dist-tsc/DotPlotSubscriber.d.ts.map +1 -0
  24. package/dist-tsc/DotPlotSubscriber.js +54 -0
  25. package/dist-tsc/ExpressionHistogram.d.ts.map +1 -1
  26. package/dist-tsc/ExpressionHistogramSubscriber.d.ts.map +1 -1
  27. package/dist-tsc/dot-plot-hook.d.ts +23 -0
  28. package/dist-tsc/dot-plot-hook.d.ts.map +1 -0
  29. package/dist-tsc/dot-plot-hook.js +69 -0
  30. package/dist-tsc/expr-hooks.d.ts +51 -0
  31. package/dist-tsc/expr-hooks.d.ts.map +1 -0
  32. package/dist-tsc/expr-hooks.js +135 -0
  33. package/dist-tsc/expr-hooks.test.d.ts +2 -0
  34. package/dist-tsc/expr-hooks.test.d.ts.map +1 -0
  35. package/dist-tsc/expr-hooks.test.js +97 -0
  36. package/dist-tsc/index.d.ts +2 -0
  37. package/dist-tsc/index.js +2 -0
  38. package/package.json +10 -7
  39. package/src/CellSetExpressionPlot.js +223 -124
  40. package/src/CellSetExpressionPlotOptions.js +57 -1
  41. package/src/CellSetExpressionPlotSubscriber.js +45 -38
  42. package/src/DotPlot.js +175 -0
  43. package/src/DotPlotSubscriber.js +173 -0
  44. package/src/dot-plot-hook.js +107 -0
  45. package/src/expr-hooks.js +170 -0
  46. package/src/expr-hooks.test.js +116 -0
  47. package/src/index.js +2 -0
@@ -10,11 +10,20 @@ import {
10
10
  useSampleEdgesData,
11
11
  } from '@vitessce/vit-s';
12
12
  import { ViewType, COMPONENT_COORDINATION_TYPES } from '@vitessce/constants-internal';
13
- import { VALUE_TRANSFORM_OPTIONS, capitalize, getValueTransformFunction } from '@vitessce/utils';
14
- import { treeToObjectsBySetNames, treeToSetSizesBySetNames, mergeObsSets } from '@vitessce/sets-utils';
13
+ import { VALUE_TRANSFORM_OPTIONS, capitalize } from '@vitessce/utils';
14
+ import {
15
+ treeToSetSizesBySetNames,
16
+ mergeObsSets,
17
+ stratifyExpressionData,
18
+ aggregateStratifiedExpressionData,
19
+ } from '@vitessce/sets-utils';
15
20
  import CellSetExpressionPlotOptions from './CellSetExpressionPlotOptions.js';
16
21
  import CellSetExpressionPlot from './CellSetExpressionPlot.js';
17
22
  import { useStyles } from './styles.js';
23
+ import {
24
+ summarizeStratifiedExpressionData,
25
+ histogramStratifiedExpressionData,
26
+ } from './expr-hooks.js';
18
27
 
19
28
  /**
20
29
  * Get expression data for the cells
@@ -34,14 +43,13 @@ import { useStyles } from './styles.js';
34
43
  * feature value transform function.
35
44
  * @param {number} featureValueTransformCoefficient A coefficient
36
45
  * to be used in the transform function.
37
- * @param {string} theme "light" or "dark" for the vitessce theme
38
- * `path` and `color`.
39
46
  */
40
47
  function useExpressionByCellSet(
48
+ sampleEdges, sampleSets, sampleSetSelection,
41
49
  expressionData, obsIndex, cellSets, additionalCellSets,
42
50
  geneSelection, cellSetSelection, cellSetColor,
43
51
  featureValueTransform, featureValueTransformCoefficient,
44
- theme,
52
+ theme, yMinProp,
45
53
  ) {
46
54
  const mergedCellSets = useMemo(
47
55
  () => mergeObsSets(cellSets, additionalCellSets),
@@ -51,37 +59,29 @@ function useExpressionByCellSet(
51
59
  // From the expression matrix and the list of selected genes / cell sets,
52
60
  // generate the array of data points for the plot.
53
61
  const [expressionArr, expressionMax] = useMemo(() => {
54
- if (mergedCellSets && cellSetSelection
55
- && geneSelection && geneSelection.length >= 1
56
- && expressionData
57
- ) {
58
- const cellObjects = treeToObjectsBySetNames(
59
- mergedCellSets, cellSetSelection, cellSetColor, theme,
62
+ const [stratifiedData, exprMax] = stratifyExpressionData(
63
+ sampleEdges, sampleSets, sampleSetSelection,
64
+ expressionData, obsIndex, mergedCellSets,
65
+ geneSelection, cellSetSelection, cellSetColor,
66
+ featureValueTransform, featureValueTransformCoefficient,
67
+ );
68
+ if (stratifiedData) {
69
+ const aggregateData = aggregateStratifiedExpressionData(
70
+ stratifiedData, geneSelection,
60
71
  );
61
-
62
- const firstGeneSelected = geneSelection[0];
63
- // Create new cellColors map based on the selected gene.
64
- let exprMax = -Infinity;
65
- const cellIndices = {};
66
- for (let i = 0; i < obsIndex.length; i += 1) {
67
- cellIndices[obsIndex[i]] = i;
68
- }
69
- const exprValues = cellObjects.map((cell) => {
70
- const cellIndex = cellIndices[cell.obsId];
71
- const value = expressionData[0][cellIndex];
72
- const transformFunction = getValueTransformFunction(
73
- featureValueTransform, featureValueTransformCoefficient,
74
- );
75
- const transformedValue = transformFunction(value);
76
- exprMax = Math.max(transformedValue, exprMax);
77
- return { value: transformedValue, gene: firstGeneSelected, set: cell.name };
78
- });
79
- return [exprValues, exprMax];
72
+ const summarizedData = summarizeStratifiedExpressionData(
73
+ aggregateData, true,
74
+ );
75
+ const histogramData = histogramStratifiedExpressionData(
76
+ summarizedData, 16, yMinProp,
77
+ );
78
+ return [histogramData, exprMax];
80
79
  }
81
80
  return [null, null];
82
81
  }, [expressionData, obsIndex, geneSelection, theme,
83
82
  mergedCellSets, cellSetSelection, cellSetColor,
84
83
  featureValueTransform, featureValueTransformCoefficient,
84
+ yMinProp, sampleEdges, sampleSets, sampleSetSelection,
85
85
  ]);
86
86
 
87
87
  // From the cell sets hierarchy and the list of selected cell sets,
@@ -96,7 +96,6 @@ function useExpressionByCellSet(
96
96
  return [expressionArr, setArr, expressionMax];
97
97
  }
98
98
 
99
-
100
99
  /**
101
100
  * A subscriber component for `CellSetExpressionPlot`,
102
101
  * which listens for gene selection updates and
@@ -135,9 +134,12 @@ export function CellSetExpressionPlotSubscriber(props) {
135
134
  obsSetColor: cellSetColor,
136
135
  additionalObsSets: additionalCellSets,
137
136
  sampleType,
137
+ sampleSetSelection,
138
+ sampleSetColor,
138
139
  }, {
139
140
  setFeatureValueTransform,
140
141
  setFeatureValueTransformCoefficient,
142
+ setSampleSetColor,
141
143
  }] = useCoordination(
142
144
  COMPONENT_COORDINATION_TYPES[ViewType.OBS_SET_FEATURE_VALUE_DISTRIBUTION],
143
145
  coordinationScopes,
@@ -167,13 +169,13 @@ export function CellSetExpressionPlotSubscriber(props) {
167
169
  { obsType },
168
170
  );
169
171
 
170
- // eslint-disable-next-line no-unused-vars
171
172
  const [{ sampleSets }, sampleSetsStatus, sampleSetsUrls] = useSampleSetsData(
172
- loaders, dataset, false, {}, {},
173
+ loaders, dataset, false,
174
+ { setSampleSetColor },
175
+ { sampleSetColor },
173
176
  { sampleType },
174
177
  );
175
178
 
176
- // eslint-disable-next-line no-unused-vars
177
179
  const [{ sampleEdges }, sampleEdgesStatus, sampleEdgesUrls] = useSampleEdgesData(
178
180
  loaders, dataset, false, {}, {},
179
181
  { obsType, sampleType },
@@ -195,11 +197,12 @@ export function CellSetExpressionPlotSubscriber(props) {
195
197
  sampleEdgesUrls,
196
198
  ]);
197
199
 
198
- const [expressionArr, setArr] = useExpressionByCellSet(
200
+ const [histogramData, setArr, exprMax] = useExpressionByCellSet(
201
+ sampleEdges, sampleSets, sampleSetSelection,
199
202
  expressionData, obsIndex, cellSets, additionalCellSets,
200
203
  geneSelection, cellSetSelection, cellSetColor,
201
204
  featureValueTransform, featureValueTransformCoefficient,
202
- theme,
205
+ theme, yMin,
203
206
  );
204
207
 
205
208
  const firstGeneSelected = geneSelection && geneSelection.length >= 1
@@ -230,13 +233,17 @@ export function CellSetExpressionPlotSubscriber(props) {
230
233
  )}
231
234
  >
232
235
  <div ref={containerRef} className={classes.vegaContainer}>
233
- {expressionArr ? (
236
+ {histogramData ? (
234
237
  <CellSetExpressionPlot
235
238
  yMin={yMin}
236
239
  yUnits={yUnits}
237
240
  jitter={jitter}
241
+ cellSetSelection={cellSetSelection}
242
+ sampleSetSelection={sampleSetSelection}
243
+ sampleSetColor={sampleSetColor}
238
244
  colors={setArr}
239
- data={expressionArr}
245
+ data={histogramData}
246
+ exprMax={exprMax}
240
247
  theme={theme}
241
248
  width={width}
242
249
  height={height}
package/src/DotPlot.js ADDED
@@ -0,0 +1,175 @@
1
+ import React from 'react';
2
+ import { clamp } from 'lodash-es';
3
+ import { VegaPlot, VEGA_THEMES } from '@vitessce/vega';
4
+ import { capitalize, pluralize as plur } from '@vitessce/utils';
5
+
6
+ /**
7
+ * Gene expression dot plot,
8
+ * implemented with the VegaPlot component.
9
+ * @param {object} props
10
+ * @param {object[]} props.data The expression data, an array
11
+ * of objects with properties `value`, `gene`, and `set`.
12
+ * @param {string} props.theme The name of the current Vitessce theme.
13
+ * @param {number} props.width The container width.
14
+ * @param {number} props.height The container height.
15
+ * @param {number} props.marginRight The size of the margin
16
+ * on the right side of the plot, to account for the vega menu button.
17
+ * By default, 90.
18
+ * @param {number} props.marginBottom The size of the margin
19
+ * on the bottom of the plot, to account for long x-axis labels.
20
+ * Default is allowing the component to automatically determine the margin.
21
+ * @param {string|null} props.featureValueTransformName A name
22
+ * for the feature value transformation function.
23
+ */
24
+ export default function DotPlot(props) {
25
+ const {
26
+ isStratified,
27
+ transpose,
28
+ data: rawData,
29
+ theme,
30
+ width,
31
+ height,
32
+ marginRight,
33
+ marginBottom,
34
+ obsType,
35
+ keyLength = 36,
36
+ featureType,
37
+ featureValueType,
38
+ featureValueTransformName,
39
+ featureValueColormap,
40
+ cellSetSelection,
41
+ } = props;
42
+
43
+ // Add a property `keyGroup` and `keyFeature` which concatenates the key and the name,
44
+ // which is both unique and can easily be converted
45
+ // back to the name by taking a substring.
46
+ const data = rawData.map(d => ({
47
+ ...d,
48
+ keyGroup: d.groupKey + d.group,
49
+ keyFeature: d.featureKey + d.feature,
50
+ keyGroupSecondary: d.secondaryGroupKey + d.secondaryGroup,
51
+ }));
52
+
53
+ // Get the max characters in an axis label for autsizing the bottom margin.
54
+ const maxCharactersForGroup = data.reduce((acc, val) => {
55
+ // eslint-disable-next-line no-param-reassign
56
+ acc = acc === undefined || val.group?.length > acc ? val.group?.length : acc;
57
+ return acc;
58
+ }, 0);
59
+ const maxCharactersForFeature = data.reduce((acc, val) => {
60
+ // eslint-disable-next-line no-param-reassign
61
+ acc = acc === undefined || val.feature.length > acc ? val.feature.length : acc;
62
+ return acc;
63
+ }, 0);
64
+ const maxCharactersForSampleSet = isStratified ? data.reduce((acc, val) => {
65
+ // eslint-disable-next-line no-param-reassign
66
+ acc = acc === undefined || val.secondaryGroup.length > acc ? val.secondaryGroup.length : acc;
67
+ return acc;
68
+ }, 0) : 0;
69
+
70
+
71
+ // Use a square-root term because the angle of the labels is 45 degrees (see below)
72
+ // so the perpendicular distance to the bottom of the labels is proportional to the
73
+ // square root of the length of the labels along the imaginary hypotenuse.
74
+ // 30 is an estimate of the pixel size of a given character and seems to work well.
75
+ const autoMarginForFeature = marginBottom
76
+ || 30 + Math.sqrt(maxCharactersForFeature / 2) * 30;
77
+ const autoMarginForGroup = marginRight
78
+ || 30 + Math.sqrt(maxCharactersForGroup / 2) * 30;
79
+ const autoMarginForSampleSet = marginRight
80
+ || 30 + Math.sqrt(maxCharactersForSampleSet / 2) * 30;
81
+
82
+ const plotWidth = transpose
83
+ ? clamp(width - autoMarginForFeature - 180, 10, Infinity) / (cellSetSelection?.length || 1)
84
+ : clamp(width - autoMarginForGroup - autoMarginForSampleSet - 200, 10, Infinity);
85
+ const plotHeight = transpose
86
+ ? clamp((height - autoMarginForGroup - autoMarginForSampleSet - 50), 10, Infinity)
87
+ : clamp((height - autoMarginForFeature - 80), 10, Infinity) / (cellSetSelection?.length || 1);
88
+
89
+ // Get an array of keys for sorting purposes.
90
+ const groupKeys = data.map(d => d.keyGroup);
91
+ const featureKeys = data.map(d => d.keyFeature);
92
+ const groupSecondaryKeys = data.map(d => d.keyGroupSecondary);
93
+
94
+
95
+ const meanTransform = (featureValueTransformName && featureValueTransformName !== 'None')
96
+ // Mean Log-Transformed Normalized Expression
97
+ ? [`Mean ${featureValueTransformName}-transformed`, `normalized ${featureValueType}`, 'in set']
98
+ // Mean Normalized Expression
99
+ : ['Mean normalized', `${featureValueType} in set`];
100
+
101
+ const spec = {
102
+ mark: {
103
+ type: 'circle',
104
+ // The Vega-Lite default opacity is 0.7 for point, tick, circle,
105
+ // or square marks.
106
+ // Reference: https://vega.github.io/vega-lite/docs/mark.html
107
+ opacity: 1.0,
108
+ },
109
+ encoding: {
110
+ [(transpose ? 'y' : 'x')]: {
111
+ field: 'keyFeature',
112
+ type: 'nominal',
113
+ axis: { labelExpr: `substring(datum.label, ${keyLength})` },
114
+ title: capitalize(featureType),
115
+ sort: featureKeys,
116
+ },
117
+ [(transpose ? 'column' : 'row')]: {
118
+ field: 'keyGroup',
119
+ type: 'nominal',
120
+ header: transpose
121
+ ? { labelExpr: `substring(datum.label, ${keyLength})`, labelAngle: -60, labelAlign: 'right', titleOrient: 'bottom', labelOrient: 'bottom' }
122
+ : { labelExpr: `substring(datum.label, ${keyLength})`, labelAngle: 0, labelAlign: 'left' },
123
+ title: `${capitalize(obsType)} Set`,
124
+ sort: groupKeys,
125
+ spacing: 0,
126
+ },
127
+ color: {
128
+ field: 'meanExpInGroup',
129
+ type: 'quantitative',
130
+ title: meanTransform,
131
+ scale: {
132
+ scheme: featureValueColormap,
133
+ },
134
+ legend: {
135
+ direction: 'horizontal',
136
+ tickCount: 2,
137
+ },
138
+ },
139
+ [(transpose ? 'x' : 'y')]: {
140
+ field: 'keyGroupSecondary',
141
+ type: 'nominal',
142
+ axis: { labelExpr: `substring(datum.label, ${keyLength})` },
143
+ title: null, // TODO: use sampleType
144
+ sort: groupSecondaryKeys,
145
+ },
146
+ size: {
147
+ field: 'pctPosInGroup',
148
+ type: 'quantitative',
149
+ title: [`Percentage of ${plur(obsType, 2)}`, 'in set'],
150
+ legend: {
151
+ symbolFillColor: 'white',
152
+ },
153
+ },
154
+ },
155
+ width: plotWidth,
156
+ height: plotHeight,
157
+ config: {
158
+ ...VEGA_THEMES[theme],
159
+ ...(!isStratified ? {
160
+ // Remove the row/column outlines when
161
+ // not stratified by sample set.
162
+ view: {
163
+ stroke: 'transparent',
164
+ },
165
+ } : {}),
166
+ },
167
+ };
168
+
169
+ return (
170
+ <VegaPlot
171
+ data={data}
172
+ spec={spec}
173
+ />
174
+ );
175
+ }
@@ -0,0 +1,173 @@
1
+ import React from 'react';
2
+ import {
3
+ TitleInfo,
4
+ useCoordination, useLoaders,
5
+ useUrls, useReady, useGridItemSize,
6
+ useFeatureSelection, useObsSetsData,
7
+ useObsFeatureMatrixIndices,
8
+ useFeatureLabelsData,
9
+ useSampleSetsData,
10
+ useSampleEdgesData,
11
+ } from '@vitessce/vit-s';
12
+ import { ViewType, COMPONENT_COORDINATION_TYPES } from '@vitessce/constants-internal';
13
+ import { VALUE_TRANSFORM_OPTIONS } from '@vitessce/utils';
14
+ import CellSetExpressionPlotOptions from './CellSetExpressionPlotOptions.js';
15
+ import DotPlot from './DotPlot.js';
16
+ import { useStyles } from './styles.js';
17
+ import { useExpressionSummaries } from './dot-plot-hook.js';
18
+
19
+
20
+ /**
21
+ * A subscriber component for DotPlot.
22
+ * @param {object} props
23
+ * @param {function} props.removeGridComponent The grid component removal function.
24
+ * @param {object} props.coordinationScopes An object mapping coordination
25
+ * types to coordination scopes.
26
+ * @param {string} props.theme The name of the current Vitessce theme.
27
+ */
28
+ export function DotPlotSubscriber(props) {
29
+ const {
30
+ coordinationScopes,
31
+ removeGridComponent,
32
+ theme,
33
+ title = 'Dot Plot',
34
+ transpose = true,
35
+ } = props;
36
+
37
+ const classes = useStyles();
38
+ const loaders = useLoaders();
39
+
40
+ // Get "props" from the coordination space.
41
+ const [{
42
+ dataset,
43
+ obsType,
44
+ featureType,
45
+ featureValueType,
46
+ featureSelection: geneSelection,
47
+ featureValueTransform,
48
+ featureValueTransformCoefficient,
49
+ featureValuePositivityThreshold: posThreshold,
50
+ featureValueColormap,
51
+ obsSetSelection: cellSetSelection,
52
+ obsSetColor: cellSetColor,
53
+ additionalObsSets: additionalCellSets,
54
+ sampleType,
55
+ sampleSetSelection,
56
+ }, {
57
+ setFeatureValueTransform,
58
+ setFeatureValueTransformCoefficient,
59
+ setFeatureValuePositivityThreshold: setPosThreshold,
60
+ setFeatureValueColormap,
61
+ }] = useCoordination(
62
+ COMPONENT_COORDINATION_TYPES[ViewType.DOT_PLOT],
63
+ coordinationScopes,
64
+ );
65
+
66
+ const [width, height, containerRef] = useGridItemSize();
67
+
68
+ const transformOptions = VALUE_TRANSFORM_OPTIONS;
69
+ const isStratified = Array.isArray(sampleSetSelection) && sampleSetSelection.length > 1;
70
+
71
+ // Get data from loaders using the data hooks.
72
+ // eslint-disable-next-line no-unused-vars
73
+ const [expressionData, loadedFeatureSelection, featureSelectionStatus] = useFeatureSelection(
74
+ loaders, dataset, false, geneSelection,
75
+ { obsType, featureType, featureValueType },
76
+ );
77
+ // TODO: support multiple feature labels using featureLabelsType coordination values.
78
+ const [{ featureLabelsMap }, featureLabelsStatus, featureLabelsUrl] = useFeatureLabelsData(
79
+ loaders, dataset, false, {}, {},
80
+ { featureType },
81
+ );
82
+ const [{ obsIndex }, matrixIndicesStatus, matrixIndicesUrl] = useObsFeatureMatrixIndices(
83
+ loaders, dataset, false,
84
+ { obsType, featureType, featureValueType },
85
+ );
86
+ const [{ obsSets: cellSets }, obsSetsStatus, obsSetsUrl] = useObsSetsData(
87
+ loaders, dataset, true, {}, {},
88
+ { obsType },
89
+ );
90
+
91
+ const [{ sampleSets }, sampleSetsStatus, sampleSetsUrl] = useSampleSetsData(
92
+ loaders, dataset, false, {}, {},
93
+ { sampleType },
94
+ );
95
+
96
+ const [{ sampleEdges }, sampleEdgesStatus, sampleEdgesUrl] = useSampleEdgesData(
97
+ loaders, dataset, false, {}, {},
98
+ { obsType, sampleType },
99
+ );
100
+
101
+ const isReady = useReady([
102
+ featureSelectionStatus,
103
+ matrixIndicesStatus,
104
+ obsSetsStatus,
105
+ featureLabelsStatus,
106
+ sampleSetsStatus,
107
+ sampleEdgesStatus,
108
+ ]);
109
+ const urls = useUrls([
110
+ featureLabelsUrl,
111
+ matrixIndicesUrl,
112
+ obsSetsUrl,
113
+ sampleSetsUrl,
114
+ sampleEdgesUrl,
115
+ ]);
116
+
117
+ const [resultArr, meanExpressionMax] = useExpressionSummaries(
118
+ sampleEdges, sampleSets, sampleSetSelection,
119
+ expressionData, obsIndex, cellSets, additionalCellSets,
120
+ geneSelection, cellSetSelection, cellSetColor,
121
+ featureValueTransform, featureValueTransformCoefficient,
122
+ posThreshold, featureLabelsMap,
123
+
124
+ );
125
+ const selectedTransformName = transformOptions.find(
126
+ o => o.value === featureValueTransform,
127
+ )?.name;
128
+
129
+ return (
130
+ <TitleInfo
131
+ title={title}
132
+ removeGridComponent={removeGridComponent}
133
+ urls={urls}
134
+ theme={theme}
135
+ isReady={isReady}
136
+ options={(
137
+ <CellSetExpressionPlotOptions
138
+ featureValueTransform={featureValueTransform}
139
+ setFeatureValueTransform={setFeatureValueTransform}
140
+ featureValueTransformCoefficient={featureValueTransformCoefficient}
141
+ setFeatureValueTransformCoefficient={setFeatureValueTransformCoefficient}
142
+ transformOptions={transformOptions}
143
+ featureValuePositivityThreshold={posThreshold}
144
+ setFeatureValuePositivityThreshold={setPosThreshold}
145
+ featureValueColormap={featureValueColormap}
146
+ setFeatureValueColormap={setFeatureValueColormap}
147
+ />
148
+ )}
149
+ >
150
+ <div ref={containerRef} className={classes.vegaContainer}>
151
+ {resultArr ? (
152
+ <DotPlot
153
+ isStratified={isStratified}
154
+ transpose={transpose}
155
+ domainMax={meanExpressionMax}
156
+ data={resultArr}
157
+ theme={theme}
158
+ width={width}
159
+ height={height}
160
+ obsType={obsType}
161
+ featureType={featureType}
162
+ featureValueType={featureValueType}
163
+ featureValueTransformName={selectedTransformName}
164
+ featureValueColormap={featureValueColormap}
165
+ cellSetSelection={cellSetSelection}
166
+ />
167
+ ) : (
168
+ <span>Select at least one {featureType}.</span>
169
+ )}
170
+ </div>
171
+ </TitleInfo>
172
+ );
173
+ }
@@ -0,0 +1,107 @@
1
+
2
+ import { useMemo } from 'react';
3
+ import { InternMap } from 'internmap';
4
+ import { v4 as uuidv4 } from 'uuid';
5
+ import {
6
+ mergeObsSets,
7
+ stratifyExpressionData,
8
+ } from '@vitessce/sets-utils';
9
+ import {
10
+ dotStratifiedExpressionData,
11
+ } from './expr-hooks.js';
12
+
13
+ /**
14
+ * Get expression data for the cells
15
+ * in the selected cell sets.
16
+ * @param {object} expressionMatrix
17
+ * @param {string[]} expressionMatrix.rows Cell IDs.
18
+ * @param {string[]} expressionMatrix.cols Gene names.
19
+ * @param {Uint8Array} expressionMatrix.matrix The
20
+ * flattened expression matrix as a typed array.
21
+ * @param {object} cellSets The cell sets from the dataset.
22
+ * @param {object} additionalCellSets The user-defined cell sets
23
+ * from the coordination space.
24
+ * @param {array} geneSelection Array of selected genes.
25
+ * @param {array} cellSetSelection Array of selected cell set paths.
26
+ * @param {object[]} cellSetColor Array of objects with properties
27
+ * @param {string|null} featureValueTransform The name of the
28
+ * feature value transform function.
29
+ * @param {number} featureValueTransformCoefficient A coefficient
30
+ * to be used in the transform function.
31
+ * @param {string} theme "light" or "dark" for the vitessce theme
32
+ * `path` and `color`.
33
+ */
34
+ export function useExpressionSummaries(
35
+ sampleEdges, sampleSets, sampleSetSelection,
36
+ expressionData, obsIndex, cellSets, additionalCellSets,
37
+ geneSelection, cellSetSelection, cellSetColor,
38
+ featureValueTransform, featureValueTransformCoefficient,
39
+ posThreshold, featureLabelsMap,
40
+ ) {
41
+ const mergedCellSets = useMemo(
42
+ () => mergeObsSets(cellSets, additionalCellSets),
43
+ [cellSets, additionalCellSets],
44
+ );
45
+
46
+ // From the expression matrix and the list of selected genes / cell sets,
47
+ // generate the array of data points for the plot.
48
+ const [resultArr, meanExpressionMax] = useMemo(() => {
49
+ const [stratifiedData, exprMax] = stratifyExpressionData(
50
+ sampleEdges, sampleSets, sampleSetSelection,
51
+ expressionData, obsIndex, mergedCellSets,
52
+ geneSelection, cellSetSelection, cellSetColor,
53
+ featureValueTransform, featureValueTransformCoefficient,
54
+ );
55
+ if (stratifiedData) {
56
+ const dotData = dotStratifiedExpressionData(
57
+ stratifiedData, posThreshold,
58
+ );
59
+
60
+ const geneToUuid = new Map(geneSelection?.map(gene => [gene, uuidv4()]));
61
+ const cellSetToUuid = new InternMap(
62
+ cellSetSelection?.map(sampleSet => ([sampleSet, uuidv4()])),
63
+ JSON.stringify,
64
+ );
65
+ const sampleSetToUuid = new InternMap(
66
+ sampleSetSelection?.map(sampleSet => ([sampleSet, uuidv4()])),
67
+ JSON.stringify,
68
+ );
69
+
70
+ const result = [];
71
+ ([...dotData.keys()]).forEach((cellSetKey) => {
72
+ ([...dotData.get(cellSetKey).keys()]).forEach((sampleSetKey) => {
73
+ ([...dotData.get(cellSetKey).get(sampleSetKey).keys()]).forEach((geneKey) => {
74
+ const dotObj = dotData.get(cellSetKey).get(sampleSetKey).get(geneKey);
75
+ const featureName = geneKey;
76
+ result.push({
77
+ key: uuidv4(), // Unique key for this dot.
78
+
79
+ featureKey: geneToUuid.get(geneKey),
80
+ feature: featureLabelsMap?.get(featureName) || featureName,
81
+
82
+ groupKey: cellSetToUuid.get(cellSetKey),
83
+ group: cellSetKey?.at(-1),
84
+
85
+ secondaryGroup: sampleSetKey?.at(-1),
86
+ secondaryGroupKey: sampleSetToUuid.get(sampleSetKey),
87
+
88
+ meanExpInGroup: dotObj.meanExpInGroup,
89
+ fracPosInGroup: dotObj.fracPosInGroup,
90
+ pctPosInGroup: dotObj.fracPosInGroup * 100.0,
91
+ });
92
+ });
93
+ });
94
+ });
95
+
96
+ return [result, exprMax];
97
+ }
98
+ return [null, null];
99
+ }, [expressionData, obsIndex, geneSelection,
100
+ mergedCellSets, cellSetSelection,
101
+ featureValueTransform, featureValueTransformCoefficient,
102
+ posThreshold, featureLabelsMap,
103
+ sampleEdges, sampleSets, sampleSetSelection,
104
+ ]);
105
+
106
+ return [resultArr, meanExpressionMax];
107
+ }