@vitessce/statistical-plots 3.4.6 → 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.
- package/dist/deflate-c8c2f459.js +13 -0
- package/dist/index-a1925e78.js +206649 -0
- package/dist/index.js +13 -91680
- package/dist/jpeg-ffd14ffe.js +840 -0
- package/dist/lerc-9d1dd17e.js +2014 -0
- package/dist/lzw-3705b408.js +128 -0
- package/dist/packbits-6f657116.js +30 -0
- package/dist/pako.esm-68f84e2a.js +4022 -0
- package/dist/raw-0a76dec9.js +12 -0
- package/dist/webimage-fbdf3bdf.js +32 -0
- package/dist-tsc/CellSetExpressionPlot.d.ts.map +1 -1
- package/dist-tsc/CellSetExpressionPlot.js +207 -106
- package/dist-tsc/CellSetExpressionPlotOptions.d.ts.map +1 -1
- package/dist-tsc/CellSetExpressionPlotOptions.js +14 -4
- package/dist-tsc/CellSetExpressionPlotSubscriber.d.ts.map +1 -1
- package/dist-tsc/CellSetExpressionPlotSubscriber.js +15 -31
- package/dist-tsc/CellSetSizesPlot.d.ts.map +1 -1
- package/dist-tsc/CellSetSizesPlotSubscriber.d.ts.map +1 -1
- package/dist-tsc/DotPlot.d.ts +28 -0
- package/dist-tsc/DotPlot.d.ts.map +1 -0
- package/dist-tsc/DotPlot.js +144 -0
- package/dist-tsc/DotPlotSubscriber.d.ts +14 -0
- package/dist-tsc/DotPlotSubscriber.d.ts.map +1 -0
- package/dist-tsc/DotPlotSubscriber.js +54 -0
- package/dist-tsc/ExpressionHistogram.d.ts.map +1 -1
- package/dist-tsc/ExpressionHistogramSubscriber.d.ts.map +1 -1
- package/dist-tsc/dot-plot-hook.d.ts +23 -0
- package/dist-tsc/dot-plot-hook.d.ts.map +1 -0
- package/dist-tsc/dot-plot-hook.js +69 -0
- package/dist-tsc/expr-hooks.d.ts +51 -0
- package/dist-tsc/expr-hooks.d.ts.map +1 -0
- package/dist-tsc/expr-hooks.js +135 -0
- package/dist-tsc/expr-hooks.test.d.ts +2 -0
- package/dist-tsc/expr-hooks.test.d.ts.map +1 -0
- package/dist-tsc/expr-hooks.test.js +97 -0
- package/dist-tsc/index.d.ts +2 -0
- package/dist-tsc/index.js +2 -0
- package/package.json +10 -7
- package/src/CellSetExpressionPlot.js +223 -124
- package/src/CellSetExpressionPlotOptions.js +57 -1
- package/src/CellSetExpressionPlotSubscriber.js +45 -38
- package/src/DotPlot.js +175 -0
- package/src/DotPlotSubscriber.js +173 -0
- package/src/dot-plot-hook.js +107 -0
- package/src/expr-hooks.js +170 -0
- package/src/expr-hooks.test.js +116 -0
- 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
|
14
|
-
import {
|
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
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
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
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
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 [
|
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
|
-
{
|
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={
|
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
|
+
}
|