@vitessce/statistical-plots 2.0.3 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{index.mjs → index.js} +20501 -10821
- package/dist-tsc/CellSetExpressionPlot.d.ts +33 -0
- package/dist-tsc/CellSetExpressionPlot.d.ts.map +1 -0
- package/dist-tsc/CellSetExpressionPlot.js +248 -0
- package/dist-tsc/CellSetExpressionPlotOptions.d.ts +2 -0
- package/dist-tsc/CellSetExpressionPlotOptions.d.ts.map +1 -0
- package/dist-tsc/CellSetExpressionPlotOptions.js +30 -0
- package/dist-tsc/CellSetExpressionPlotSubscriber.d.ts +16 -0
- package/dist-tsc/CellSetExpressionPlotSubscriber.d.ts.map +1 -0
- package/dist-tsc/CellSetExpressionPlotSubscriber.js +107 -0
- package/dist-tsc/CellSetSizesPlot.d.ts +29 -0
- package/dist-tsc/CellSetSizesPlot.d.ts.map +1 -0
- package/dist-tsc/CellSetSizesPlot.js +149 -0
- package/dist-tsc/CellSetSizesPlotSubscriber.d.ts +18 -0
- package/dist-tsc/CellSetSizesPlotSubscriber.d.ts.map +1 -0
- package/dist-tsc/CellSetSizesPlotSubscriber.js +77 -0
- package/dist-tsc/ExpressionHistogram.d.ts +34 -0
- package/dist-tsc/ExpressionHistogram.d.ts.map +1 -0
- package/dist-tsc/ExpressionHistogram.js +93 -0
- package/dist-tsc/ExpressionHistogramSubscriber.d.ts +16 -0
- package/dist-tsc/ExpressionHistogramSubscriber.d.ts.map +1 -0
- package/dist-tsc/ExpressionHistogramSubscriber.js +70 -0
- package/dist-tsc/index.d.ts +7 -0
- package/dist-tsc/index.d.ts.map +1 -0
- package/dist-tsc/index.js +6 -6
- package/dist-tsc/styles.d.ts +2 -0
- package/dist-tsc/styles.d.ts.map +1 -0
- package/dist-tsc/styles.js +8 -0
- package/package.json +19 -10
- package/src/CellSetExpressionPlot.js +3 -3
- package/src/CellSetExpressionPlotOptions.js +1 -3
- package/src/CellSetExpressionPlotSubscriber.js +8 -16
- package/src/CellSetSizesPlot.js +90 -13
- package/src/CellSetSizesPlotSubscriber.js +65 -19
- package/src/ExpressionHistogram.js +58 -3
- package/src/ExpressionHistogramSubscriber.js +36 -18
- package/src/index.js +6 -6
- package/src/styles.js +1 -1
@@ -1,16 +1,18 @@
|
|
1
|
-
import React, { useMemo } from 'react';
|
1
|
+
import React, { useMemo, useState } from 'react';
|
2
2
|
import {
|
3
3
|
TitleInfo,
|
4
4
|
useCoordination, useLoaders,
|
5
5
|
useUrls, useReady, useGridItemSize,
|
6
6
|
useObsSetsData,
|
7
|
-
registerPluginViewType,
|
8
7
|
} from '@vitessce/vit-s';
|
8
|
+
import { isEqual } from 'lodash-es';
|
9
9
|
import { ViewType, COMPONENT_COORDINATION_TYPES } from '@vitessce/constants-internal';
|
10
|
-
import {
|
10
|
+
import {
|
11
|
+
mergeObsSets, treeToSetSizesBySetNames, filterPathsByExpansionAndSelection, findChangedHierarchy,
|
12
|
+
} from '@vitessce/sets-utils';
|
11
13
|
import { capitalize } from '@vitessce/utils';
|
12
|
-
import CellSetSizesPlot from './CellSetSizesPlot';
|
13
|
-
import { useStyles } from './styles';
|
14
|
+
import CellSetSizesPlot from './CellSetSizesPlot.js';
|
15
|
+
import { useStyles } from './styles.js';
|
14
16
|
|
15
17
|
/**
|
16
18
|
* A subscriber component for `CellSetSizePlot`,
|
@@ -42,6 +44,7 @@ export function CellSetSizesPlotSubscriber(props) {
|
|
42
44
|
obsSetSelection: cellSetSelection,
|
43
45
|
obsSetColor: cellSetColor,
|
44
46
|
additionalObsSets: additionalCellSets,
|
47
|
+
obsSetExpansion: cellSetExpansion,
|
45
48
|
}, {
|
46
49
|
setObsSetSelection: setCellSetSelection,
|
47
50
|
setObsSetColor: setCellSetColor,
|
@@ -52,6 +55,11 @@ export function CellSetSizesPlotSubscriber(props) {
|
|
52
55
|
const [width, height, containerRef] = useGridItemSize();
|
53
56
|
const [urls, addUrl] = useUrls(loaders, dataset);
|
54
57
|
|
58
|
+
// the name of the hierarchy that was clicked on last
|
59
|
+
const [currentHierarchy, setCurrentHierarchy] = useState([]);
|
60
|
+
// the previous cell set that was selected
|
61
|
+
const [prevCellSetSelection, setPrevCellSetSelection] = useState([]);
|
62
|
+
|
55
63
|
// Get data from loaders using the data hooks.
|
56
64
|
const [{ obsSets: cellSets }, obsSetsStatus] = useObsSetsData(
|
57
65
|
loaders, dataset, addUrl, true,
|
@@ -68,12 +76,57 @@ export function CellSetSizesPlotSubscriber(props) {
|
|
68
76
|
[cellSets, additionalCellSets],
|
69
77
|
);
|
70
78
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
79
|
+
const data = useMemo(() => {
|
80
|
+
if (cellSetSelection && cellSetColor && mergedCellSets && cellSets) {
|
81
|
+
let newHierarchy = currentHierarchy;
|
82
|
+
|
83
|
+
if (cellSetSelection) {
|
84
|
+
const changedHierarchy = findChangedHierarchy(prevCellSetSelection, cellSetSelection);
|
85
|
+
setPrevCellSetSelection(cellSetSelection);
|
86
|
+
|
87
|
+
if (changedHierarchy) {
|
88
|
+
setCurrentHierarchy(changedHierarchy);
|
89
|
+
newHierarchy = changedHierarchy;
|
90
|
+
}
|
91
|
+
}
|
92
|
+
|
93
|
+
const cellSetPaths = filterPathsByExpansionAndSelection(
|
94
|
+
mergedCellSets,
|
95
|
+
newHierarchy,
|
96
|
+
cellSetExpansion,
|
97
|
+
cellSetSelection,
|
98
|
+
);
|
99
|
+
|
100
|
+
if (mergedCellSets && cellSets && cellSetSelection && cellSetColor) {
|
101
|
+
return treeToSetSizesBySetNames(
|
102
|
+
mergedCellSets,
|
103
|
+
cellSetPaths,
|
104
|
+
cellSetSelection,
|
105
|
+
cellSetColor,
|
106
|
+
theme,
|
107
|
+
);
|
108
|
+
}
|
109
|
+
}
|
110
|
+
return [];
|
111
|
+
}, [
|
112
|
+
mergedCellSets,
|
113
|
+
cellSetSelection,
|
114
|
+
cellSetExpansion,
|
115
|
+
cellSetColor,
|
116
|
+
theme,
|
117
|
+
]);
|
118
|
+
|
119
|
+
const onBarSelect = (setNamePath, wasGrayedOut, selectOnlyEnabled = false) => {
|
120
|
+
if (selectOnlyEnabled) {
|
121
|
+
setCellSetSelection([setNamePath]);
|
122
|
+
return;
|
123
|
+
}
|
124
|
+
if (!wasGrayedOut) {
|
125
|
+
setCellSetSelection(cellSetSelection.filter(d => !isEqual(d, setNamePath)));
|
126
|
+
} else if (wasGrayedOut) {
|
127
|
+
setCellSetSelection([...cellSetSelection, setNamePath]);
|
128
|
+
}
|
129
|
+
};
|
77
130
|
|
78
131
|
return (
|
79
132
|
<TitleInfo
|
@@ -86,6 +139,7 @@ export function CellSetSizesPlotSubscriber(props) {
|
|
86
139
|
<div ref={containerRef} className={classes.vegaContainer}>
|
87
140
|
<CellSetSizesPlot
|
88
141
|
data={data}
|
142
|
+
onBarSelect={onBarSelect}
|
89
143
|
theme={theme}
|
90
144
|
width={width}
|
91
145
|
height={height}
|
@@ -95,11 +149,3 @@ export function CellSetSizesPlotSubscriber(props) {
|
|
95
149
|
</TitleInfo>
|
96
150
|
);
|
97
151
|
}
|
98
|
-
|
99
|
-
export function register() {
|
100
|
-
registerPluginViewType(
|
101
|
-
ViewType.OBS_SET_SIZES,
|
102
|
-
CellSetSizesPlotSubscriber,
|
103
|
-
COMPONENT_COORDINATION_TYPES[ViewType.OBS_SET_SIZES],
|
104
|
-
);
|
105
|
-
}
|
@@ -1,7 +1,14 @@
|
|
1
|
-
import React from 'react';
|
2
|
-
import clamp from 'lodash
|
1
|
+
import React, { useState, useEffect, useCallback } from 'react';
|
2
|
+
import { clamp, debounce } from 'lodash-es';
|
3
3
|
import { VegaPlot, VEGA_THEMES } from '@vitessce/vega';
|
4
4
|
|
5
|
+
/**
|
6
|
+
* We use debounce, so that onSelect is called only after the user has finished the selection.
|
7
|
+
* Due to vega-lite limitations, we cannot use the vega-lite signals to implement this.
|
8
|
+
* See this issue: https://github.com/vega/vega-lite/issues/5728
|
9
|
+
* See this for reference on what is supported: https://vega.github.io/vega-lite/docs/selection.html
|
10
|
+
*/
|
11
|
+
|
5
12
|
/**
|
6
13
|
* Gene expression histogram displayed as a bar chart,
|
7
14
|
* implemented with the VegaPlot component.
|
@@ -29,14 +36,18 @@ export default function ExpressionHistogram(props) {
|
|
29
36
|
height,
|
30
37
|
marginRight = 90,
|
31
38
|
marginBottom = 50,
|
39
|
+
onSelect,
|
32
40
|
} = props;
|
33
41
|
|
42
|
+
const [selectedRanges, setSelectedRanges] = useState([]);
|
43
|
+
|
34
44
|
const xTitle = geneSelection && geneSelection.length >= 1
|
35
45
|
? 'Normalized Expression Value'
|
36
46
|
: 'Total Normalized Transcript Count';
|
37
47
|
|
38
48
|
const spec = {
|
39
|
-
|
49
|
+
data: { values: data },
|
50
|
+
mark: 'bar',
|
40
51
|
encoding: {
|
41
52
|
x: {
|
42
53
|
field: 'value',
|
@@ -50,15 +61,59 @@ export default function ExpressionHistogram(props) {
|
|
50
61
|
title: 'Number of Cells',
|
51
62
|
},
|
52
63
|
color: { value: 'gray' },
|
64
|
+
opacity: {
|
65
|
+
condition: { selection: 'brush', value: 1 },
|
66
|
+
value: 0.7,
|
67
|
+
},
|
53
68
|
},
|
69
|
+
params: [
|
70
|
+
{
|
71
|
+
name: 'brush',
|
72
|
+
select: { type: 'interval', encodings: ['x'] },
|
73
|
+
},
|
74
|
+
],
|
54
75
|
width: clamp(width - marginRight, 10, Infinity),
|
55
76
|
height: clamp(height - marginBottom, 10, Infinity),
|
56
77
|
config: VEGA_THEMES[theme],
|
57
78
|
};
|
58
79
|
|
80
|
+
|
81
|
+
const handleSignal = (name, value) => {
|
82
|
+
if (name === 'brush') {
|
83
|
+
setSelectedRanges(value.value);
|
84
|
+
}
|
85
|
+
};
|
86
|
+
|
87
|
+
|
88
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
89
|
+
const debouncedOnSelect = useCallback(debounce((ranges, latestOnSelect) => {
|
90
|
+
latestOnSelect(ranges);
|
91
|
+
// We set a debounce timer of 1000ms: the assumption here is that the user has
|
92
|
+
// finished the selection when there's been no mouse movement on the histogram for a second.
|
93
|
+
// We do not pass any dependencies for the useCallback
|
94
|
+
// since we only want to define the debounced function once (on the initial render).
|
95
|
+
}, 1000), []);
|
96
|
+
|
97
|
+
useEffect(() => {
|
98
|
+
if (!selectedRanges || selectedRanges.length === 0) return () => {};
|
99
|
+
|
100
|
+
// Call the debounced function instead of directly calling onSelect
|
101
|
+
debouncedOnSelect(selectedRanges, onSelect);
|
102
|
+
|
103
|
+
// Clean up the debounce timer when the component unmounts or the dependency changes
|
104
|
+
return () => {
|
105
|
+
debouncedOnSelect.cancel();
|
106
|
+
};
|
107
|
+
// We only want to call the debounced function when the selectedRanges changes.
|
108
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
109
|
+
}, [selectedRanges]);
|
110
|
+
|
111
|
+
const signalListeners = { brush: handleSignal };
|
112
|
+
|
59
113
|
return (
|
60
114
|
<VegaPlot
|
61
115
|
data={data}
|
116
|
+
signalListeners={signalListeners}
|
62
117
|
spec={spec}
|
63
118
|
/>
|
64
119
|
);
|
@@ -1,16 +1,17 @@
|
|
1
|
-
import React, {
|
1
|
+
import React, {
|
2
|
+
useMemo, useCallback,
|
3
|
+
} from 'react';
|
2
4
|
import { sum } from 'd3-array';
|
3
5
|
import {
|
4
6
|
TitleInfo,
|
5
7
|
useCoordination, useLoaders,
|
6
8
|
useUrls, useReady, useGridItemSize,
|
7
9
|
useObsFeatureMatrixData, useFeatureSelection,
|
8
|
-
registerPluginViewType,
|
9
10
|
} from '@vitessce/vit-s';
|
10
11
|
import { ViewType, COMPONENT_COORDINATION_TYPES } from '@vitessce/constants-internal';
|
11
|
-
import
|
12
|
-
import
|
13
|
-
|
12
|
+
import { setObsSelection, getObsInfoFromDataWithinRange } from '@vitessce/sets-utils';
|
13
|
+
import ExpressionHistogram from './ExpressionHistogram.js';
|
14
|
+
import { useStyles } from './styles.js';
|
14
15
|
/**
|
15
16
|
* A subscriber component for `ExpressionHistogram`,
|
16
17
|
* which listens for gene selection updates and
|
@@ -38,6 +39,13 @@ export function ExpressionHistogramSubscriber(props) {
|
|
38
39
|
featureType,
|
39
40
|
featureValueType,
|
40
41
|
featureSelection: geneSelection,
|
42
|
+
additionalObsSets: additionalCellSets,
|
43
|
+
obsSetColor: cellSetColor,
|
44
|
+
}, {
|
45
|
+
setAdditionalObsSets: setAdditionalCellSets,
|
46
|
+
setObsSetColor: setCellSetColor,
|
47
|
+
setObsColorEncoding: setCellColorEncoding,
|
48
|
+
setObsSetSelection: setCellSetSelection,
|
41
49
|
}] = useCoordination(
|
42
50
|
COMPONENT_COORDINATION_TYPES[ViewType.FEATURE_VALUE_HISTOGRAM],
|
43
51
|
coordinationScopes,
|
@@ -69,11 +77,12 @@ export function ExpressionHistogramSubscriber(props) {
|
|
69
77
|
// generate the array of data points for the histogram.
|
70
78
|
const data = useMemo(() => {
|
71
79
|
if (firstGeneSelected && obsFeatureMatrix && expressionData) {
|
72
|
-
|
73
|
-
|
74
|
-
|
80
|
+
return obsIndex.map((cellId, cellIndex) => {
|
81
|
+
const value = expressionData[0][cellIndex];
|
82
|
+
// Create new cellColors map based on the selected gene.
|
75
83
|
const normValue = value * 100 / 255;
|
76
|
-
|
84
|
+
const newItem = { value: normValue, gene: firstGeneSelected, cellId };
|
85
|
+
return newItem;
|
77
86
|
});
|
78
87
|
}
|
79
88
|
if (obsFeatureMatrix) {
|
@@ -82,12 +91,28 @@ export function ExpressionHistogramSubscriber(props) {
|
|
82
91
|
const values = obsFeatureMatrix.data
|
83
92
|
.subarray(cellIndex * numGenes, (cellIndex + 1) * numGenes);
|
84
93
|
const sumValue = sum(values) * 100 / 255;
|
85
|
-
|
94
|
+
const newItem = { value: sumValue, gene: null, cellId };
|
95
|
+
return newItem;
|
86
96
|
});
|
87
97
|
}
|
88
98
|
return null;
|
89
99
|
}, [obsIndex, featureIndex, obsFeatureMatrix, firstGeneSelected, expressionData]);
|
90
100
|
|
101
|
+
const onSelect = useCallback((value) => {
|
102
|
+
const geneName = firstGeneSelected ? [firstGeneSelected, 'values'].join(' ') : 'transcript count';
|
103
|
+
|
104
|
+
const selectedCellIds = getObsInfoFromDataWithinRange(value, data);
|
105
|
+
setObsSelection(
|
106
|
+
selectedCellIds, additionalCellSets, cellSetColor,
|
107
|
+
setCellSetSelection, setAdditionalCellSets, setCellSetColor,
|
108
|
+
setCellColorEncoding,
|
109
|
+
'Selection ',
|
110
|
+
`: based on ${geneName} in range [${value[0].toFixed(1)}, ${value[1].toFixed(1)}] `,
|
111
|
+
);
|
112
|
+
}, [additionalCellSets, cellSetColor, data, setAdditionalCellSets,
|
113
|
+
setCellColorEncoding, setCellSetColor, setCellSetSelection, firstGeneSelected,
|
114
|
+
]);
|
115
|
+
|
91
116
|
return (
|
92
117
|
<TitleInfo
|
93
118
|
title={`Expression Histogram${(firstGeneSelected ? ` (${firstGeneSelected})` : '')}`}
|
@@ -99,6 +124,7 @@ export function ExpressionHistogramSubscriber(props) {
|
|
99
124
|
<div ref={containerRef} className={classes.vegaContainer}>
|
100
125
|
<ExpressionHistogram
|
101
126
|
geneSelection={geneSelection}
|
127
|
+
onSelect={onSelect}
|
102
128
|
data={data}
|
103
129
|
theme={theme}
|
104
130
|
width={width}
|
@@ -108,11 +134,3 @@ export function ExpressionHistogramSubscriber(props) {
|
|
108
134
|
</TitleInfo>
|
109
135
|
);
|
110
136
|
}
|
111
|
-
|
112
|
-
export function register() {
|
113
|
-
registerPluginViewType(
|
114
|
-
ViewType.FEATURE_VALUE_HISTOGRAM,
|
115
|
-
ExpressionHistogramSubscriber,
|
116
|
-
COMPONENT_COORDINATION_TYPES[ViewType.FEATURE_VALUE_HISTOGRAM],
|
117
|
-
);
|
118
|
-
}
|
package/src/index.js
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
export { CellSetExpressionPlotSubscriber
|
2
|
-
export { CellSetSizesPlotSubscriber
|
3
|
-
export { ExpressionHistogramSubscriber
|
4
|
-
export { default as CellSetSizesPlot } from './CellSetSizesPlot';
|
5
|
-
export { default as CellSetExpressionPlot } from './CellSetExpressionPlot';
|
6
|
-
export { default as ExpressionHistogram } from './ExpressionHistogram';
|
1
|
+
export { CellSetExpressionPlotSubscriber } from './CellSetExpressionPlotSubscriber.js';
|
2
|
+
export { CellSetSizesPlotSubscriber } from './CellSetSizesPlotSubscriber.js';
|
3
|
+
export { ExpressionHistogramSubscriber } from './ExpressionHistogramSubscriber.js';
|
4
|
+
export { default as CellSetSizesPlot } from './CellSetSizesPlot.js';
|
5
|
+
export { default as CellSetExpressionPlot } from './CellSetExpressionPlot.js';
|
6
|
+
export { default as ExpressionHistogram } from './ExpressionHistogram.js';
|
package/src/styles.js
CHANGED