@vitessce/statistical-plots 3.5.7 → 3.5.8
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-287e693d.js → deflate-1679ef33.js} +1 -1
- package/dist/{index-1f1b6355.js → index-0f4fe21d.js} +2065 -1061
- package/dist/index.js +9 -6
- package/dist/{jpeg-1b2c1d25.js → jpeg-280f0ee1.js} +1 -1
- package/dist/{lerc-4f010cd7.js → lerc-12264a36.js} +1 -1
- package/dist/{lzw-e60fb582.js → lzw-70f852cc.js} +1 -1
- package/dist/{packbits-a8bfe098.js → packbits-393c67b2.js} +1 -1
- package/dist/{raw-01dff90e.js → raw-d8d7ab7f.js} +1 -1
- package/dist/{webimage-6b926ce3.js → webimage-5d24a8e2.js} +1 -1
- package/dist-tsc/CellSetCompositionBarPlot.d.ts +5 -0
- package/dist-tsc/CellSetCompositionBarPlot.d.ts.map +1 -0
- package/dist-tsc/CellSetCompositionBarPlot.js +166 -0
- package/dist-tsc/CellSetCompositionBarPlotSubscriber.d.ts +2 -0
- package/dist-tsc/CellSetCompositionBarPlotSubscriber.d.ts.map +1 -0
- package/dist-tsc/CellSetCompositionBarPlotSubscriber.js +40 -0
- package/dist-tsc/FeatureSetEnrichmentBarPlot.d.ts +5 -0
- package/dist-tsc/FeatureSetEnrichmentBarPlot.d.ts.map +1 -0
- package/dist-tsc/FeatureSetEnrichmentBarPlot.js +164 -0
- package/dist-tsc/FeatureSetEnrichmentBarPlotSubscriber.d.ts +2 -0
- package/dist-tsc/FeatureSetEnrichmentBarPlotSubscriber.d.ts.map +1 -0
- package/dist-tsc/FeatureSetEnrichmentBarPlotSubscriber.js +51 -0
- package/dist-tsc/Treemap.d.ts.map +1 -1
- package/dist-tsc/Treemap.js +2 -12
- package/dist-tsc/TreemapSubscriber.d.ts.map +1 -1
- package/dist-tsc/TreemapSubscriber.js +1 -0
- package/dist-tsc/VolcanoPlot.d.ts +2 -0
- package/dist-tsc/VolcanoPlot.d.ts.map +1 -0
- package/dist-tsc/VolcanoPlot.js +230 -0
- package/dist-tsc/VolcanoPlotOptions.d.ts +2 -0
- package/dist-tsc/VolcanoPlotOptions.d.ts.map +1 -0
- package/dist-tsc/VolcanoPlotOptions.js +23 -0
- package/dist-tsc/VolcanoPlotSubscriber.d.ts +2 -0
- package/dist-tsc/VolcanoPlotSubscriber.d.ts.map +1 -0
- package/dist-tsc/VolcanoPlotSubscriber.js +33 -0
- package/dist-tsc/index.d.ts +3 -0
- package/dist-tsc/index.js +3 -0
- package/dist-tsc/utils.d.ts +9 -0
- package/dist-tsc/utils.d.ts.map +1 -0
- package/dist-tsc/utils.js +40 -0
- package/package.json +7 -7
- package/src/CellSetCompositionBarPlot.js +205 -0
- package/src/CellSetCompositionBarPlotSubscriber.js +151 -0
- package/src/FeatureSetEnrichmentBarPlot.js +203 -0
- package/src/FeatureSetEnrichmentBarPlotSubscriber.js +166 -0
- package/src/Treemap.js +2 -17
- package/src/TreemapSubscriber.js +1 -0
- package/src/VolcanoPlot.js +313 -0
- package/src/VolcanoPlotOptions.js +136 -0
- package/src/VolcanoPlotSubscriber.js +162 -0
- package/src/index.js +3 -0
- package/src/utils.js +47 -0
@@ -0,0 +1,151 @@
|
|
1
|
+
/* eslint-disable no-unused-vars */
|
2
|
+
import React, { useMemo, useCallback } from 'react';
|
3
|
+
import {
|
4
|
+
TitleInfo,
|
5
|
+
useCoordination,
|
6
|
+
useLoaders,
|
7
|
+
useReady,
|
8
|
+
useGridItemSize,
|
9
|
+
useObsSetStatsData,
|
10
|
+
useMatchingLoader,
|
11
|
+
useColumnNameMapping,
|
12
|
+
} from '@vitessce/vit-s';
|
13
|
+
import {
|
14
|
+
ViewType,
|
15
|
+
COMPONENT_COORDINATION_TYPES,
|
16
|
+
ViewHelpMapping,
|
17
|
+
DataType,
|
18
|
+
} from '@vitessce/constants-internal';
|
19
|
+
import { capitalize } from '@vitessce/utils';
|
20
|
+
import CellSetCompositionBarPlot from './CellSetCompositionBarPlot.js';
|
21
|
+
import { useStyles } from './styles.js';
|
22
|
+
import { useRawSetPaths } from './utils.js';
|
23
|
+
|
24
|
+
|
25
|
+
export function CellSetCompositionBarPlotSubscriber(props) {
|
26
|
+
const {
|
27
|
+
coordinationScopes,
|
28
|
+
removeGridComponent,
|
29
|
+
theme,
|
30
|
+
helpText = ViewHelpMapping.OBS_SET_COMPOSITION_BAR_PLOT,
|
31
|
+
} = props;
|
32
|
+
|
33
|
+
const classes = useStyles();
|
34
|
+
const loaders = useLoaders();
|
35
|
+
|
36
|
+
// Get "props" from the coordination space.
|
37
|
+
const [{
|
38
|
+
dataset,
|
39
|
+
obsType,
|
40
|
+
sampleType,
|
41
|
+
featureType,
|
42
|
+
featureValueType,
|
43
|
+
obsFilter: cellFilter,
|
44
|
+
obsHighlight: cellHighlight,
|
45
|
+
obsSetSelection,
|
46
|
+
obsSetColor,
|
47
|
+
obsColorEncoding: cellColorEncoding,
|
48
|
+
additionalObsSets: additionalCellSets,
|
49
|
+
featurePointSignificanceThreshold,
|
50
|
+
featurePointFoldChangeThreshold,
|
51
|
+
featureLabelSignificanceThreshold,
|
52
|
+
featureLabelFoldChangeThreshold,
|
53
|
+
featureValueTransform,
|
54
|
+
featureValueTransformCoefficient,
|
55
|
+
gatingFeatureSelectionX,
|
56
|
+
gatingFeatureSelectionY,
|
57
|
+
featureSelection,
|
58
|
+
sampleSetSelection,
|
59
|
+
sampleSetColor,
|
60
|
+
}, {
|
61
|
+
setObsFilter: setCellFilter,
|
62
|
+
setObsSetSelection,
|
63
|
+
setObsHighlight: setCellHighlight,
|
64
|
+
setObsSetColor: setCellSetColor,
|
65
|
+
setObsColorEncoding: setCellColorEncoding,
|
66
|
+
setAdditionalObsSets: setAdditionalCellSets,
|
67
|
+
setFeaturePointSignificanceThreshold,
|
68
|
+
setFeaturePointFoldChangeThreshold,
|
69
|
+
setFeatureLabelSignificanceThreshold,
|
70
|
+
setFeatureLabelFoldChangeThreshold,
|
71
|
+
setFeatureValueTransform,
|
72
|
+
setFeatureValueTransformCoefficient,
|
73
|
+
setGatingFeatureSelectionX,
|
74
|
+
setGatingFeatureSelectionY,
|
75
|
+
setFeatureSelection,
|
76
|
+
setSampleSetSelection,
|
77
|
+
setSampleSetColor,
|
78
|
+
}] = useCoordination(
|
79
|
+
COMPONENT_COORDINATION_TYPES[ViewType.OBS_SET_COMPOSITION_BAR_PLOT],
|
80
|
+
coordinationScopes,
|
81
|
+
);
|
82
|
+
const [width, height, containerRef] = useGridItemSize();
|
83
|
+
|
84
|
+
const obsSetsLoader = useMatchingLoader(
|
85
|
+
loaders, dataset, DataType.OBS_SETS, { obsType },
|
86
|
+
);
|
87
|
+
const sampleSetsLoader = useMatchingLoader(
|
88
|
+
loaders, dataset, DataType.SAMPLE_SETS, { sampleType },
|
89
|
+
);
|
90
|
+
const obsSetsColumnNameMapping = useColumnNameMapping(obsSetsLoader);
|
91
|
+
const obsSetsColumnNameMappingReversed = useColumnNameMapping(obsSetsLoader, true);
|
92
|
+
const sampleSetsColumnNameMapping = useColumnNameMapping(sampleSetsLoader);
|
93
|
+
const sampleSetsColumnNameMappingReversed = useColumnNameMapping(sampleSetsLoader, true);
|
94
|
+
|
95
|
+
const rawSampleSetSelection = useRawSetPaths(sampleSetsColumnNameMapping, sampleSetSelection);
|
96
|
+
const rawObsSetSelection = useRawSetPaths(obsSetsColumnNameMapping, obsSetSelection);
|
97
|
+
|
98
|
+
const [{ obsSetStats }, obsSetStatsStatus] = useObsSetStatsData(
|
99
|
+
loaders, dataset, false,
|
100
|
+
{ obsType, sampleType },
|
101
|
+
// These volcanoOptions are passed to ObsSetStatsAnndataLoader.loadMulti():
|
102
|
+
{ sampleSetSelection: rawSampleSetSelection, obsSetSelection: rawObsSetSelection },
|
103
|
+
);
|
104
|
+
|
105
|
+
const isReady = useReady([
|
106
|
+
obsSetStatsStatus,
|
107
|
+
]);
|
108
|
+
|
109
|
+
// Support a click handler which selects individual cell set bars.
|
110
|
+
const onBarSelect = useCallback((setNamePath, isShiftDown = false) => {
|
111
|
+
// TODO: Implement different behavior when isShiftDown
|
112
|
+
setObsSetSelection([setNamePath]);
|
113
|
+
}, [setObsSetSelection]);
|
114
|
+
|
115
|
+
// TODO: support the following options
|
116
|
+
// - Use logFoldChange vs. intercept+effect for the bar y-value.
|
117
|
+
// - Boolean flag to allow hiding non-significant bars.
|
118
|
+
|
119
|
+
return (
|
120
|
+
<TitleInfo
|
121
|
+
title={`${capitalize(obsType)} Set Composition Analysis Plot`}
|
122
|
+
removeGridComponent={removeGridComponent}
|
123
|
+
theme={theme}
|
124
|
+
isReady={isReady}
|
125
|
+
helpText={helpText}
|
126
|
+
>
|
127
|
+
<div ref={containerRef} className={classes.vegaContainer}>
|
128
|
+
{obsSetStats ? (
|
129
|
+
<CellSetCompositionBarPlot
|
130
|
+
theme={theme}
|
131
|
+
width={width}
|
132
|
+
height={height}
|
133
|
+
obsType={obsType}
|
134
|
+
obsSetsColumnNameMapping={obsSetsColumnNameMapping}
|
135
|
+
obsSetsColumnNameMappingReversed={obsSetsColumnNameMappingReversed}
|
136
|
+
sampleSetsColumnNameMapping={sampleSetsColumnNameMapping}
|
137
|
+
sampleSetsColumnNameMappingReversed={sampleSetsColumnNameMappingReversed}
|
138
|
+
sampleSetSelection={sampleSetSelection}
|
139
|
+
obsSetSelection={obsSetSelection}
|
140
|
+
obsSetColor={obsSetColor}
|
141
|
+
sampleSetColor={sampleSetColor}
|
142
|
+
data={obsSetStats}
|
143
|
+
onBarSelect={onBarSelect}
|
144
|
+
/>
|
145
|
+
) : (
|
146
|
+
<span>Select at least one {obsType} set.</span>
|
147
|
+
)}
|
148
|
+
</div>
|
149
|
+
</TitleInfo>
|
150
|
+
);
|
151
|
+
}
|
@@ -0,0 +1,203 @@
|
|
1
|
+
import React, { useCallback, useMemo } from 'react';
|
2
|
+
import { clamp } from 'lodash-es';
|
3
|
+
import { v4 as uuidv4 } from 'uuid';
|
4
|
+
import { VegaPlot, VEGA_THEMES } from '@vitessce/vega';
|
5
|
+
import { capitalize } from '@vitessce/utils';
|
6
|
+
import { getColorScale } from './utils.js';
|
7
|
+
|
8
|
+
/**
|
9
|
+
* Feature set enrichment test results displayed using a bar chart.
|
10
|
+
*/
|
11
|
+
export default function FeatureSetEnrichmentBarPlot(props) {
|
12
|
+
const {
|
13
|
+
data,
|
14
|
+
theme,
|
15
|
+
width,
|
16
|
+
height,
|
17
|
+
marginRight = 200,
|
18
|
+
marginBottom = 120,
|
19
|
+
keyLength = 36,
|
20
|
+
featureType,
|
21
|
+
onBarSelect,
|
22
|
+
obsSetsColumnNameMappingReversed,
|
23
|
+
sampleSetsColumnNameMappingReversed,
|
24
|
+
sampleSetSelection,
|
25
|
+
obsSetSelection,
|
26
|
+
obsSetColor,
|
27
|
+
sampleSetColor,
|
28
|
+
pValueThreshold,
|
29
|
+
} = props;
|
30
|
+
|
31
|
+
const [obsSetColorScale, sampleSetColorScale] = useMemo(() => [
|
32
|
+
getColorScale(obsSetSelection, obsSetColor, theme),
|
33
|
+
getColorScale(sampleSetSelection, sampleSetColor, theme),
|
34
|
+
], [obsSetSelection, sampleSetSelection, sampleSetColor, obsSetColor, theme]);
|
35
|
+
|
36
|
+
const computedData = useMemo(() => {
|
37
|
+
if (Array.isArray(data)) {
|
38
|
+
let result = [];
|
39
|
+
data.forEach((comparisonObject) => {
|
40
|
+
const { df, metadata } = comparisonObject;
|
41
|
+
const coordinationValues = metadata?.coordination_values;
|
42
|
+
|
43
|
+
const rawObsSetPath = coordinationValues.obsSetFilter
|
44
|
+
? coordinationValues.obsSetFilter[0]
|
45
|
+
: coordinationValues.obsSetSelection[0];
|
46
|
+
const obsSetPath = [...rawObsSetPath];
|
47
|
+
obsSetPath[0] = obsSetsColumnNameMappingReversed[rawObsSetPath[0]];
|
48
|
+
|
49
|
+
const color = obsSetColorScale(obsSetPath);
|
50
|
+
|
51
|
+
df.featureSetName.forEach((featureSetName, i) => {
|
52
|
+
const key = uuidv4();
|
53
|
+
result.push({
|
54
|
+
key,
|
55
|
+
name: featureSetName,
|
56
|
+
term: df.featureSetTerm[i],
|
57
|
+
color,
|
58
|
+
obsSetPath,
|
59
|
+
obsSetPaths: [obsSetPath],
|
60
|
+
obsSetNameToPval: { [obsSetPath.at(-1)]: df.featureSetSignificance[i] },
|
61
|
+
keyName: `${key}${featureSetName}`,
|
62
|
+
featureSetSignificance: df.featureSetSignificance[i],
|
63
|
+
minusLog10p: -Math.log10(df.featureSetSignificance[i]),
|
64
|
+
// Color based on obsSet
|
65
|
+
});
|
66
|
+
});
|
67
|
+
});
|
68
|
+
|
69
|
+
// TODO: instead of filtering, perhaps use virtual scrolling
|
70
|
+
// (would require custom renderer / not using Vega-Lite).
|
71
|
+
result = result
|
72
|
+
.map(d => ({
|
73
|
+
...d,
|
74
|
+
minusLog10p: Math.min(50, d.minusLog10p), // Clamp infinite values at 50
|
75
|
+
}))
|
76
|
+
.filter(d => d.featureSetSignificance <= pValueThreshold)
|
77
|
+
.toSorted((a, b) => a.featureSetSignificance - b.featureSetSignificance)
|
78
|
+
.reduce((a, h) => {
|
79
|
+
// Only add the pathway once if it appears for multiple cell types?
|
80
|
+
const match = a.find(d => d.name === h.name);
|
81
|
+
if (match) {
|
82
|
+
match.obsSetPaths.push(h.obsSetPath);
|
83
|
+
match.obsSetNameToPval[h.obsSetPath.at(-1)] = h.featureSetSignificance;
|
84
|
+
return a;
|
85
|
+
}
|
86
|
+
return [...a, h];
|
87
|
+
}, []);
|
88
|
+
|
89
|
+
const MAX_ROWS = 25;
|
90
|
+
result = result.slice(0, MAX_ROWS);
|
91
|
+
return result;
|
92
|
+
}
|
93
|
+
return null;
|
94
|
+
}, [data, sampleSetSelection, obsSetsColumnNameMappingReversed,
|
95
|
+
sampleSetsColumnNameMappingReversed, obsSetSelection,
|
96
|
+
obsSetColorScale, sampleSetColorScale, pValueThreshold,
|
97
|
+
]);
|
98
|
+
|
99
|
+
// Get an array of keys for sorting purposes.
|
100
|
+
const keys = computedData.map(d => d.keyName);
|
101
|
+
|
102
|
+
const colorScale = {
|
103
|
+
// Manually set the color scale so that Vega-Lite does
|
104
|
+
// not choose the colors automatically.
|
105
|
+
domain: computedData.map(d => d.key),
|
106
|
+
range: computedData.map(d => d.color),
|
107
|
+
};
|
108
|
+
const captializedFeatureType = capitalize(featureType);
|
109
|
+
|
110
|
+
const spec = {
|
111
|
+
mark: { type: 'bar', stroke: 'black', cursor: 'pointer' },
|
112
|
+
params: [
|
113
|
+
{
|
114
|
+
name: 'bar_select',
|
115
|
+
select: {
|
116
|
+
type: 'point',
|
117
|
+
on: 'click[event.shiftKey === false]',
|
118
|
+
fields: ['name'],
|
119
|
+
empty: 'none',
|
120
|
+
},
|
121
|
+
},
|
122
|
+
{
|
123
|
+
name: 'shift_bar_select',
|
124
|
+
select: {
|
125
|
+
type: 'point',
|
126
|
+
on: 'click[event.shiftKey]',
|
127
|
+
fields: ['name'],
|
128
|
+
empty: 'none',
|
129
|
+
},
|
130
|
+
},
|
131
|
+
],
|
132
|
+
encoding: {
|
133
|
+
y: {
|
134
|
+
field: 'keyName',
|
135
|
+
type: 'nominal',
|
136
|
+
axis: { labelExpr: `substring(datum.label, ${keyLength})` },
|
137
|
+
title: `${captializedFeatureType} Set`,
|
138
|
+
sort: keys,
|
139
|
+
},
|
140
|
+
x: {
|
141
|
+
field: 'minusLog10p',
|
142
|
+
type: 'quantitative',
|
143
|
+
title: '- log10 p-value',
|
144
|
+
},
|
145
|
+
color: {
|
146
|
+
field: 'key',
|
147
|
+
type: 'nominal',
|
148
|
+
scale: colorScale,
|
149
|
+
legend: null,
|
150
|
+
},
|
151
|
+
/*
|
152
|
+
fillOpacity: {
|
153
|
+
field: 'isCredibleEffect',
|
154
|
+
type: 'nominal',
|
155
|
+
scale: opacityScale,
|
156
|
+
},
|
157
|
+
strokeWidth: {
|
158
|
+
field: 'isReferenceSet',
|
159
|
+
type: 'nominal',
|
160
|
+
scale: strokeWidthScale,
|
161
|
+
},
|
162
|
+
*/
|
163
|
+
tooltip: {
|
164
|
+
field: 'featureSetSignificance',
|
165
|
+
type: 'quantitative',
|
166
|
+
},
|
167
|
+
},
|
168
|
+
// TODO: for width, also subtract length of longest y-axis set name label.
|
169
|
+
width: clamp(width - marginRight, 10, Infinity),
|
170
|
+
height: clamp(height - marginBottom, 10, Infinity),
|
171
|
+
config: VEGA_THEMES[theme],
|
172
|
+
};
|
173
|
+
|
174
|
+
const handleSignal = (name, value) => {
|
175
|
+
if (name === 'bar_select') {
|
176
|
+
onBarSelect(value.obsSetPath);
|
177
|
+
} else if (name === 'shift_bar_select') {
|
178
|
+
onBarSelect(value.obsSetPath, true);
|
179
|
+
}
|
180
|
+
};
|
181
|
+
|
182
|
+
const signalListeners = { bar_select: handleSignal, shift_bar_select: handleSignal };
|
183
|
+
const getTooltipText = useCallback(item => ({
|
184
|
+
[`${captializedFeatureType} Set`]: item.datum.name,
|
185
|
+
'Ontology Term': item.datum.term,
|
186
|
+
...Object.fromEntries(
|
187
|
+
Object.entries(item.datum.obsSetNameToPval).map(([cellSetName, pVal]) => ([
|
188
|
+
`p-value for ${cellSetName}`,
|
189
|
+
pVal,
|
190
|
+
])),
|
191
|
+
),
|
192
|
+
}
|
193
|
+
), [captializedFeatureType]);
|
194
|
+
|
195
|
+
return (
|
196
|
+
<VegaPlot
|
197
|
+
data={computedData}
|
198
|
+
spec={spec}
|
199
|
+
signalListeners={signalListeners}
|
200
|
+
getTooltipText={getTooltipText}
|
201
|
+
/>
|
202
|
+
);
|
203
|
+
}
|
@@ -0,0 +1,166 @@
|
|
1
|
+
/* eslint-disable no-unused-vars */
|
2
|
+
import React, { useCallback } from 'react';
|
3
|
+
import {
|
4
|
+
TitleInfo,
|
5
|
+
useCoordination,
|
6
|
+
useLoaders,
|
7
|
+
useReady,
|
8
|
+
useGridItemSize,
|
9
|
+
useFeatureSetStatsData,
|
10
|
+
useMatchingLoader,
|
11
|
+
useColumnNameMapping,
|
12
|
+
useAsyncFunction,
|
13
|
+
} from '@vitessce/vit-s';
|
14
|
+
import {
|
15
|
+
ViewType,
|
16
|
+
COMPONENT_COORDINATION_TYPES,
|
17
|
+
ViewHelpMapping,
|
18
|
+
DataType,
|
19
|
+
AsyncFunctionType,
|
20
|
+
} from '@vitessce/constants-internal';
|
21
|
+
import { capitalize } from '@vitessce/utils';
|
22
|
+
import FeatureSetEnrichmentBarPlot from './FeatureSetEnrichmentBarPlot.js';
|
23
|
+
import { useStyles } from './styles.js';
|
24
|
+
import { useRawSetPaths } from './utils.js';
|
25
|
+
|
26
|
+
|
27
|
+
export function FeatureSetEnrichmentBarPlotSubscriber(props) {
|
28
|
+
const {
|
29
|
+
coordinationScopes,
|
30
|
+
removeGridComponent,
|
31
|
+
theme,
|
32
|
+
helpText = ViewHelpMapping.FEATURE_SET_ENRICHMENT_BAR_PLOT,
|
33
|
+
} = props;
|
34
|
+
|
35
|
+
const classes = useStyles();
|
36
|
+
const loaders = useLoaders();
|
37
|
+
const transformFeature = useAsyncFunction(AsyncFunctionType.TRANSFORM_FEATURE);
|
38
|
+
|
39
|
+
// Get "props" from the coordination space.
|
40
|
+
const [{
|
41
|
+
dataset,
|
42
|
+
obsType,
|
43
|
+
sampleType,
|
44
|
+
featureType,
|
45
|
+
featureValueType,
|
46
|
+
obsFilter: cellFilter,
|
47
|
+
obsHighlight: cellHighlight,
|
48
|
+
obsSetSelection,
|
49
|
+
obsSetColor,
|
50
|
+
obsColorEncoding: cellColorEncoding,
|
51
|
+
additionalObsSets: additionalCellSets,
|
52
|
+
featurePointSignificanceThreshold,
|
53
|
+
featurePointFoldChangeThreshold,
|
54
|
+
featureLabelSignificanceThreshold,
|
55
|
+
featureLabelFoldChangeThreshold,
|
56
|
+
featureValueTransform,
|
57
|
+
featureValueTransformCoefficient,
|
58
|
+
gatingFeatureSelectionX,
|
59
|
+
gatingFeatureSelectionY,
|
60
|
+
featureSelection,
|
61
|
+
sampleSetSelection,
|
62
|
+
sampleSetColor,
|
63
|
+
}, {
|
64
|
+
setObsFilter: setCellFilter,
|
65
|
+
setObsSetSelection,
|
66
|
+
setObsHighlight: setCellHighlight,
|
67
|
+
setObsSetColor: setCellSetColor,
|
68
|
+
setObsColorEncoding: setCellColorEncoding,
|
69
|
+
setAdditionalObsSets: setAdditionalCellSets,
|
70
|
+
setFeaturePointSignificanceThreshold,
|
71
|
+
setFeaturePointFoldChangeThreshold,
|
72
|
+
setFeatureLabelSignificanceThreshold,
|
73
|
+
setFeatureLabelFoldChangeThreshold,
|
74
|
+
setFeatureValueTransform,
|
75
|
+
setFeatureValueTransformCoefficient,
|
76
|
+
setGatingFeatureSelectionX,
|
77
|
+
setGatingFeatureSelectionY,
|
78
|
+
setFeatureSelection,
|
79
|
+
setSampleSetSelection,
|
80
|
+
setSampleSetColor,
|
81
|
+
}] = useCoordination(
|
82
|
+
COMPONENT_COORDINATION_TYPES[ViewType.FEATURE_SET_ENRICHMENT_BAR_PLOT],
|
83
|
+
coordinationScopes,
|
84
|
+
);
|
85
|
+
const [width, height, containerRef] = useGridItemSize();
|
86
|
+
|
87
|
+
const obsSetsLoader = useMatchingLoader(
|
88
|
+
loaders, dataset, DataType.OBS_SETS, { obsType },
|
89
|
+
);
|
90
|
+
const sampleSetsLoader = useMatchingLoader(
|
91
|
+
loaders, dataset, DataType.SAMPLE_SETS, { sampleType },
|
92
|
+
);
|
93
|
+
const obsSetsColumnNameMapping = useColumnNameMapping(obsSetsLoader);
|
94
|
+
const obsSetsColumnNameMappingReversed = useColumnNameMapping(obsSetsLoader, true);
|
95
|
+
const sampleSetsColumnNameMapping = useColumnNameMapping(sampleSetsLoader);
|
96
|
+
const sampleSetsColumnNameMappingReversed = useColumnNameMapping(sampleSetsLoader, true);
|
97
|
+
|
98
|
+
const rawSampleSetSelection = useRawSetPaths(sampleSetsColumnNameMapping, sampleSetSelection);
|
99
|
+
const rawObsSetSelection = useRawSetPaths(obsSetsColumnNameMapping, obsSetSelection);
|
100
|
+
|
101
|
+
const [{ featureSetStats }, featureSetStatsStatus] = useFeatureSetStatsData(
|
102
|
+
loaders, dataset, false,
|
103
|
+
{ obsType, featureType, sampleType },
|
104
|
+
// These volcanoOptions are passed to ObsSetStatsAnndataLoader.loadMulti():
|
105
|
+
{ sampleSetSelection: rawSampleSetSelection, obsSetSelection: rawObsSetSelection },
|
106
|
+
);
|
107
|
+
|
108
|
+
const isReady = useReady([
|
109
|
+
featureSetStatsStatus,
|
110
|
+
]);
|
111
|
+
|
112
|
+
// Support a click handler which selects individual cell set bars.
|
113
|
+
const onBarSelect = useCallback(async (featureSetName, featureSetTerm, isShiftDown = false) => {
|
114
|
+
// TODO: Implement different behavior when isShiftDown
|
115
|
+
// TODO: get feature IDs using AsyncFunction transformFeature
|
116
|
+
// (pathway term in, gene names out).
|
117
|
+
const kgNode = { nodeType: 'pathway', term: featureSetTerm };
|
118
|
+
const targetFeatureType = featureType;
|
119
|
+
// Will not work since transformFeature currently:
|
120
|
+
// - matches based on kgId (rather than term)
|
121
|
+
// - only knows about Reactome pathways (not GO terms).
|
122
|
+
// console.log(await transformFeature(kgNode, targetFeatureType))
|
123
|
+
// setFeatureSelection(featureIds);
|
124
|
+
}, [setFeatureSelection]);
|
125
|
+
|
126
|
+
// TODO: support the following options
|
127
|
+
// - p-value threshold for which bars to show
|
128
|
+
// - max number of bars to show
|
129
|
+
// - Boolean flag: should same pathway which appears multiple times
|
130
|
+
// be de-duplicated (one bar per pathway, using most-significant result)?
|
131
|
+
|
132
|
+
return (
|
133
|
+
<TitleInfo
|
134
|
+
title={`${capitalize(featureType)} Set Enrichment Plot`}
|
135
|
+
removeGridComponent={removeGridComponent}
|
136
|
+
theme={theme}
|
137
|
+
isReady={isReady}
|
138
|
+
helpText={helpText}
|
139
|
+
>
|
140
|
+
<div ref={containerRef} className={classes.vegaContainer}>
|
141
|
+
{featureSetStats ? (
|
142
|
+
<FeatureSetEnrichmentBarPlot
|
143
|
+
theme={theme}
|
144
|
+
width={width}
|
145
|
+
height={height}
|
146
|
+
obsType={obsType}
|
147
|
+
featureType={featureType}
|
148
|
+
obsSetsColumnNameMapping={obsSetsColumnNameMapping}
|
149
|
+
obsSetsColumnNameMappingReversed={obsSetsColumnNameMappingReversed}
|
150
|
+
sampleSetsColumnNameMapping={sampleSetsColumnNameMapping}
|
151
|
+
sampleSetsColumnNameMappingReversed={sampleSetsColumnNameMappingReversed}
|
152
|
+
sampleSetSelection={sampleSetSelection}
|
153
|
+
obsSetSelection={obsSetSelection}
|
154
|
+
obsSetColor={obsSetColor}
|
155
|
+
sampleSetColor={sampleSetColor}
|
156
|
+
data={featureSetStats}
|
157
|
+
onBarSelect={onBarSelect}
|
158
|
+
pValueThreshold={0.01}
|
159
|
+
/>
|
160
|
+
) : (
|
161
|
+
<span>Select at least one {obsType} set.</span>
|
162
|
+
)}
|
163
|
+
</div>
|
164
|
+
</TitleInfo>
|
165
|
+
);
|
166
|
+
}
|
package/src/Treemap.js
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
/* eslint-disable indent */
|
2
2
|
/* eslint-disable camelcase */
|
3
3
|
import React, { useMemo, useEffect, useRef } from 'react';
|
4
|
-
import { scaleOrdinal } from 'd3-scale';
|
5
4
|
import { select } from 'd3-selection';
|
6
5
|
import { treemap, treemapBinary, hierarchy as d3_hierarchy } from 'd3-hierarchy';
|
7
6
|
import { rollup as d3_rollup } from 'd3-array';
|
8
7
|
import { isEqual } from 'lodash-es';
|
9
|
-
import {
|
10
|
-
import {
|
8
|
+
import { pluralize as plur } from '@vitessce/utils';
|
9
|
+
import { getColorScale } from './utils.js';
|
11
10
|
|
12
11
|
// Based on Observable's built-in DOM.uid function.
|
13
12
|
// This is intended to be used with SVG clipPaths
|
@@ -21,20 +20,6 @@ function uidGenerator(prefix) {
|
|
21
20
|
};
|
22
21
|
}
|
23
22
|
|
24
|
-
// Create a d3-scale ordinal scale mapping set paths to color strings.
|
25
|
-
function getColorScale(setSelectionArr, setColorArr, theme) {
|
26
|
-
return scaleOrdinal()
|
27
|
-
.domain(setSelectionArr || [])
|
28
|
-
.range(
|
29
|
-
setSelectionArr
|
30
|
-
?.map(setNamePath => (
|
31
|
-
setColorArr?.find(d => isEqual(d.path, setNamePath))?.color
|
32
|
-
|| getDefaultColor(theme)
|
33
|
-
))
|
34
|
-
?.map(colorArrayToString) || [],
|
35
|
-
);
|
36
|
-
}
|
37
|
-
|
38
23
|
/**
|
39
24
|
* Renders a treemap plot using D3.
|
40
25
|
* References:
|
package/src/TreemapSubscriber.js
CHANGED
@@ -211,6 +211,7 @@ export function TreemapSubscriber(props) {
|
|
211
211
|
];
|
212
212
|
}, [obsIndex, sampleEdges, sampleSets, obsSetColor,
|
213
213
|
sampleSetColor, mergedObsSets, obsSetSelection, mergedSampleSets,
|
214
|
+
sampleSetSelection,
|
214
215
|
// TODO: consider filtering-related coordination values
|
215
216
|
]);
|
216
217
|
|