@vitessce/statistical-plots 3.5.10 → 3.5.12
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-ad0dcbe4.js → deflate-9e272e07.js} +1 -1
- package/dist/{index-b8398176.js → index-fa429ace.js} +230 -83
- package/dist/index.js +1 -1
- package/dist/{jpeg-81bd1053.js → jpeg-affe217d.js} +1 -1
- package/dist/{lerc-b15c3a4c.js → lerc-eeb05714.js} +1 -1
- package/dist/{lzw-503cb795.js → lzw-fdf7d374.js} +1 -1
- package/dist/{packbits-40cbad40.js → packbits-530d3977.js} +1 -1
- package/dist/{raw-9b8d9daf.js → raw-5d9364f4.js} +1 -1
- package/dist/{webimage-bbc59b4a.js → webimage-57a383de.js} +1 -1
- package/dist-tsc/CellSetCompositionBarPlot.d.ts.map +1 -1
- package/dist-tsc/CellSetCompositionBarPlot.js +28 -7
- package/dist-tsc/CellSetExpressionPlotOptions.d.ts.map +1 -1
- package/dist-tsc/CellSetExpressionPlotOptions.js +11 -4
- package/dist-tsc/CellSetExpressionPlotSubscriber.d.ts.map +1 -1
- package/dist-tsc/CellSetExpressionPlotSubscriber.js +43 -11
- package/dist-tsc/DotPlot.d.ts.map +1 -1
- package/dist-tsc/DotPlot.js +6 -2
- package/dist-tsc/FeatureSetEnrichmentBarPlot.d.ts.map +1 -1
- package/dist-tsc/FeatureSetEnrichmentBarPlot.js +7 -6
- package/dist-tsc/FeatureSetEnrichmentBarPlotSubscriber.d.ts.map +1 -1
- package/dist-tsc/FeatureSetEnrichmentBarPlotSubscriber.js +5 -2
- package/dist-tsc/TreemapSubscriber.d.ts.map +1 -1
- package/dist-tsc/TreemapSubscriber.js +10 -6
- package/dist-tsc/expr-hooks.d.ts.map +1 -1
- package/dist-tsc/expr-hooks.test.js +2 -1
- package/package.json +7 -7
- package/src/CellSetCompositionBarPlot.js +35 -9
- package/src/CellSetExpressionPlotOptions.js +39 -2
- package/src/CellSetExpressionPlotSubscriber.js +47 -11
- package/src/DotPlot.js +4 -2
- package/src/FeatureSetEnrichmentBarPlot.js +7 -6
- package/src/FeatureSetEnrichmentBarPlotSubscriber.js +5 -2
- package/src/TreemapSubscriber.js +20 -7
- package/src/expr-hooks.js +0 -1
- package/src/expr-hooks.test.js +2 -1
@@ -3,6 +3,10 @@ import { useId } from 'react-aria';
|
|
3
3
|
import { TableCell, TableRow, TextField, Slider } from '@material-ui/core';
|
4
4
|
import { usePlotOptionsStyles, OptionsContainer, OptionSelect } from '@vitessce/vit-s';
|
5
5
|
import { GLSL_COLORMAPS } from '@vitessce/gl';
|
6
|
+
import { capitalize } from '@vitessce/utils';
|
7
|
+
|
8
|
+
|
9
|
+
const FEATURE_AGGREGATION_STRATEGIES = ['first', 'last', 'sum', 'mean'];
|
6
10
|
|
7
11
|
export default function CellSetExpressionPlotOptions(props) {
|
8
12
|
const {
|
@@ -15,6 +19,8 @@ export default function CellSetExpressionPlotOptions(props) {
|
|
15
19
|
setFeatureValuePositivityThreshold,
|
16
20
|
featureValueColormap,
|
17
21
|
setFeatureValueColormap,
|
22
|
+
featureAggregationStrategy,
|
23
|
+
setFeatureAggregationStrategy,
|
18
24
|
} = props;
|
19
25
|
|
20
26
|
const cellSetExpressionPlotOptionsId = useId();
|
@@ -25,9 +31,13 @@ export default function CellSetExpressionPlotOptions(props) {
|
|
25
31
|
setFeatureValueColormap(event.target.value);
|
26
32
|
}
|
27
33
|
|
28
|
-
|
34
|
+
function handleTransformChange(event) {
|
29
35
|
setFeatureValueTransform(event.target.value === '' ? null : event.target.value);
|
30
|
-
}
|
36
|
+
}
|
37
|
+
|
38
|
+
function handleFeatureAggregationStrategyChange(event) {
|
39
|
+
setFeatureAggregationStrategy(event.target.value);
|
40
|
+
}
|
31
41
|
|
32
42
|
function handlePositivityThresholdChange(event, value) {
|
33
43
|
setFeatureValuePositivityThreshold(value);
|
@@ -119,6 +129,33 @@ export default function CellSetExpressionPlotOptions(props) {
|
|
119
129
|
/>
|
120
130
|
</TableCell>
|
121
131
|
</TableRow>
|
132
|
+
{setFeatureAggregationStrategy ? (
|
133
|
+
<TableRow>
|
134
|
+
<TableCell className={classes.labelCell} variant="head" scope="row">
|
135
|
+
<label
|
136
|
+
htmlFor={`feature-aggregation-strategy-${cellSetExpressionPlotOptionsId}`}
|
137
|
+
>
|
138
|
+
Feature Aggregation Strategy
|
139
|
+
</label>
|
140
|
+
</TableCell>
|
141
|
+
<TableCell className={classes.inputCell} variant="body">
|
142
|
+
<OptionSelect
|
143
|
+
className={classes.select}
|
144
|
+
value={featureAggregationStrategy ?? 'first'}
|
145
|
+
onChange={handleFeatureAggregationStrategyChange}
|
146
|
+
inputProps={{
|
147
|
+
id: `feature-aggregation-strategy-${cellSetExpressionPlotOptionsId}`,
|
148
|
+
}}
|
149
|
+
>
|
150
|
+
{FEATURE_AGGREGATION_STRATEGIES.map(opt => (
|
151
|
+
<option key={opt} value={opt}>
|
152
|
+
{capitalize(opt)}
|
153
|
+
</option>
|
154
|
+
))}
|
155
|
+
</OptionSelect>
|
156
|
+
</TableCell>
|
157
|
+
</TableRow>
|
158
|
+
) : null}
|
122
159
|
{setFeatureValuePositivityThreshold ? (
|
123
160
|
<TableRow key="transform-coefficient-option-row">
|
124
161
|
<TableCell className={classes.labelCell}>
|
@@ -26,6 +26,28 @@ import {
|
|
26
26
|
histogramStratifiedExpressionData,
|
27
27
|
} from './expr-hooks.js';
|
28
28
|
|
29
|
+
const DEFAULT_FEATURE_AGGREGATION_STRATEGY = 'first';
|
30
|
+
|
31
|
+
function featureSummary(geneSelection, featureAggregationStrategy) {
|
32
|
+
if (featureAggregationStrategy === 'first') {
|
33
|
+
return geneSelection?.[0];
|
34
|
+
} if (featureAggregationStrategy === 'last') {
|
35
|
+
return geneSelection?.at(-1);
|
36
|
+
} if (typeof featureAggregationStrategy === 'number') {
|
37
|
+
const i = featureAggregationStrategy;
|
38
|
+
return geneSelection?.[i];
|
39
|
+
} if (featureAggregationStrategy === 'sum') {
|
40
|
+
// TODO: make these .join()-ed labels more scalable,
|
41
|
+
// in particular, if more than 10 or so elements.
|
42
|
+
return geneSelection?.join(' + ');
|
43
|
+
} if (featureAggregationStrategy === 'mean') {
|
44
|
+
return `Mean of ${geneSelection?.join(', ')}`;
|
45
|
+
} if (featureAggregationStrategy === 'difference') {
|
46
|
+
return geneSelection?.join(' - ');
|
47
|
+
}
|
48
|
+
return '';
|
49
|
+
}
|
50
|
+
|
29
51
|
/**
|
30
52
|
* Get expression data for the cells
|
31
53
|
* in the selected cell sets.
|
@@ -50,7 +72,7 @@ function useExpressionByCellSet(
|
|
50
72
|
expressionData, obsIndex, cellSets, additionalCellSets,
|
51
73
|
geneSelection, cellSetSelection, cellSetColor,
|
52
74
|
featureValueTransform, featureValueTransformCoefficient,
|
53
|
-
theme, yMinProp,
|
75
|
+
theme, yMinProp, featureAggregationStrategy,
|
54
76
|
) {
|
55
77
|
const mergedCellSets = useMemo(
|
56
78
|
() => mergeObsSets(cellSets, additionalCellSets),
|
@@ -68,7 +90,7 @@ function useExpressionByCellSet(
|
|
68
90
|
);
|
69
91
|
if (stratifiedData) {
|
70
92
|
const aggregateData = aggregateStratifiedExpressionData(
|
71
|
-
stratifiedData, geneSelection,
|
93
|
+
stratifiedData, geneSelection, featureAggregationStrategy,
|
72
94
|
);
|
73
95
|
const summarizedData = summarizeStratifiedExpressionData(
|
74
96
|
aggregateData, true,
|
@@ -83,6 +105,7 @@ function useExpressionByCellSet(
|
|
83
105
|
mergedCellSets, cellSetSelection, cellSetColor,
|
84
106
|
featureValueTransform, featureValueTransformCoefficient,
|
85
107
|
yMinProp, sampleEdges, sampleSets, sampleSetSelection,
|
108
|
+
featureAggregationStrategy,
|
86
109
|
]);
|
87
110
|
|
88
111
|
// From the cell sets hierarchy and the list of selected cell sets,
|
@@ -140,10 +163,12 @@ export function CellSetExpressionPlotSubscriber(props) {
|
|
140
163
|
sampleType,
|
141
164
|
sampleSetSelection,
|
142
165
|
sampleSetColor,
|
166
|
+
featureAggregationStrategy,
|
143
167
|
}, {
|
144
168
|
setFeatureValueTransform,
|
145
169
|
setFeatureValueTransformCoefficient,
|
146
170
|
setSampleSetColor,
|
171
|
+
setFeatureAggregationStrategy,
|
147
172
|
}] = useCoordination(
|
148
173
|
COMPONENT_COORDINATION_TYPES[ViewType.OBS_SET_FEATURE_VALUE_DISTRIBUTION],
|
149
174
|
coordinationScopes,
|
@@ -206,26 +231,35 @@ export function CellSetExpressionPlotSubscriber(props) {
|
|
206
231
|
sampleEdgesUrls,
|
207
232
|
]);
|
208
233
|
|
234
|
+
const featureAggregationStrategyToUse = featureAggregationStrategy
|
235
|
+
?? DEFAULT_FEATURE_AGGREGATION_STRATEGY;
|
236
|
+
|
209
237
|
const [histogramData, setArr, exprMax] = useExpressionByCellSet(
|
210
238
|
sampleEdges, sampleSets, sampleSetSelection,
|
211
239
|
expressionData, obsIndex, cellSets, additionalCellSets,
|
212
240
|
geneSelection, cellSetSelection, cellSetColor,
|
213
241
|
featureValueTransform, featureValueTransformCoefficient,
|
214
|
-
theme, yMin,
|
242
|
+
theme, yMin, featureAggregationStrategyToUse,
|
215
243
|
);
|
216
244
|
|
217
|
-
const
|
218
|
-
|
219
|
-
featureLabelsMap?.get(
|
220
|
-
|| featureLabelsMap?.get(cleanFeatureId(
|
221
|
-
||
|
222
|
-
)
|
223
|
-
|
245
|
+
const featureSuffix = useMemo(() => {
|
246
|
+
const cleanedGeneSelection = geneSelection?.map(geneName => (
|
247
|
+
featureLabelsMap?.get(geneName)
|
248
|
+
|| featureLabelsMap?.get(cleanFeatureId(geneName))
|
249
|
+
|| geneName
|
250
|
+
));
|
251
|
+
if (Array.isArray(cleanedGeneSelection)) {
|
252
|
+
return featureSummary(cleanedGeneSelection, featureAggregationStrategyToUse);
|
253
|
+
}
|
254
|
+
return null;
|
255
|
+
}, [geneSelection, featureAggregationStrategyToUse]);
|
256
|
+
|
257
|
+
|
224
258
|
const selectedTransformName = transformOptions.find(
|
225
259
|
o => o.value === featureValueTransform,
|
226
260
|
)?.name;
|
227
261
|
// Use empty string when firstGeneSelected is null
|
228
|
-
const titleSuffix =
|
262
|
+
const titleSuffix = featureSuffix ? ` (${featureSuffix})` : '';
|
229
263
|
|
230
264
|
return (
|
231
265
|
<TitleInfo
|
@@ -246,6 +280,8 @@ export function CellSetExpressionPlotSubscriber(props) {
|
|
246
280
|
featureValueTransformCoefficient={featureValueTransformCoefficient}
|
247
281
|
setFeatureValueTransformCoefficient={setFeatureValueTransformCoefficient}
|
248
282
|
transformOptions={transformOptions}
|
283
|
+
featureAggregationStrategy={featureAggregationStrategy}
|
284
|
+
setFeatureAggregationStrategy={setFeatureAggregationStrategy}
|
249
285
|
/>
|
250
286
|
)}
|
251
287
|
>
|
package/src/DotPlot.js
CHANGED
@@ -39,7 +39,8 @@ export default function DotPlot(props) {
|
|
39
39
|
featureType,
|
40
40
|
featureValueType,
|
41
41
|
featureValueTransformName,
|
42
|
-
featureValueColormap
|
42
|
+
// TODO: re-enable featureValueColormap coordination
|
43
|
+
// featureValueColormap,
|
43
44
|
obsSetSelection,
|
44
45
|
obsSetColor,
|
45
46
|
} = props;
|
@@ -134,7 +135,8 @@ export default function DotPlot(props) {
|
|
134
135
|
type: 'quantitative',
|
135
136
|
title: meanTransform,
|
136
137
|
scale: {
|
137
|
-
scheme: featureValueColormap,
|
138
|
+
// scheme: featureValueColormap,
|
139
|
+
scheme: 'greys',
|
138
140
|
},
|
139
141
|
legend: {
|
140
142
|
direction: 'horizontal',
|
@@ -14,7 +14,7 @@ export default function FeatureSetEnrichmentBarPlot(props) {
|
|
14
14
|
theme,
|
15
15
|
width,
|
16
16
|
height,
|
17
|
-
marginRight =
|
17
|
+
marginRight = 300,
|
18
18
|
marginBottom = 120,
|
19
19
|
keyLength = 36,
|
20
20
|
featureType,
|
@@ -86,7 +86,7 @@ export default function FeatureSetEnrichmentBarPlot(props) {
|
|
86
86
|
return [...a, h];
|
87
87
|
}, []);
|
88
88
|
|
89
|
-
const MAX_ROWS =
|
89
|
+
const MAX_ROWS = 50;
|
90
90
|
result = result.slice(0, MAX_ROWS);
|
91
91
|
return result;
|
92
92
|
}
|
@@ -115,7 +115,7 @@ export default function FeatureSetEnrichmentBarPlot(props) {
|
|
115
115
|
select: {
|
116
116
|
type: 'point',
|
117
117
|
on: 'click[event.shiftKey === false]',
|
118
|
-
fields: ['name'],
|
118
|
+
fields: ['name', 'term'],
|
119
119
|
empty: 'none',
|
120
120
|
},
|
121
121
|
},
|
@@ -124,7 +124,7 @@ export default function FeatureSetEnrichmentBarPlot(props) {
|
|
124
124
|
select: {
|
125
125
|
type: 'point',
|
126
126
|
on: 'click[event.shiftKey]',
|
127
|
-
fields: ['name'],
|
127
|
+
fields: ['name', 'term'],
|
128
128
|
empty: 'none',
|
129
129
|
},
|
130
130
|
},
|
@@ -173,9 +173,10 @@ export default function FeatureSetEnrichmentBarPlot(props) {
|
|
173
173
|
|
174
174
|
const handleSignal = (name, value) => {
|
175
175
|
if (name === 'bar_select') {
|
176
|
-
onBarSelect(value.
|
176
|
+
onBarSelect(value.name?.[0], value.term?.[0]);
|
177
177
|
} else if (name === 'shift_bar_select') {
|
178
|
-
|
178
|
+
// Name and term may be arrays
|
179
|
+
onBarSelect(value.name, value.term, true);
|
179
180
|
}
|
180
181
|
};
|
181
182
|
|
@@ -119,8 +119,11 @@ export function FeatureSetEnrichmentBarPlotSubscriber(props) {
|
|
119
119
|
// Will not work since transformFeature currently:
|
120
120
|
// - matches based on kgId (rather than term)
|
121
121
|
// - only knows about Reactome pathways (not GO terms).
|
122
|
-
|
123
|
-
|
122
|
+
const targetsInPathway = await transformFeature(kgNode, targetFeatureType);
|
123
|
+
const featureIds = targetsInPathway
|
124
|
+
.filter((d, i) => i < 10) // TODO: do not limit the number of genes here
|
125
|
+
.map(d => d.label);
|
126
|
+
setFeatureSelection(featureIds);
|
124
127
|
}, [setFeatureSelection]);
|
125
128
|
|
126
129
|
// TODO: support the following options
|
package/src/TreemapSubscriber.js
CHANGED
@@ -141,9 +141,6 @@ export function TreemapSubscriber(props) {
|
|
141
141
|
[sampleSets],
|
142
142
|
);
|
143
143
|
|
144
|
-
const obsCount = obsIndex?.length || 0;
|
145
|
-
const sampleCount = sampleIndex?.length || 0;
|
146
|
-
|
147
144
|
// TODO: use obsFilter / sampleFilter to display
|
148
145
|
// _all_ cells/samples in gray / transparent in background,
|
149
146
|
// and use obsSetSelection/sampleSetSelection to display
|
@@ -182,7 +179,7 @@ export function TreemapSubscriber(props) {
|
|
182
179
|
sampleResult.set(sampleSetKey, sampleSetSize || 0);
|
183
180
|
});
|
184
181
|
|
185
|
-
if (mergedObsSets && obsSetSelection) {
|
182
|
+
if (mergedObsSets && obsSetSelection && obsIndex) {
|
186
183
|
const sampleIdToSetMap = sampleSets && sampleSetSelection
|
187
184
|
? treeToSelectedSetMap(sampleSets, sampleSetSelection)
|
188
185
|
: null;
|
@@ -213,10 +210,20 @@ export function TreemapSubscriber(props) {
|
|
213
210
|
];
|
214
211
|
}, [obsIndex, sampleEdges, sampleSets, obsSetColor,
|
215
212
|
sampleSetColor, mergedObsSets, obsSetSelection, mergedSampleSets,
|
216
|
-
sampleSetSelection,
|
213
|
+
sampleSetSelection, obsIndex,
|
217
214
|
// TODO: consider filtering-related coordination values
|
218
215
|
]);
|
219
216
|
|
217
|
+
const totalObsCount = obsIndex?.length || 0;
|
218
|
+
const totalSampleCount = sampleIndex?.length || 0;
|
219
|
+
|
220
|
+
const selectedObsCount = obsCounts.reduce((a, h) => a + h.value, 0);
|
221
|
+
const selectedSampleCount = sampleCounts.reduce((a, h) => a + h.value, 0);
|
222
|
+
|
223
|
+
const unselectedObsCount = totalObsCount - selectedObsCount;
|
224
|
+
const unselectedSampleCount = totalSampleCount - selectedSampleCount;
|
225
|
+
|
226
|
+
|
220
227
|
const onNodeClick = useCallback((obsSetPath) => {
|
221
228
|
setObsSetSelection([obsSetPath]);
|
222
229
|
}, [setObsSetSelection]);
|
@@ -224,12 +231,13 @@ export function TreemapSubscriber(props) {
|
|
224
231
|
return (
|
225
232
|
<TitleInfo
|
226
233
|
title={`Treemap of ${capitalize(plur(obsType, 2))}`}
|
227
|
-
info={`${commaNumber(
|
234
|
+
info={`${commaNumber(selectedObsCount)} ${plur(obsType, selectedObsCount)} from ${commaNumber(selectedSampleCount)} ${plur(sampleType, selectedSampleCount)}`}
|
228
235
|
removeGridComponent={removeGridComponent}
|
229
236
|
urls={urls}
|
230
237
|
theme={theme}
|
231
238
|
isReady={isReady}
|
232
239
|
helpText={helpText}
|
240
|
+
withPadding={false}
|
233
241
|
options={(
|
234
242
|
<TreemapOptions
|
235
243
|
obsType={obsType}
|
@@ -254,7 +262,7 @@ export function TreemapSubscriber(props) {
|
|
254
262
|
hierarchyLevels={hierarchyLevels || DEFAULT_HIERARCHY_LEVELS}
|
255
263
|
theme={theme}
|
256
264
|
width={width}
|
257
|
-
height={height}
|
265
|
+
height={Math.max(height * (selectedObsCount / totalObsCount), 40)}
|
258
266
|
obsType={obsType}
|
259
267
|
sampleType={sampleType}
|
260
268
|
obsSetColor={obsSetColor}
|
@@ -264,6 +272,11 @@ export function TreemapSubscriber(props) {
|
|
264
272
|
onNodeClick={onNodeClick}
|
265
273
|
/>
|
266
274
|
</div>
|
275
|
+
<div style={{ position: 'absolute', right: '2px', bottom: '2px', fontSize: '10px' }}>
|
276
|
+
{unselectedObsCount > 0 ? (
|
277
|
+
<span>{`${commaNumber(unselectedObsCount)} ${plur(obsType, unselectedObsCount)} from ${commaNumber(unselectedSampleCount)} ${plur(sampleType, unselectedSampleCount)} currently omitted`}</span>
|
278
|
+
) : null}
|
279
|
+
</div>
|
267
280
|
</TitleInfo>
|
268
281
|
);
|
269
282
|
}
|
package/src/expr-hooks.js
CHANGED
@@ -92,7 +92,6 @@ export function summarizeStratifiedExpressionData(
|
|
92
92
|
stratifiedResult, keepZeros,
|
93
93
|
) {
|
94
94
|
const summarizedResult = new InternMap([], JSON.stringify);
|
95
|
-
|
96
95
|
Array.from(stratifiedResult.entries()).forEach(([cellSetKey, firstLevelInternMap]) => {
|
97
96
|
summarizedResult.set(cellSetKey, new InternMap([], JSON.stringify));
|
98
97
|
Array.from(firstLevelInternMap.entries()).forEach(([sampleSetKey, secondLevelInternMap]) => {
|
package/src/expr-hooks.test.js
CHANGED
@@ -78,6 +78,7 @@ describe('Utility functions for processing expression data for statistical plots
|
|
78
78
|
];
|
79
79
|
const featureValueTransform = null;
|
80
80
|
const featureValueTransformCoefficient = 1;
|
81
|
+
const featureAggregationStrategy = 'first';
|
81
82
|
|
82
83
|
const [result] = stratifyExpressionData(
|
83
84
|
sampleEdges, sampleSets, sampleSetSelection,
|
@@ -86,7 +87,7 @@ describe('Utility functions for processing expression data for statistical plots
|
|
86
87
|
featureValueTransform, featureValueTransformCoefficient,
|
87
88
|
);
|
88
89
|
const aggregateData = aggregateStratifiedExpressionData(
|
89
|
-
result, geneSelection,
|
90
|
+
result, geneSelection, featureAggregationStrategy,
|
90
91
|
);
|
91
92
|
const summaryResult = summarizeStratifiedExpressionData(aggregateData, true);
|
92
93
|
|