@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
package/dist/index.js
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
import { i as inflate_1 } from "./pako.esm-68f84e2a.js";
|
2
|
-
import { g as getDefaultExportFromCjs, B as BaseDecoder } from "./index-
|
2
|
+
import { g as getDefaultExportFromCjs, B as BaseDecoder } from "./index-fa429ace.js";
|
3
3
|
import "react";
|
4
4
|
import "@vitessce/vit-s";
|
5
5
|
import "react-dom";
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"CellSetCompositionBarPlot.d.ts","sourceRoot":"","sources":["../src/CellSetCompositionBarPlot.js"],"names":[],"mappings":"
|
1
|
+
{"version":3,"file":"CellSetCompositionBarPlot.d.ts","sourceRoot":"","sources":["../src/CellSetCompositionBarPlot.js"],"names":[],"mappings":"AAUA;;GAEG;AACH,2EAyNC"}
|
@@ -2,14 +2,20 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import React, { useCallback, useMemo } from 'react';
|
3
3
|
import { clamp, isEqual } from 'lodash-es';
|
4
4
|
import { v4 as uuidv4 } from 'uuid';
|
5
|
+
import { extent } from 'd3-array';
|
5
6
|
import { VegaPlot, VEGA_THEMES } from '@vitessce/vega';
|
6
7
|
import { capitalize } from '@vitessce/utils';
|
7
8
|
import { getColorScale } from './utils.js';
|
9
|
+
const MAX_BAR_SIZE = 40;
|
8
10
|
/**
|
9
11
|
* Cell set composition results displayed using a bar chart.
|
10
12
|
*/
|
11
13
|
export default function CellSetCompositionBarPlot(props) {
|
12
|
-
const { data, theme, width, height, marginRight = 200, marginBottom =
|
14
|
+
const { data, theme, width, height: heightProp, marginRight = 200, marginBottom = 60, keyLength = 36, obsType, onBarSelect, obsSetsColumnNameMappingReversed, sampleSetsColumnNameMappingReversed, sampleSetSelection, obsSetSelection, obsSetColor, sampleSetColor, } = props;
|
15
|
+
const height = (Array.isArray(obsSetSelection)
|
16
|
+
&& ((heightProp - marginBottom) / obsSetSelection.length >= MAX_BAR_SIZE))
|
17
|
+
? MAX_BAR_SIZE * obsSetSelection.length + marginBottom
|
18
|
+
: heightProp;
|
13
19
|
const [obsSetColorScale, sampleSetColorScale] = useMemo(() => [
|
14
20
|
getColorScale(obsSetSelection, obsSetColor, theme),
|
15
21
|
getColorScale(sampleSetSelection, sampleSetColor, theme),
|
@@ -20,18 +26,15 @@ export default function CellSetCompositionBarPlot(props) {
|
|
20
26
|
const { df, metadata } = data[0];
|
21
27
|
// Return in array-of-objects form that Vega-Lite likes.
|
22
28
|
const referenceCellType = metadata?.analysis_params?.reference_cell_type;
|
29
|
+
const covariateValue = metadata?.analysis_params?.covariate_value;
|
23
30
|
const coordinationValues = metadata?.coordination_values;
|
24
31
|
const obsSetColumnName = coordinationValues?.obsSetSelection?.[0]?.[0];
|
25
32
|
const obsSetGroupName = obsSetsColumnNameMappingReversed?.[obsSetColumnName];
|
26
33
|
const sampleSetColumnName = coordinationValues?.sampleSetFilter?.[0]?.[0];
|
27
34
|
const sampleSetGroupName = sampleSetsColumnNameMappingReversed?.[sampleSetColumnName];
|
28
|
-
|
29
|
-
// so that we would no longer need to load/check the covariate column in the frontend.
|
30
|
-
const covariatePrefix = `${sampleSetColumnName}T.`;
|
31
|
-
const firstCovariateValue = df.covariate?.[0]?.substring(covariatePrefix.length);
|
32
|
-
const firstCovariateSetPath = [sampleSetGroupName, firstCovariateValue];
|
35
|
+
const covariateSetPath = [sampleSetGroupName, covariateValue];
|
33
36
|
let shouldSwapFoldChangeDirection = false;
|
34
|
-
if (isEqual(
|
37
|
+
if (isEqual(covariateSetPath, sampleSetSelection[0])) {
|
35
38
|
shouldSwapFoldChangeDirection = true;
|
36
39
|
}
|
37
40
|
return df.obsSetId.map((obsSetId, i) => {
|
@@ -85,6 +88,22 @@ export default function CellSetCompositionBarPlot(props) {
|
|
85
88
|
domain: [true, false],
|
86
89
|
range: [2.0, 0.5],
|
87
90
|
};
|
91
|
+
const xExtent = useMemo(() => {
|
92
|
+
if (computedData) {
|
93
|
+
const [min, max] = extent(computedData.map(d => d.logFoldChange));
|
94
|
+
const buffer = 1.05; // Ensure some extra space
|
95
|
+
const minAbs = Math.abs(min) * buffer;
|
96
|
+
const maxAbs = Math.abs(max) * buffer;
|
97
|
+
if (minAbs > maxAbs) {
|
98
|
+
return [-minAbs, minAbs];
|
99
|
+
}
|
100
|
+
return [-maxAbs, maxAbs];
|
101
|
+
}
|
102
|
+
return undefined;
|
103
|
+
}, [computedData]);
|
104
|
+
const xScale = {
|
105
|
+
domain: xExtent,
|
106
|
+
};
|
88
107
|
const spec = {
|
89
108
|
mark: { type: 'bar', stroke: 'black', cursor: 'pointer' },
|
90
109
|
params: [
|
@@ -120,6 +139,7 @@ export default function CellSetCompositionBarPlot(props) {
|
|
120
139
|
field: 'logFoldChange',
|
121
140
|
type: 'quantitative',
|
122
141
|
title: 'Log fold-change',
|
142
|
+
scale: xScale,
|
123
143
|
},
|
124
144
|
color: {
|
125
145
|
field: 'key',
|
@@ -136,6 +156,7 @@ export default function CellSetCompositionBarPlot(props) {
|
|
136
156
|
field: 'isReferenceSet',
|
137
157
|
type: 'nominal',
|
138
158
|
scale: strokeWidthScale,
|
159
|
+
legend: null,
|
139
160
|
},
|
140
161
|
tooltip: {
|
141
162
|
field: 'effectExpectedSample',
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"CellSetExpressionPlotOptions.d.ts","sourceRoot":"","sources":["../src/CellSetExpressionPlotOptions.js"],"names":[],"mappings":"
|
1
|
+
{"version":3,"file":"CellSetExpressionPlotOptions.d.ts","sourceRoot":"","sources":["../src/CellSetExpressionPlotOptions.js"],"names":[],"mappings":"AAUA,8EAyKC"}
|
@@ -4,16 +4,21 @@ import { useId } from 'react-aria';
|
|
4
4
|
import { TableCell, TableRow, TextField, Slider } from '@material-ui/core';
|
5
5
|
import { usePlotOptionsStyles, OptionsContainer, OptionSelect } from '@vitessce/vit-s';
|
6
6
|
import { GLSL_COLORMAPS } from '@vitessce/gl';
|
7
|
+
import { capitalize } from '@vitessce/utils';
|
8
|
+
const FEATURE_AGGREGATION_STRATEGIES = ['first', 'last', 'sum', 'mean'];
|
7
9
|
export default function CellSetExpressionPlotOptions(props) {
|
8
|
-
const { featureValueTransform, setFeatureValueTransform, featureValueTransformCoefficient, setFeatureValueTransformCoefficient, transformOptions, featureValuePositivityThreshold, setFeatureValuePositivityThreshold, featureValueColormap, setFeatureValueColormap, } = props;
|
10
|
+
const { featureValueTransform, setFeatureValueTransform, featureValueTransformCoefficient, setFeatureValueTransformCoefficient, transformOptions, featureValuePositivityThreshold, setFeatureValuePositivityThreshold, featureValueColormap, setFeatureValueColormap, featureAggregationStrategy, setFeatureAggregationStrategy, } = props;
|
9
11
|
const cellSetExpressionPlotOptionsId = useId();
|
10
12
|
const classes = usePlotOptionsStyles();
|
11
13
|
function handleFeatureValueColormapChange(event) {
|
12
14
|
setFeatureValueColormap(event.target.value);
|
13
15
|
}
|
14
|
-
|
16
|
+
function handleTransformChange(event) {
|
15
17
|
setFeatureValueTransform(event.target.value === '' ? null : event.target.value);
|
16
|
-
}
|
18
|
+
}
|
19
|
+
function handleFeatureAggregationStrategyChange(event) {
|
20
|
+
setFeatureAggregationStrategy(event.target.value);
|
21
|
+
}
|
17
22
|
function handlePositivityThresholdChange(event, value) {
|
18
23
|
setFeatureValuePositivityThreshold(value);
|
19
24
|
}
|
@@ -38,5 +43,7 @@ export default function CellSetExpressionPlotOptions(props) {
|
|
38
43
|
id: `cellset-expression-transform-select-${cellSetExpressionPlotOptionsId}`,
|
39
44
|
}, children: transformOptions.map(opt => (_jsx("option", { value: opt.value === null ? '' : opt.value, children: opt.name }, opt.name))) }) })] }), _jsxs(TableRow, { children: [_jsx(TableCell, { className: classes.labelCell, variant: "head", scope: "row", children: _jsx("label", { htmlFor: `cellset-expression-transform-coeff-${cellSetExpressionPlotOptionsId}`, children: "Transform Coefficient" }) }), _jsx(TableCell, { className: classes.inputCell, variant: "body", children: _jsx(TextField, { label: "Transform Coefficient", type: "number", onChange: handleTransformCoefficientChange, value: featureValueTransformCoefficient, InputLabelProps: {
|
40
45
|
shrink: true,
|
41
|
-
}, id: `cellset-expression-transform-coeff-${cellSetExpressionPlotOptionsId}` }) })] }),
|
46
|
+
}, id: `cellset-expression-transform-coeff-${cellSetExpressionPlotOptionsId}` }) })] }), setFeatureAggregationStrategy ? (_jsxs(TableRow, { children: [_jsx(TableCell, { className: classes.labelCell, variant: "head", scope: "row", children: _jsx("label", { htmlFor: `feature-aggregation-strategy-${cellSetExpressionPlotOptionsId}`, children: "Feature Aggregation Strategy" }) }), _jsx(TableCell, { className: classes.inputCell, variant: "body", children: _jsx(OptionSelect, { className: classes.select, value: featureAggregationStrategy ?? 'first', onChange: handleFeatureAggregationStrategyChange, inputProps: {
|
47
|
+
id: `feature-aggregation-strategy-${cellSetExpressionPlotOptionsId}`,
|
48
|
+
}, children: FEATURE_AGGREGATION_STRATEGIES.map(opt => (_jsx("option", { value: opt, children: capitalize(opt) }, opt))) }) })] })) : null, setFeatureValuePositivityThreshold ? (_jsxs(TableRow, { children: [_jsx(TableCell, { className: classes.labelCell, children: "Positivity Threshold" }), _jsx(TableCell, { className: classes.inputCell, children: _jsx(Slider, { classes: { root: classes.slider, valueLabel: classes.sliderValueLabel }, value: featureValuePositivityThreshold, onChange: handlePositivityThresholdChange, "aria-labelledby": "pos-threshold-slider", valueLabelDisplay: "auto", step: 1.0, min: 0.0, max: 100.0 }) })] }, "transform-coefficient-option-row")) : null] }));
|
42
49
|
}
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"CellSetExpressionPlotSubscriber.d.ts","sourceRoot":"","sources":["../src/CellSetExpressionPlotSubscriber.js"],"names":[],"mappings":"
|
1
|
+
{"version":3,"file":"CellSetExpressionPlotSubscriber.d.ts","sourceRoot":"","sources":["../src/CellSetExpressionPlotSubscriber.js"],"names":[],"mappings":"AA0HA;;;;;;;;;GASG;AACH,uDALG;IAAwB,mBAAmB;IACrB,kBAAkB,EAAhC,MAAM;IAEQ,KAAK,EAAnB,MAAM;CAChB,eAwLA"}
|
@@ -8,6 +8,31 @@ import CellSetExpressionPlotOptions from './CellSetExpressionPlotOptions.js';
|
|
8
8
|
import CellSetExpressionPlot from './CellSetExpressionPlot.js';
|
9
9
|
import { useStyles } from './styles.js';
|
10
10
|
import { summarizeStratifiedExpressionData, histogramStratifiedExpressionData, } from './expr-hooks.js';
|
11
|
+
const DEFAULT_FEATURE_AGGREGATION_STRATEGY = 'first';
|
12
|
+
function featureSummary(geneSelection, featureAggregationStrategy) {
|
13
|
+
if (featureAggregationStrategy === 'first') {
|
14
|
+
return geneSelection?.[0];
|
15
|
+
}
|
16
|
+
if (featureAggregationStrategy === 'last') {
|
17
|
+
return geneSelection?.at(-1);
|
18
|
+
}
|
19
|
+
if (typeof featureAggregationStrategy === 'number') {
|
20
|
+
const i = featureAggregationStrategy;
|
21
|
+
return geneSelection?.[i];
|
22
|
+
}
|
23
|
+
if (featureAggregationStrategy === 'sum') {
|
24
|
+
// TODO: make these .join()-ed labels more scalable,
|
25
|
+
// in particular, if more than 10 or so elements.
|
26
|
+
return geneSelection?.join(' + ');
|
27
|
+
}
|
28
|
+
if (featureAggregationStrategy === 'mean') {
|
29
|
+
return `Mean of ${geneSelection?.join(', ')}`;
|
30
|
+
}
|
31
|
+
if (featureAggregationStrategy === 'difference') {
|
32
|
+
return geneSelection?.join(' - ');
|
33
|
+
}
|
34
|
+
return '';
|
35
|
+
}
|
11
36
|
/**
|
12
37
|
* Get expression data for the cells
|
13
38
|
* in the selected cell sets.
|
@@ -27,14 +52,14 @@ import { summarizeStratifiedExpressionData, histogramStratifiedExpressionData, }
|
|
27
52
|
* @param {number} featureValueTransformCoefficient A coefficient
|
28
53
|
* to be used in the transform function.
|
29
54
|
*/
|
30
|
-
function useExpressionByCellSet(sampleEdges, sampleSets, sampleSetSelection, expressionData, obsIndex, cellSets, additionalCellSets, geneSelection, cellSetSelection, cellSetColor, featureValueTransform, featureValueTransformCoefficient, theme, yMinProp) {
|
55
|
+
function useExpressionByCellSet(sampleEdges, sampleSets, sampleSetSelection, expressionData, obsIndex, cellSets, additionalCellSets, geneSelection, cellSetSelection, cellSetColor, featureValueTransform, featureValueTransformCoefficient, theme, yMinProp, featureAggregationStrategy) {
|
31
56
|
const mergedCellSets = useMemo(() => mergeObsSets(cellSets, additionalCellSets), [cellSets, additionalCellSets]);
|
32
57
|
// From the expression matrix and the list of selected genes / cell sets,
|
33
58
|
// generate the array of data points for the plot.
|
34
59
|
const [expressionArr, expressionMax] = useMemo(() => {
|
35
60
|
const [stratifiedData, exprMax] = stratifyExpressionData(sampleEdges, sampleSets, sampleSetSelection, expressionData, obsIndex, mergedCellSets, geneSelection, cellSetSelection, cellSetColor, featureValueTransform, featureValueTransformCoefficient);
|
36
61
|
if (stratifiedData) {
|
37
|
-
const aggregateData = aggregateStratifiedExpressionData(stratifiedData, geneSelection);
|
62
|
+
const aggregateData = aggregateStratifiedExpressionData(stratifiedData, geneSelection, featureAggregationStrategy);
|
38
63
|
const summarizedData = summarizeStratifiedExpressionData(aggregateData, true);
|
39
64
|
const histogramData = histogramStratifiedExpressionData(summarizedData, 16, yMinProp);
|
40
65
|
return [histogramData, exprMax];
|
@@ -44,6 +69,7 @@ function useExpressionByCellSet(sampleEdges, sampleSets, sampleSetSelection, exp
|
|
44
69
|
mergedCellSets, cellSetSelection, cellSetColor,
|
45
70
|
featureValueTransform, featureValueTransformCoefficient,
|
46
71
|
yMinProp, sampleEdges, sampleSets, sampleSetSelection,
|
72
|
+
featureAggregationStrategy,
|
47
73
|
]);
|
48
74
|
// From the cell sets hierarchy and the list of selected cell sets,
|
49
75
|
// generate the array of set sizes data points for the bar plot.
|
@@ -67,7 +93,7 @@ export function CellSetExpressionPlotSubscriber(props) {
|
|
67
93
|
const classes = useStyles();
|
68
94
|
const loaders = useLoaders();
|
69
95
|
// Get "props" from the coordination space.
|
70
|
-
const [{ dataset, obsType, featureType, featureValueType, featureSelection: geneSelection, featureValueTransform, featureValueTransformCoefficient, obsSetSelection: cellSetSelection, obsSetColor: cellSetColor, additionalObsSets: additionalCellSets, sampleType, sampleSetSelection, sampleSetColor, }, { setFeatureValueTransform, setFeatureValueTransformCoefficient, setSampleSetColor, }] = useCoordination(COMPONENT_COORDINATION_TYPES[ViewType.OBS_SET_FEATURE_VALUE_DISTRIBUTION], coordinationScopes);
|
96
|
+
const [{ dataset, obsType, featureType, featureValueType, featureSelection: geneSelection, featureValueTransform, featureValueTransformCoefficient, obsSetSelection: cellSetSelection, obsSetColor: cellSetColor, additionalObsSets: additionalCellSets, sampleType, sampleSetSelection, sampleSetColor, featureAggregationStrategy, }, { setFeatureValueTransform, setFeatureValueTransformCoefficient, setSampleSetColor, setFeatureAggregationStrategy, }] = useCoordination(COMPONENT_COORDINATION_TYPES[ViewType.OBS_SET_FEATURE_VALUE_DISTRIBUTION], coordinationScopes);
|
71
97
|
const [width, height, containerRef] = useGridItemSize();
|
72
98
|
const transformOptions = VALUE_TRANSFORM_OPTIONS;
|
73
99
|
// Get data from loaders using the data hooks.
|
@@ -97,15 +123,21 @@ export function CellSetExpressionPlotSubscriber(props) {
|
|
97
123
|
sampleSetsUrls,
|
98
124
|
sampleEdgesUrls,
|
99
125
|
]);
|
100
|
-
const
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
126
|
+
const featureAggregationStrategyToUse = featureAggregationStrategy
|
127
|
+
?? DEFAULT_FEATURE_AGGREGATION_STRATEGY;
|
128
|
+
const [histogramData, setArr, exprMax] = useExpressionByCellSet(sampleEdges, sampleSets, sampleSetSelection, expressionData, obsIndex, cellSets, additionalCellSets, geneSelection, cellSetSelection, cellSetColor, featureValueTransform, featureValueTransformCoefficient, theme, yMin, featureAggregationStrategyToUse);
|
129
|
+
const featureSuffix = useMemo(() => {
|
130
|
+
const cleanedGeneSelection = geneSelection?.map(geneName => (featureLabelsMap?.get(geneName)
|
131
|
+
|| featureLabelsMap?.get(cleanFeatureId(geneName))
|
132
|
+
|| geneName));
|
133
|
+
if (Array.isArray(cleanedGeneSelection)) {
|
134
|
+
return featureSummary(cleanedGeneSelection, featureAggregationStrategyToUse);
|
135
|
+
}
|
136
|
+
return null;
|
137
|
+
}, [geneSelection, featureAggregationStrategyToUse]);
|
106
138
|
const selectedTransformName = transformOptions.find(o => o.value === featureValueTransform)?.name;
|
107
139
|
// Use empty string when firstGeneSelected is null
|
108
|
-
const titleSuffix =
|
140
|
+
const titleSuffix = featureSuffix ? ` (${featureSuffix})` : '';
|
109
141
|
return (_jsx(TitleInfo, { title: title ? `${title}${titleSuffix}`
|
110
|
-
: `Expression by ${capitalize(obsType)} Set${titleSuffix}`, closeButtonVisible: closeButtonVisible, downloadButtonVisible: downloadButtonVisible, removeGridComponent: removeGridComponent, urls: urls, theme: theme, isReady: isReady, helpText: helpText, options: (_jsx(CellSetExpressionPlotOptions, { featureValueTransform: featureValueTransform, setFeatureValueTransform: setFeatureValueTransform, featureValueTransformCoefficient: featureValueTransformCoefficient, setFeatureValueTransformCoefficient: setFeatureValueTransformCoefficient, transformOptions: transformOptions })), children: _jsx("div", { ref: containerRef, className: classes.vegaContainer, children: histogramData ? (_jsx(CellSetExpressionPlot, { yMin: yMin, yUnits: yUnits, jitter: jitter, obsSetSelection: cellSetSelection, obsSetColor: cellSetColor, sampleSetSelection: sampleSetSelection, sampleSetColor: sampleSetColor, colors: setArr, data: histogramData, exprMax: exprMax, theme: theme, width: width, height: height, obsType: obsType, featureType: featureType, featureValueType: featureValueType, featureValueTransformName: selectedTransformName, xAxisTitle: xAxisTitle })) : (_jsxs("span", { children: ["Select a ", featureType, "."] })) }) }));
|
142
|
+
: `Expression by ${capitalize(obsType)} Set${titleSuffix}`, closeButtonVisible: closeButtonVisible, downloadButtonVisible: downloadButtonVisible, removeGridComponent: removeGridComponent, urls: urls, theme: theme, isReady: isReady, helpText: helpText, options: (_jsx(CellSetExpressionPlotOptions, { featureValueTransform: featureValueTransform, setFeatureValueTransform: setFeatureValueTransform, featureValueTransformCoefficient: featureValueTransformCoefficient, setFeatureValueTransformCoefficient: setFeatureValueTransformCoefficient, transformOptions: transformOptions, featureAggregationStrategy: featureAggregationStrategy, setFeatureAggregationStrategy: setFeatureAggregationStrategy })), children: _jsx("div", { ref: containerRef, className: classes.vegaContainer, children: histogramData ? (_jsx(CellSetExpressionPlot, { yMin: yMin, yUnits: yUnits, jitter: jitter, obsSetSelection: cellSetSelection, obsSetColor: cellSetColor, sampleSetSelection: sampleSetSelection, sampleSetColor: sampleSetColor, colors: setArr, data: histogramData, exprMax: exprMax, theme: theme, width: width, height: height, obsType: obsType, featureType: featureType, featureValueType: featureValueType, featureValueTransformName: selectedTransformName, xAxisTitle: xAxisTitle })) : (_jsxs("span", { children: ["Select a ", featureType, "."] })) }) }));
|
111
143
|
}
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"DotPlot.d.ts","sourceRoot":"","sources":["../src/DotPlot.js"],"names":[],"mappings":"AAOA;;;;;;;;;;;;;;;;;GAiBG;AACH,uCAdG;IAAwB,IAAI,EAApB,MAAM,EAAE;IAEM,KAAK,EAAnB,MAAM;IACQ,KAAK,EAAnB,MAAM;IACQ,MAAM,EAApB,MAAM;IACQ,WAAW,EAAzB,MAAM;IAGQ,YAAY,EAA1B,MAAM;IAGa,yBAAyB,EAA5C,MAAM,GAAC,IAAI;CAErB,
|
1
|
+
{"version":3,"file":"DotPlot.d.ts","sourceRoot":"","sources":["../src/DotPlot.js"],"names":[],"mappings":"AAOA;;;;;;;;;;;;;;;;;GAiBG;AACH,uCAdG;IAAwB,IAAI,EAApB,MAAM,EAAE;IAEM,KAAK,EAAnB,MAAM;IACQ,KAAK,EAAnB,MAAM;IACQ,MAAM,EAApB,MAAM;IACQ,WAAW,EAAzB,MAAM;IAGQ,YAAY,EAA1B,MAAM;IAGa,yBAAyB,EAA5C,MAAM,GAAC,IAAI;CAErB,eA4NA"}
|
package/dist-tsc/DotPlot.js
CHANGED
@@ -24,7 +24,10 @@ import { getColorScale } from './utils.js';
|
|
24
24
|
* for the feature value transformation function.
|
25
25
|
*/
|
26
26
|
export default function DotPlot(props) {
|
27
|
-
const { isStratified, transpose, data: rawData, theme, width, height, marginRight, marginBottom, obsType, sampleType, keyLength = 36, featureType, featureValueType, featureValueTransformName,
|
27
|
+
const { isStratified, transpose, data: rawData, theme, width, height, marginRight, marginBottom, obsType, sampleType, keyLength = 36, featureType, featureValueType, featureValueTransformName,
|
28
|
+
// TODO: re-enable featureValueColormap coordination
|
29
|
+
// featureValueColormap,
|
30
|
+
obsSetSelection, obsSetColor, } = props;
|
28
31
|
const vegaContainerRef = useRef();
|
29
32
|
// Add a property `keyGroup` and `keyFeature` which concatenates the key and the name,
|
30
33
|
// which is both unique and can easily be converted
|
@@ -107,7 +110,8 @@ export default function DotPlot(props) {
|
|
107
110
|
type: 'quantitative',
|
108
111
|
title: meanTransform,
|
109
112
|
scale: {
|
110
|
-
scheme: featureValueColormap,
|
113
|
+
// scheme: featureValueColormap,
|
114
|
+
scheme: 'greys',
|
111
115
|
},
|
112
116
|
legend: {
|
113
117
|
direction: 'horizontal',
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"FeatureSetEnrichmentBarPlot.d.ts","sourceRoot":"","sources":["../src/FeatureSetEnrichmentBarPlot.js"],"names":[],"mappings":"AAOA;;GAEG;AACH,
|
1
|
+
{"version":3,"file":"FeatureSetEnrichmentBarPlot.d.ts","sourceRoot":"","sources":["../src/FeatureSetEnrichmentBarPlot.js"],"names":[],"mappings":"AAOA;;GAEG;AACH,6EAiMC"}
|
@@ -9,7 +9,7 @@ import { getColorScale } from './utils.js';
|
|
9
9
|
* Feature set enrichment test results displayed using a bar chart.
|
10
10
|
*/
|
11
11
|
export default function FeatureSetEnrichmentBarPlot(props) {
|
12
|
-
const { data, theme, width, height, marginRight =
|
12
|
+
const { data, theme, width, height, marginRight = 300, marginBottom = 120, keyLength = 36, featureType, onBarSelect, obsSetsColumnNameMappingReversed, sampleSetsColumnNameMappingReversed, sampleSetSelection, obsSetSelection, obsSetColor, sampleSetColor, pValueThreshold, } = props;
|
13
13
|
const [obsSetColorScale, sampleSetColorScale] = useMemo(() => [
|
14
14
|
getColorScale(obsSetSelection, obsSetColor, theme),
|
15
15
|
getColorScale(sampleSetSelection, sampleSetColor, theme),
|
@@ -62,7 +62,7 @@ export default function FeatureSetEnrichmentBarPlot(props) {
|
|
62
62
|
}
|
63
63
|
return [...a, h];
|
64
64
|
}, []);
|
65
|
-
const MAX_ROWS =
|
65
|
+
const MAX_ROWS = 50;
|
66
66
|
result = result.slice(0, MAX_ROWS);
|
67
67
|
return result;
|
68
68
|
}
|
@@ -88,7 +88,7 @@ export default function FeatureSetEnrichmentBarPlot(props) {
|
|
88
88
|
select: {
|
89
89
|
type: 'point',
|
90
90
|
on: 'click[event.shiftKey === false]',
|
91
|
-
fields: ['name'],
|
91
|
+
fields: ['name', 'term'],
|
92
92
|
empty: 'none',
|
93
93
|
},
|
94
94
|
},
|
@@ -97,7 +97,7 @@ export default function FeatureSetEnrichmentBarPlot(props) {
|
|
97
97
|
select: {
|
98
98
|
type: 'point',
|
99
99
|
on: 'click[event.shiftKey]',
|
100
|
-
fields: ['name'],
|
100
|
+
fields: ['name', 'term'],
|
101
101
|
empty: 'none',
|
102
102
|
},
|
103
103
|
},
|
@@ -145,10 +145,11 @@ export default function FeatureSetEnrichmentBarPlot(props) {
|
|
145
145
|
};
|
146
146
|
const handleSignal = (name, value) => {
|
147
147
|
if (name === 'bar_select') {
|
148
|
-
onBarSelect(value.
|
148
|
+
onBarSelect(value.name?.[0], value.term?.[0]);
|
149
149
|
}
|
150
150
|
else if (name === 'shift_bar_select') {
|
151
|
-
|
151
|
+
// Name and term may be arrays
|
152
|
+
onBarSelect(value.name, value.term, true);
|
152
153
|
}
|
153
154
|
};
|
154
155
|
const signalListeners = { bar_select: handleSignal, shift_bar_select: handleSignal };
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"FeatureSetEnrichmentBarPlotSubscriber.d.ts","sourceRoot":"","sources":["../src/FeatureSetEnrichmentBarPlotSubscriber.js"],"names":[],"mappings":"AA0BA,+
|
1
|
+
{"version":3,"file":"FeatureSetEnrichmentBarPlotSubscriber.d.ts","sourceRoot":"","sources":["../src/FeatureSetEnrichmentBarPlotSubscriber.js"],"names":[],"mappings":"AA0BA,+EA8IC"}
|
@@ -39,8 +39,11 @@ export function FeatureSetEnrichmentBarPlotSubscriber(props) {
|
|
39
39
|
// Will not work since transformFeature currently:
|
40
40
|
// - matches based on kgId (rather than term)
|
41
41
|
// - only knows about Reactome pathways (not GO terms).
|
42
|
-
|
43
|
-
|
42
|
+
const targetsInPathway = await transformFeature(kgNode, targetFeatureType);
|
43
|
+
const featureIds = targetsInPathway
|
44
|
+
.filter((d, i) => i < 10) // TODO: do not limit the number of genes here
|
45
|
+
.map(d => d.label);
|
46
|
+
setFeatureSelection(featureIds);
|
44
47
|
}, [setFeatureSelection]);
|
45
48
|
// TODO: support the following options
|
46
49
|
// - p-value threshold for which bars to show
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"TreemapSubscriber.d.ts","sourceRoot":"","sources":["../src/TreemapSubscriber.js"],"names":[],"mappings":"AAyBA,
|
1
|
+
{"version":3,"file":"TreemapSubscriber.d.ts","sourceRoot":"","sources":["../src/TreemapSubscriber.js"],"names":[],"mappings":"AAyBA,2DAgQC"}
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
2
2
|
/* eslint-disable no-unused-vars */
|
3
3
|
import React, { useMemo, useCallback } from 'react';
|
4
4
|
import { TitleInfo, useCoordination, useLoaders, useUrls, useReady, useGridItemSize, useObsFeatureMatrixIndices, useObsSetsData, useSampleEdgesData, useSampleSetsData, } from '@vitessce/vit-s';
|
@@ -43,8 +43,6 @@ export function TreemapSubscriber(props) {
|
|
43
43
|
]);
|
44
44
|
const mergedObsSets = useMemo(() => mergeObsSets(obsSets, additionalObsSets), [obsSets, additionalObsSets]);
|
45
45
|
const mergedSampleSets = useMemo(() => mergeObsSets(sampleSets, null), [sampleSets]);
|
46
|
-
const obsCount = obsIndex?.length || 0;
|
47
|
-
const sampleCount = sampleIndex?.length || 0;
|
48
46
|
// TODO: use obsFilter / sampleFilter to display
|
49
47
|
// _all_ cells/samples in gray / transparent in background,
|
50
48
|
// and use obsSetSelection/sampleSetSelection to display
|
@@ -71,7 +69,7 @@ export function TreemapSubscriber(props) {
|
|
71
69
|
const sampleSetSize = sampleSetSizes?.find(d => isEqual(d.setNamePath, sampleSetKey))?.size;
|
72
70
|
sampleResult.set(sampleSetKey, sampleSetSize || 0);
|
73
71
|
});
|
74
|
-
if (mergedObsSets && obsSetSelection) {
|
72
|
+
if (mergedObsSets && obsSetSelection && obsIndex) {
|
75
73
|
const sampleIdToSetMap = sampleSets && sampleSetSelection
|
76
74
|
? treeToSelectedSetMap(sampleSets, sampleSetSelection)
|
77
75
|
: null;
|
@@ -98,11 +96,17 @@ export function TreemapSubscriber(props) {
|
|
98
96
|
];
|
99
97
|
}, [obsIndex, sampleEdges, sampleSets, obsSetColor,
|
100
98
|
sampleSetColor, mergedObsSets, obsSetSelection, mergedSampleSets,
|
101
|
-
sampleSetSelection,
|
99
|
+
sampleSetSelection, obsIndex,
|
102
100
|
// TODO: consider filtering-related coordination values
|
103
101
|
]);
|
102
|
+
const totalObsCount = obsIndex?.length || 0;
|
103
|
+
const totalSampleCount = sampleIndex?.length || 0;
|
104
|
+
const selectedObsCount = obsCounts.reduce((a, h) => a + h.value, 0);
|
105
|
+
const selectedSampleCount = sampleCounts.reduce((a, h) => a + h.value, 0);
|
106
|
+
const unselectedObsCount = totalObsCount - selectedObsCount;
|
107
|
+
const unselectedSampleCount = totalSampleCount - selectedSampleCount;
|
104
108
|
const onNodeClick = useCallback((obsSetPath) => {
|
105
109
|
setObsSetSelection([obsSetPath]);
|
106
110
|
}, [setObsSetSelection]);
|
107
|
-
return (
|
111
|
+
return (_jsxs(TitleInfo, { title: `Treemap of ${capitalize(plur(obsType, 2))}`, info: `${commaNumber(selectedObsCount)} ${plur(obsType, selectedObsCount)} from ${commaNumber(selectedSampleCount)} ${plur(sampleType, selectedSampleCount)}`, removeGridComponent: removeGridComponent, urls: urls, theme: theme, isReady: isReady, helpText: helpText, withPadding: false, options: (_jsx(TreemapOptions, { obsType: obsType, sampleType: sampleType, obsColorEncoding: obsColorEncoding, setObsColorEncoding: setObsColorEncoding, hierarchyLevels: hierarchyLevels || DEFAULT_HIERARCHY_LEVELS, setHierarchyLevels: setHierarchyLevels })), children: [_jsx("div", { ref: containerRef, className: classes.vegaContainer, children: _jsx(Treemap, { obsCounts: obsCounts, sampleCounts: sampleCounts, obsColorEncoding: obsColorEncoding, hierarchyLevels: hierarchyLevels || DEFAULT_HIERARCHY_LEVELS, theme: theme, width: width, height: Math.max(height * (selectedObsCount / totalObsCount), 40), obsType: obsType, sampleType: sampleType, obsSetColor: obsSetColor, sampleSetColor: sampleSetColor, obsSetSelection: obsSetSelection, sampleSetSelection: sampleSetSelection, onNodeClick: onNodeClick }) }), _jsx("div", { style: { position: 'absolute', right: '2px', bottom: '2px', fontSize: '10px' }, children: unselectedObsCount > 0 ? (_jsx("span", { children: `${commaNumber(unselectedObsCount)} ${plur(obsType, unselectedObsCount)} from ${commaNumber(unselectedSampleCount)} ${plur(sampleType, unselectedSampleCount)} currently omitted` })) : null })] }));
|
108
112
|
}
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"expr-hooks.d.ts","sourceRoot":"","sources":["../src/expr-hooks.js"],"names":[],"mappings":"AAiDA;;;;;;GAMG;AACH,8DAJW,GAAC,gBACD,GAAC,OA4BX;AAED;;;;;;GAMG;AACH,oEAJW,GAAC,aACD,GAAC,
|
1
|
+
{"version":3,"file":"expr-hooks.d.ts","sourceRoot":"","sources":["../src/expr-hooks.js"],"names":[],"mappings":"AAiDA;;;;;;GAMG;AACH,8DAJW,GAAC,gBACD,GAAC,OA4BX;AAED;;;;;;GAMG;AACH,oEAJW,GAAC,aACD,GAAC,OAiBX;AAED;;;;;;;;GAQG;AACH,oEALW,GAAC,YACD,GAAC,YACD,GAAC;;;;;;;;;;;;;;;;;;;;;;;;EA4DX"}
|
@@ -70,8 +70,9 @@ describe('Utility functions for processing expression data for statistical plots
|
|
70
70
|
];
|
71
71
|
const featureValueTransform = null;
|
72
72
|
const featureValueTransformCoefficient = 1;
|
73
|
+
const featureAggregationStrategy = 'first';
|
73
74
|
const [result] = stratifyExpressionData(sampleEdges, sampleSets, sampleSetSelection, expressionData, obsIndex, mergedCellSets, geneSelection, cellSetSelection, cellSetColor, featureValueTransform, featureValueTransformCoefficient);
|
74
|
-
const aggregateData = aggregateStratifiedExpressionData(result, geneSelection);
|
75
|
+
const aggregateData = aggregateStratifiedExpressionData(result, geneSelection, featureAggregationStrategy);
|
75
76
|
const summaryResult = summarizeStratifiedExpressionData(aggregateData, true);
|
76
77
|
expect(Array.from(summaryResult.keys())).toEqual([['Cell type', 'T cell'], ['Cell type', 'B cell']]);
|
77
78
|
expect(Array.from(summaryResult.get(['Cell type', 'T cell']).keys())).toEqual([['Clinical groups', 'AKI'], ['Clinical groups', 'CKD']]);
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@vitessce/statistical-plots",
|
3
|
-
"version": "3.5.
|
3
|
+
"version": "3.5.12",
|
4
4
|
"author": "HIDIVE Lab at HMS",
|
5
5
|
"homepage": "http://vitessce.io",
|
6
6
|
"repository": {
|
@@ -30,12 +30,12 @@
|
|
30
30
|
"react-aria": "^3.28.0",
|
31
31
|
"internmap": "^2.0.3",
|
32
32
|
"uuid": "^9.0.0",
|
33
|
-
"@vitessce/constants-internal": "3.5.
|
34
|
-
"@vitessce/sets-utils": "3.5.
|
35
|
-
"@vitessce/utils": "3.5.
|
36
|
-
"@vitessce/vega": "3.5.
|
37
|
-
"@vitessce/vit-s": "3.5.
|
38
|
-
"@vitessce/gl": "3.5.
|
33
|
+
"@vitessce/constants-internal": "3.5.12",
|
34
|
+
"@vitessce/sets-utils": "3.5.12",
|
35
|
+
"@vitessce/utils": "3.5.12",
|
36
|
+
"@vitessce/vega": "3.5.12",
|
37
|
+
"@vitessce/vit-s": "3.5.12",
|
38
|
+
"@vitessce/gl": "3.5.12"
|
39
39
|
},
|
40
40
|
"devDependencies": {
|
41
41
|
"react": "^18.0.0",
|
@@ -1,10 +1,13 @@
|
|
1
1
|
import React, { useCallback, useMemo } from 'react';
|
2
2
|
import { clamp, isEqual } from 'lodash-es';
|
3
3
|
import { v4 as uuidv4 } from 'uuid';
|
4
|
+
import { extent } from 'd3-array';
|
4
5
|
import { VegaPlot, VEGA_THEMES } from '@vitessce/vega';
|
5
6
|
import { capitalize } from '@vitessce/utils';
|
6
7
|
import { getColorScale } from './utils.js';
|
7
8
|
|
9
|
+
const MAX_BAR_SIZE = 40;
|
10
|
+
|
8
11
|
/**
|
9
12
|
* Cell set composition results displayed using a bar chart.
|
10
13
|
*/
|
@@ -13,9 +16,9 @@ export default function CellSetCompositionBarPlot(props) {
|
|
13
16
|
data,
|
14
17
|
theme,
|
15
18
|
width,
|
16
|
-
height,
|
19
|
+
height: heightProp,
|
17
20
|
marginRight = 200,
|
18
|
-
marginBottom =
|
21
|
+
marginBottom = 60,
|
19
22
|
keyLength = 36,
|
20
23
|
obsType,
|
21
24
|
onBarSelect,
|
@@ -27,6 +30,13 @@ export default function CellSetCompositionBarPlot(props) {
|
|
27
30
|
sampleSetColor,
|
28
31
|
} = props;
|
29
32
|
|
33
|
+
const height = (
|
34
|
+
Array.isArray(obsSetSelection)
|
35
|
+
&& ((heightProp - marginBottom) / obsSetSelection.length >= MAX_BAR_SIZE)
|
36
|
+
)
|
37
|
+
? MAX_BAR_SIZE * obsSetSelection.length + marginBottom
|
38
|
+
: heightProp;
|
39
|
+
|
30
40
|
const [obsSetColorScale, sampleSetColorScale] = useMemo(() => [
|
31
41
|
getColorScale(obsSetSelection, obsSetColor, theme),
|
32
42
|
getColorScale(sampleSetSelection, sampleSetColor, theme),
|
@@ -39,21 +49,17 @@ export default function CellSetCompositionBarPlot(props) {
|
|
39
49
|
// Return in array-of-objects form that Vega-Lite likes.
|
40
50
|
|
41
51
|
const referenceCellType = metadata?.analysis_params?.reference_cell_type;
|
52
|
+
const covariateValue = metadata?.analysis_params?.covariate_value;
|
42
53
|
const coordinationValues = metadata?.coordination_values;
|
43
54
|
const obsSetColumnName = coordinationValues?.obsSetSelection?.[0]?.[0];
|
44
55
|
const obsSetGroupName = obsSetsColumnNameMappingReversed?.[obsSetColumnName];
|
45
56
|
|
46
57
|
const sampleSetColumnName = coordinationValues?.sampleSetFilter?.[0]?.[0];
|
47
58
|
const sampleSetGroupName = sampleSetsColumnNameMappingReversed?.[sampleSetColumnName];
|
48
|
-
|
49
|
-
// See https://github.com/keller-mark/compasce/issues/30 which should simplify this logic once implemented,
|
50
|
-
// so that we would no longer need to load/check the covariate column in the frontend.
|
51
|
-
const covariatePrefix = `${sampleSetColumnName}T.`;
|
52
|
-
const firstCovariateValue = df.covariate?.[0]?.substring(covariatePrefix.length);
|
53
|
-
const firstCovariateSetPath = [sampleSetGroupName, firstCovariateValue];
|
59
|
+
const covariateSetPath = [sampleSetGroupName, covariateValue];
|
54
60
|
|
55
61
|
let shouldSwapFoldChangeDirection = false;
|
56
|
-
if (isEqual(
|
62
|
+
if (isEqual(covariateSetPath, sampleSetSelection[0])) {
|
57
63
|
shouldSwapFoldChangeDirection = true;
|
58
64
|
}
|
59
65
|
|
@@ -114,6 +120,24 @@ export default function CellSetCompositionBarPlot(props) {
|
|
114
120
|
range: [2.0, 0.5],
|
115
121
|
};
|
116
122
|
|
123
|
+
const xExtent = useMemo(() => {
|
124
|
+
if (computedData) {
|
125
|
+
const [min, max] = extent(computedData.map(d => d.logFoldChange));
|
126
|
+
const buffer = 1.05; // Ensure some extra space
|
127
|
+
const minAbs = Math.abs(min) * buffer;
|
128
|
+
const maxAbs = Math.abs(max) * buffer;
|
129
|
+
if (minAbs > maxAbs) {
|
130
|
+
return [-minAbs, minAbs];
|
131
|
+
}
|
132
|
+
return [-maxAbs, maxAbs];
|
133
|
+
}
|
134
|
+
return undefined;
|
135
|
+
}, [computedData]);
|
136
|
+
|
137
|
+
const xScale = {
|
138
|
+
domain: xExtent,
|
139
|
+
};
|
140
|
+
|
117
141
|
const spec = {
|
118
142
|
mark: { type: 'bar', stroke: 'black', cursor: 'pointer' },
|
119
143
|
params: [
|
@@ -149,6 +173,7 @@ export default function CellSetCompositionBarPlot(props) {
|
|
149
173
|
field: 'logFoldChange',
|
150
174
|
type: 'quantitative',
|
151
175
|
title: 'Log fold-change',
|
176
|
+
scale: xScale,
|
152
177
|
},
|
153
178
|
color: {
|
154
179
|
field: 'key',
|
@@ -165,6 +190,7 @@ export default function CellSetCompositionBarPlot(props) {
|
|
165
190
|
field: 'isReferenceSet',
|
166
191
|
type: 'nominal',
|
167
192
|
scale: strokeWidthScale,
|
193
|
+
legend: null,
|
168
194
|
},
|
169
195
|
tooltip: {
|
170
196
|
field: 'effectExpectedSample',
|