@vitessce/statistical-plots 2.0.2 → 2.0.3
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 +76191 -0
- package/{dist → dist-tsc}/index.js +0 -0
- package/package.json +10 -10
- package/src/CellSetExpressionPlot.js +278 -0
- package/src/CellSetExpressionPlotOptions.js +75 -0
- package/src/CellSetExpressionPlotSubscriber.js +228 -0
- package/src/CellSetSizesPlot.js +96 -0
- package/src/CellSetSizesPlotSubscriber.js +105 -0
- package/{dist → src}/ExpressionHistogram.js +42 -26
- package/src/ExpressionHistogramSubscriber.js +118 -0
- package/src/index.js +6 -0
- package/src/styles.js +9 -0
- package/dist/CellSetExpressionPlot.js +0 -248
- package/dist/CellSetExpressionPlotOptions.js +0 -32
- package/dist/CellSetExpressionPlotSubscriber.js +0 -111
- package/dist/CellSetSizesPlot.js +0 -77
- package/dist/CellSetSizesPlotSubscriber.js +0 -44
- package/dist/ExpressionHistogramSubscriber.js +0 -63
- package/dist/styles.js +0 -8
@@ -0,0 +1,96 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import clamp from 'lodash/clamp';
|
3
|
+
import { VegaPlot, VEGA_THEMES } from '@vitessce/vega';
|
4
|
+
import { colorArrayToString } from '@vitessce/sets-utils';
|
5
|
+
import { capitalize } from '@vitessce/utils';
|
6
|
+
|
7
|
+
/**
|
8
|
+
* Cell set sizes displayed as a bar chart,
|
9
|
+
* implemented with the VegaPlot component.
|
10
|
+
* @param {object} props
|
11
|
+
* @param {object[]} props.data The set size data, an array
|
12
|
+
* of objects with properties `name`, `key`, `color`, and `size`.
|
13
|
+
* @param {string} props.theme The name of the current Vitessce theme.
|
14
|
+
* @param {number} props.width The container width.
|
15
|
+
* @param {number} props.height The container height.
|
16
|
+
* @param {number} props.marginRight The size of the margin
|
17
|
+
* on the right side of the plot, to account for the vega menu button.
|
18
|
+
* By default, 90.
|
19
|
+
* @param {number} props.marginBottom The size of the margin
|
20
|
+
* on the bottom of the plot, to account for long x-axis labels.
|
21
|
+
* By default, 120.
|
22
|
+
* @param {number} props.keyLength The length of the `key` property of
|
23
|
+
* each data point. Assumes all key strings have the same length.
|
24
|
+
* By default, 36.
|
25
|
+
*/
|
26
|
+
export default function CellSetSizesPlot(props) {
|
27
|
+
const {
|
28
|
+
data: rawData,
|
29
|
+
theme,
|
30
|
+
width,
|
31
|
+
height,
|
32
|
+
marginRight = 90,
|
33
|
+
marginBottom = 120,
|
34
|
+
keyLength = 36,
|
35
|
+
obsType,
|
36
|
+
} = props;
|
37
|
+
|
38
|
+
// Add a property `keyName` which concatenates the key and the name,
|
39
|
+
// which is both unique and can easily be converted
|
40
|
+
// back to the name by taking a substring.
|
41
|
+
// Add a property `colorString` which contains the `[r, g, b]` color
|
42
|
+
// after converting to a color hex string.
|
43
|
+
const data = rawData.map(d => ({
|
44
|
+
...d,
|
45
|
+
keyName: d.key + d.name,
|
46
|
+
colorString: colorArrayToString(d.color),
|
47
|
+
}));
|
48
|
+
|
49
|
+
// Manually set the color scale so that Vega-Lite does
|
50
|
+
// not choose the colors automatically.
|
51
|
+
const colors = {
|
52
|
+
domain: data.map(d => d.key),
|
53
|
+
range: data.map(d => d.colorString),
|
54
|
+
};
|
55
|
+
|
56
|
+
// Get an array of keys for sorting purposes.
|
57
|
+
const keys = data.map(d => d.keyName);
|
58
|
+
|
59
|
+
const spec = {
|
60
|
+
mark: { type: 'bar' },
|
61
|
+
encoding: {
|
62
|
+
x: {
|
63
|
+
field: 'keyName',
|
64
|
+
type: 'nominal',
|
65
|
+
axis: { labelExpr: `substring(datum.label, ${keyLength})` },
|
66
|
+
title: 'Cell Set',
|
67
|
+
sort: keys,
|
68
|
+
},
|
69
|
+
y: {
|
70
|
+
field: 'size',
|
71
|
+
type: 'quantitative',
|
72
|
+
title: `${capitalize(obsType)} Set Size`,
|
73
|
+
},
|
74
|
+
color: {
|
75
|
+
field: 'key',
|
76
|
+
type: 'nominal',
|
77
|
+
scale: colors,
|
78
|
+
legend: null,
|
79
|
+
},
|
80
|
+
tooltip: {
|
81
|
+
field: 'size',
|
82
|
+
type: 'quantitative',
|
83
|
+
},
|
84
|
+
},
|
85
|
+
width: clamp(width - marginRight, 10, Infinity),
|
86
|
+
height: clamp(height - marginBottom, 10, Infinity),
|
87
|
+
config: VEGA_THEMES[theme],
|
88
|
+
};
|
89
|
+
|
90
|
+
return (
|
91
|
+
<VegaPlot
|
92
|
+
data={data}
|
93
|
+
spec={spec}
|
94
|
+
/>
|
95
|
+
);
|
96
|
+
}
|
@@ -0,0 +1,105 @@
|
|
1
|
+
import React, { useMemo } from 'react';
|
2
|
+
import {
|
3
|
+
TitleInfo,
|
4
|
+
useCoordination, useLoaders,
|
5
|
+
useUrls, useReady, useGridItemSize,
|
6
|
+
useObsSetsData,
|
7
|
+
registerPluginViewType,
|
8
|
+
} from '@vitessce/vit-s';
|
9
|
+
import { ViewType, COMPONENT_COORDINATION_TYPES } from '@vitessce/constants-internal';
|
10
|
+
import { mergeObsSets, treeToSetSizesBySetNames } from '@vitessce/sets-utils';
|
11
|
+
import { capitalize } from '@vitessce/utils';
|
12
|
+
import CellSetSizesPlot from './CellSetSizesPlot';
|
13
|
+
import { useStyles } from './styles';
|
14
|
+
|
15
|
+
/**
|
16
|
+
* A subscriber component for `CellSetSizePlot`,
|
17
|
+
* which listens for cell sets data updates and
|
18
|
+
* `GRID_RESIZE` events.
|
19
|
+
* @param {object} props
|
20
|
+
* @param {function} props.removeGridComponent The grid component removal function.
|
21
|
+
* @param {function} props.onReady The function to call when the subscriptions
|
22
|
+
* have been made.
|
23
|
+
* @param {string} props.theme The name of the current Vitessce theme.
|
24
|
+
* @param {string} props.title The component title.
|
25
|
+
*/
|
26
|
+
export function CellSetSizesPlotSubscriber(props) {
|
27
|
+
const {
|
28
|
+
coordinationScopes,
|
29
|
+
removeGridComponent,
|
30
|
+
theme,
|
31
|
+
title: titleOverride,
|
32
|
+
} = props;
|
33
|
+
|
34
|
+
const classes = useStyles();
|
35
|
+
|
36
|
+
const loaders = useLoaders();
|
37
|
+
|
38
|
+
// Get "props" from the coordination space.
|
39
|
+
const [{
|
40
|
+
dataset,
|
41
|
+
obsType,
|
42
|
+
obsSetSelection: cellSetSelection,
|
43
|
+
obsSetColor: cellSetColor,
|
44
|
+
additionalObsSets: additionalCellSets,
|
45
|
+
}, {
|
46
|
+
setObsSetSelection: setCellSetSelection,
|
47
|
+
setObsSetColor: setCellSetColor,
|
48
|
+
}] = useCoordination(COMPONENT_COORDINATION_TYPES[ViewType.OBS_SET_SIZES], coordinationScopes);
|
49
|
+
|
50
|
+
const title = titleOverride || `${capitalize(obsType)} Set Sizes`;
|
51
|
+
|
52
|
+
const [width, height, containerRef] = useGridItemSize();
|
53
|
+
const [urls, addUrl] = useUrls(loaders, dataset);
|
54
|
+
|
55
|
+
// Get data from loaders using the data hooks.
|
56
|
+
const [{ obsSets: cellSets }, obsSetsStatus] = useObsSetsData(
|
57
|
+
loaders, dataset, addUrl, true,
|
58
|
+
{ setObsSetSelection: setCellSetSelection, setObsSetColor: setCellSetColor },
|
59
|
+
{ obsSetSelection: cellSetSelection, obsSetColor: cellSetColor },
|
60
|
+
{ obsType },
|
61
|
+
);
|
62
|
+
const isReady = useReady([
|
63
|
+
obsSetsStatus,
|
64
|
+
]);
|
65
|
+
|
66
|
+
const mergedCellSets = useMemo(
|
67
|
+
() => mergeObsSets(cellSets, additionalCellSets),
|
68
|
+
[cellSets, additionalCellSets],
|
69
|
+
);
|
70
|
+
|
71
|
+
// From the cell sets hierarchy and the list of selected cell sets,
|
72
|
+
// generate the array of set sizes data points for the bar plot.
|
73
|
+
const data = useMemo(() => (mergedCellSets && cellSetSelection && cellSetColor
|
74
|
+
? treeToSetSizesBySetNames(mergedCellSets, cellSetSelection, cellSetColor, theme)
|
75
|
+
: []
|
76
|
+
), [mergedCellSets, cellSetSelection, cellSetColor, theme]);
|
77
|
+
|
78
|
+
return (
|
79
|
+
<TitleInfo
|
80
|
+
title={title}
|
81
|
+
removeGridComponent={removeGridComponent}
|
82
|
+
urls={urls}
|
83
|
+
theme={theme}
|
84
|
+
isReady={isReady}
|
85
|
+
>
|
86
|
+
<div ref={containerRef} className={classes.vegaContainer}>
|
87
|
+
<CellSetSizesPlot
|
88
|
+
data={data}
|
89
|
+
theme={theme}
|
90
|
+
width={width}
|
91
|
+
height={height}
|
92
|
+
obsType={obsType}
|
93
|
+
/>
|
94
|
+
</div>
|
95
|
+
</TitleInfo>
|
96
|
+
);
|
97
|
+
}
|
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,7 @@
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
2
1
|
import React from 'react';
|
3
2
|
import clamp from 'lodash/clamp';
|
4
3
|
import { VegaPlot, VEGA_THEMES } from '@vitessce/vega';
|
4
|
+
|
5
5
|
/**
|
6
6
|
* Gene expression histogram displayed as a bar chart,
|
7
7
|
* implemented with the VegaPlot component.
|
@@ -21,29 +21,45 @@ import { VegaPlot, VEGA_THEMES } from '@vitessce/vega';
|
|
21
21
|
* By default, 50.
|
22
22
|
*/
|
23
23
|
export default function ExpressionHistogram(props) {
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
24
|
+
const {
|
25
|
+
geneSelection,
|
26
|
+
data,
|
27
|
+
theme,
|
28
|
+
width,
|
29
|
+
height,
|
30
|
+
marginRight = 90,
|
31
|
+
marginBottom = 50,
|
32
|
+
} = props;
|
33
|
+
|
34
|
+
const xTitle = geneSelection && geneSelection.length >= 1
|
35
|
+
? 'Normalized Expression Value'
|
36
|
+
: 'Total Normalized Transcript Count';
|
37
|
+
|
38
|
+
const spec = {
|
39
|
+
mark: { type: 'bar' },
|
40
|
+
encoding: {
|
41
|
+
x: {
|
42
|
+
field: 'value',
|
43
|
+
type: 'quantitative',
|
44
|
+
bin: { maxbins: 50 },
|
45
|
+
title: xTitle,
|
46
|
+
},
|
47
|
+
y: {
|
48
|
+
type: 'quantitative',
|
49
|
+
aggregate: 'count',
|
50
|
+
title: 'Number of Cells',
|
51
|
+
},
|
52
|
+
color: { value: 'gray' },
|
53
|
+
},
|
54
|
+
width: clamp(width - marginRight, 10, Infinity),
|
55
|
+
height: clamp(height - marginBottom, 10, Infinity),
|
56
|
+
config: VEGA_THEMES[theme],
|
57
|
+
};
|
58
|
+
|
59
|
+
return (
|
60
|
+
<VegaPlot
|
61
|
+
data={data}
|
62
|
+
spec={spec}
|
63
|
+
/>
|
64
|
+
);
|
49
65
|
}
|
@@ -0,0 +1,118 @@
|
|
1
|
+
import React, { useMemo } from 'react';
|
2
|
+
import { sum } from 'd3-array';
|
3
|
+
import {
|
4
|
+
TitleInfo,
|
5
|
+
useCoordination, useLoaders,
|
6
|
+
useUrls, useReady, useGridItemSize,
|
7
|
+
useObsFeatureMatrixData, useFeatureSelection,
|
8
|
+
registerPluginViewType,
|
9
|
+
} from '@vitessce/vit-s';
|
10
|
+
import { ViewType, COMPONENT_COORDINATION_TYPES } from '@vitessce/constants-internal';
|
11
|
+
import ExpressionHistogram from './ExpressionHistogram';
|
12
|
+
import { useStyles } from './styles';
|
13
|
+
|
14
|
+
/**
|
15
|
+
* A subscriber component for `ExpressionHistogram`,
|
16
|
+
* which listens for gene selection updates and
|
17
|
+
* `GRID_RESIZE` events.
|
18
|
+
* @param {object} props
|
19
|
+
* @param {function} props.removeGridComponent The grid component removal function.
|
20
|
+
* @param {object} props.coordinationScopes An object mapping coordination
|
21
|
+
* types to coordination scopes.
|
22
|
+
* @param {string} props.theme The name of the current Vitessce theme.
|
23
|
+
*/
|
24
|
+
export function ExpressionHistogramSubscriber(props) {
|
25
|
+
const {
|
26
|
+
coordinationScopes,
|
27
|
+
removeGridComponent,
|
28
|
+
theme,
|
29
|
+
} = props;
|
30
|
+
|
31
|
+
const classes = useStyles();
|
32
|
+
const loaders = useLoaders();
|
33
|
+
|
34
|
+
// Get "props" from the coordination space.
|
35
|
+
const [{
|
36
|
+
dataset,
|
37
|
+
obsType,
|
38
|
+
featureType,
|
39
|
+
featureValueType,
|
40
|
+
featureSelection: geneSelection,
|
41
|
+
}] = useCoordination(
|
42
|
+
COMPONENT_COORDINATION_TYPES[ViewType.FEATURE_VALUE_HISTOGRAM],
|
43
|
+
coordinationScopes,
|
44
|
+
);
|
45
|
+
|
46
|
+
const [width, height, containerRef] = useGridItemSize();
|
47
|
+
const [urls, addUrl] = useUrls(loaders, dataset);
|
48
|
+
|
49
|
+
// Get data from loaders using the data hooks.
|
50
|
+
const [{ obsIndex, featureIndex, obsFeatureMatrix }, matrixStatus] = useObsFeatureMatrixData(
|
51
|
+
loaders, dataset, addUrl, true, {}, {},
|
52
|
+
{ obsType, featureType, featureValueType },
|
53
|
+
);
|
54
|
+
// eslint-disable-next-line no-unused-vars
|
55
|
+
const [expressionData, loadedFeatureSelection, featureSelectionStatus] = useFeatureSelection(
|
56
|
+
loaders, dataset, false, geneSelection,
|
57
|
+
{ obsType, featureType, featureValueType },
|
58
|
+
);
|
59
|
+
const isReady = useReady([
|
60
|
+
matrixStatus,
|
61
|
+
featureSelectionStatus,
|
62
|
+
]);
|
63
|
+
|
64
|
+
const firstGeneSelected = geneSelection && geneSelection.length >= 1
|
65
|
+
? geneSelection[0]
|
66
|
+
: null;
|
67
|
+
|
68
|
+
// From the expression matrix and the list of selected genes,
|
69
|
+
// generate the array of data points for the histogram.
|
70
|
+
const data = useMemo(() => {
|
71
|
+
if (firstGeneSelected && obsFeatureMatrix && expressionData) {
|
72
|
+
// Create new cellColors map based on the selected gene.
|
73
|
+
return Array.from(expressionData[0]).map((_, index) => {
|
74
|
+
const value = expressionData[0][index];
|
75
|
+
const normValue = value * 100 / 255;
|
76
|
+
return { value: normValue, gene: firstGeneSelected };
|
77
|
+
});
|
78
|
+
}
|
79
|
+
if (obsFeatureMatrix) {
|
80
|
+
const numGenes = featureIndex.length;
|
81
|
+
return obsIndex.map((cellId, cellIndex) => {
|
82
|
+
const values = obsFeatureMatrix.data
|
83
|
+
.subarray(cellIndex * numGenes, (cellIndex + 1) * numGenes);
|
84
|
+
const sumValue = sum(values) * 100 / 255;
|
85
|
+
return { value: sumValue, gene: null };
|
86
|
+
});
|
87
|
+
}
|
88
|
+
return null;
|
89
|
+
}, [obsIndex, featureIndex, obsFeatureMatrix, firstGeneSelected, expressionData]);
|
90
|
+
|
91
|
+
return (
|
92
|
+
<TitleInfo
|
93
|
+
title={`Expression Histogram${(firstGeneSelected ? ` (${firstGeneSelected})` : '')}`}
|
94
|
+
removeGridComponent={removeGridComponent}
|
95
|
+
urls={urls}
|
96
|
+
theme={theme}
|
97
|
+
isReady={isReady}
|
98
|
+
>
|
99
|
+
<div ref={containerRef} className={classes.vegaContainer}>
|
100
|
+
<ExpressionHistogram
|
101
|
+
geneSelection={geneSelection}
|
102
|
+
data={data}
|
103
|
+
theme={theme}
|
104
|
+
width={width}
|
105
|
+
height={height}
|
106
|
+
/>
|
107
|
+
</div>
|
108
|
+
</TitleInfo>
|
109
|
+
);
|
110
|
+
}
|
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
ADDED
@@ -0,0 +1,6 @@
|
|
1
|
+
export { CellSetExpressionPlotSubscriber, register as registerCellSetExpression } from './CellSetExpressionPlotSubscriber';
|
2
|
+
export { CellSetSizesPlotSubscriber, register as registerCellSetSizes } from './CellSetSizesPlotSubscriber';
|
3
|
+
export { ExpressionHistogramSubscriber, register as registerExpressionHistogram } from './ExpressionHistogramSubscriber';
|
4
|
+
export { default as CellSetSizesPlot } from './CellSetSizesPlot';
|
5
|
+
export { default as CellSetExpressionPlot } from './CellSetExpressionPlot';
|
6
|
+
export { default as ExpressionHistogram } from './ExpressionHistogram';
|
package/src/styles.js
ADDED
@@ -1,248 +0,0 @@
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
2
|
-
import React from 'react';
|
3
|
-
import clamp from 'lodash/clamp';
|
4
|
-
import { VegaPlot, VEGA_THEMES, DATASET_NAME } from '@vitessce/vega';
|
5
|
-
import { colorArrayToString } from '@vitessce/sets-utils';
|
6
|
-
import { capitalize } from '@vitessce/utils';
|
7
|
-
/**
|
8
|
-
* Gene expression histogram displayed as a bar chart,
|
9
|
-
* implemented with the VegaPlot component.
|
10
|
-
* @param {object} props
|
11
|
-
* @param {object[]} props.data The expression data, an array
|
12
|
-
* of objects with properties `value`, `gene`, and `set`.
|
13
|
-
* @param {number} props.domainMax The maximum gene expression value.
|
14
|
-
* @param {object[]} props.colors An object for each
|
15
|
-
* cell set, with properties `name` and `color`.
|
16
|
-
* @param {string} props.theme The name of the current Vitessce theme.
|
17
|
-
* @param {number} props.width The container width.
|
18
|
-
* @param {number} props.height The container height.
|
19
|
-
* @param {number} props.marginRight The size of the margin
|
20
|
-
* on the right side of the plot, to account for the vega menu button.
|
21
|
-
* By default, 90.
|
22
|
-
* @param {number} props.marginBottom The size of the margin
|
23
|
-
* on the bottom of the plot, to account for long x-axis labels.
|
24
|
-
* Default is allowing the component to automatically determine the margin.
|
25
|
-
* @param {string|null} props.featureValueTransformName A name
|
26
|
-
* for the feature value transformation function.
|
27
|
-
*/
|
28
|
-
export default function CellSetExpressionPlot(props) {
|
29
|
-
const { domainMax = 100, colors, data, theme, width, height, marginRight = 90, marginBottom, obsType, featureValueType, featureValueTransformName, } = props;
|
30
|
-
// Get the max characters in an axis label for autsizing the bottom margin.
|
31
|
-
const maxCharactersForLabel = data.reduce((acc, val) => {
|
32
|
-
// eslint-disable-next-line no-param-reassign
|
33
|
-
acc = acc === undefined || val.set.length > acc ? val.set.length : acc;
|
34
|
-
return acc;
|
35
|
-
}, 0);
|
36
|
-
// Use a square-root term because the angle of the labels is 45 degrees (see below)
|
37
|
-
// so the perpendicular distance to the bottom of the labels is proportional to the
|
38
|
-
// square root of the length of the labels along the imaginary hypotenuse.
|
39
|
-
// 30 is an estimate of the pixel size of a given character and seems to work well.
|
40
|
-
const autoMarginBottom = marginBottom
|
41
|
-
|| 30 + Math.sqrt(maxCharactersForLabel / 2) * 30;
|
42
|
-
// Manually set the color scale so that Vega-Lite does
|
43
|
-
// not choose the colors automatically.
|
44
|
-
const colorScale = {
|
45
|
-
domain: colors.map(d => d.name),
|
46
|
-
range: colors.map(d => colorArrayToString(d.color)),
|
47
|
-
};
|
48
|
-
const plotWidth = clamp(width - marginRight, 10, Infinity);
|
49
|
-
const plotHeight = clamp(height - autoMarginBottom, 10, Infinity);
|
50
|
-
const numBands = colors.length;
|
51
|
-
const bandWidth = plotWidth / numBands;
|
52
|
-
const rectColor = (theme === 'dark' ? 'white' : 'black');
|
53
|
-
const spec = {
|
54
|
-
$schema: 'https://vega.github.io/schema/vega/v5.json',
|
55
|
-
description: `A violin plot showing distributions of expression levels for selected ${obsType} sets.`,
|
56
|
-
width: plotWidth,
|
57
|
-
height: plotHeight,
|
58
|
-
config: {
|
59
|
-
...VEGA_THEMES[theme],
|
60
|
-
axisBand: {
|
61
|
-
bandPosition: 1,
|
62
|
-
tickExtra: true,
|
63
|
-
tickOffset: 0,
|
64
|
-
},
|
65
|
-
},
|
66
|
-
signals: [
|
67
|
-
{ name: 'bandWidth', value: bandWidth },
|
68
|
-
{ name: 'width', value: plotWidth },
|
69
|
-
{ name: 'height', value: plotHeight },
|
70
|
-
{ name: 'trim', value: true },
|
71
|
-
],
|
72
|
-
data: [
|
73
|
-
{
|
74
|
-
name: 'density',
|
75
|
-
source: DATASET_NAME,
|
76
|
-
transform: [
|
77
|
-
{
|
78
|
-
type: 'kde',
|
79
|
-
field: 'value',
|
80
|
-
groupby: ['set'],
|
81
|
-
bandwidth: 0,
|
82
|
-
extent: [0, domainMax],
|
83
|
-
},
|
84
|
-
],
|
85
|
-
},
|
86
|
-
{
|
87
|
-
name: 'stats',
|
88
|
-
source: DATASET_NAME,
|
89
|
-
transform: [
|
90
|
-
{
|
91
|
-
type: 'aggregate',
|
92
|
-
groupby: ['set'],
|
93
|
-
fields: ['value', 'value', 'value'],
|
94
|
-
ops: ['q1', 'median', 'q3'],
|
95
|
-
as: ['q1', 'median', 'q3'],
|
96
|
-
},
|
97
|
-
],
|
98
|
-
},
|
99
|
-
],
|
100
|
-
scales: [
|
101
|
-
{
|
102
|
-
name: 'layout',
|
103
|
-
type: 'band',
|
104
|
-
range: 'width',
|
105
|
-
domain: { data: DATASET_NAME, field: 'set' },
|
106
|
-
},
|
107
|
-
{
|
108
|
-
name: 'yscale',
|
109
|
-
type: 'linear',
|
110
|
-
range: 'height',
|
111
|
-
domain: [0, domainMax],
|
112
|
-
},
|
113
|
-
{
|
114
|
-
name: 'wscale',
|
115
|
-
type: 'linear',
|
116
|
-
range: [0, { signal: 'bandWidth' }],
|
117
|
-
domain: { data: 'density', field: 'density' },
|
118
|
-
},
|
119
|
-
{
|
120
|
-
name: 'wscaleReversed',
|
121
|
-
type: 'linear',
|
122
|
-
reverse: true,
|
123
|
-
range: [0, { signal: 'bandWidth' }],
|
124
|
-
domain: { data: 'density', field: 'density' },
|
125
|
-
},
|
126
|
-
{
|
127
|
-
name: 'color',
|
128
|
-
type: 'ordinal',
|
129
|
-
...colorScale,
|
130
|
-
},
|
131
|
-
],
|
132
|
-
axes: [
|
133
|
-
{
|
134
|
-
orient: 'left',
|
135
|
-
scale: 'yscale',
|
136
|
-
zindex: 1,
|
137
|
-
title: (featureValueTransformName && featureValueTransformName !== 'None')
|
138
|
-
? [`${featureValueTransformName}-Transformed`, `Normalized ${capitalize(featureValueType)} Values`]
|
139
|
-
: `Normalized ${capitalize(featureValueType)} Values`,
|
140
|
-
},
|
141
|
-
{
|
142
|
-
orient: 'bottom',
|
143
|
-
scale: 'layout',
|
144
|
-
tickCount: 5,
|
145
|
-
zindex: 1,
|
146
|
-
title: `${capitalize(obsType)} Set`,
|
147
|
-
labelAngle: -45,
|
148
|
-
labelAlign: 'right',
|
149
|
-
},
|
150
|
-
],
|
151
|
-
marks: [
|
152
|
-
{
|
153
|
-
type: 'group',
|
154
|
-
from: {
|
155
|
-
facet: {
|
156
|
-
data: 'density',
|
157
|
-
name: 'violin',
|
158
|
-
groupby: 'set',
|
159
|
-
},
|
160
|
-
},
|
161
|
-
encode: {
|
162
|
-
enter: {
|
163
|
-
xc: { scale: 'layout', field: 'set', band: 0.5 },
|
164
|
-
width: { signal: 'bandWidth' },
|
165
|
-
height: { signal: 'height' },
|
166
|
-
},
|
167
|
-
},
|
168
|
-
data: [
|
169
|
-
{
|
170
|
-
name: 'summary',
|
171
|
-
source: 'stats',
|
172
|
-
transform: [
|
173
|
-
{
|
174
|
-
type: 'filter',
|
175
|
-
expr: 'datum.set === parent.set',
|
176
|
-
},
|
177
|
-
],
|
178
|
-
},
|
179
|
-
],
|
180
|
-
marks: [
|
181
|
-
{
|
182
|
-
type: 'area',
|
183
|
-
orient: 'vertical',
|
184
|
-
from: { data: 'violin' },
|
185
|
-
encode: {
|
186
|
-
enter: {
|
187
|
-
fill: { scale: 'color', field: { parent: 'set' } },
|
188
|
-
},
|
189
|
-
update: {
|
190
|
-
width: { scale: 'wscale', field: 'density' },
|
191
|
-
xc: { signal: 'bandWidth / 2' },
|
192
|
-
y2: { scale: 'yscale', field: 'value' },
|
193
|
-
y: { scale: 'yscale', value: 0 },
|
194
|
-
},
|
195
|
-
},
|
196
|
-
},
|
197
|
-
{
|
198
|
-
type: 'area',
|
199
|
-
orient: 'vertical',
|
200
|
-
from: { data: 'violin' },
|
201
|
-
encode: {
|
202
|
-
enter: {
|
203
|
-
fill: { scale: 'color', field: { parent: 'set' } },
|
204
|
-
},
|
205
|
-
update: {
|
206
|
-
width: { scale: 'wscaleReversed', field: 'density' },
|
207
|
-
xc: { signal: 'bandWidth' },
|
208
|
-
y2: { scale: 'yscale', field: 'value' },
|
209
|
-
y: { scale: 'yscale', value: 0 },
|
210
|
-
},
|
211
|
-
},
|
212
|
-
},
|
213
|
-
{
|
214
|
-
type: 'rect',
|
215
|
-
from: { data: 'summary' },
|
216
|
-
encode: {
|
217
|
-
enter: {
|
218
|
-
fill: { value: rectColor },
|
219
|
-
width: { value: 2 },
|
220
|
-
},
|
221
|
-
update: {
|
222
|
-
y: { scale: 'yscale', field: 'q1' },
|
223
|
-
y2: { scale: 'yscale', field: 'q3' },
|
224
|
-
xc: { signal: 'bandWidth / 2' },
|
225
|
-
},
|
226
|
-
},
|
227
|
-
},
|
228
|
-
{
|
229
|
-
type: 'rect',
|
230
|
-
from: { data: 'summary' },
|
231
|
-
encode: {
|
232
|
-
enter: {
|
233
|
-
fill: { value: rectColor },
|
234
|
-
height: { value: 2 },
|
235
|
-
width: { value: 8 },
|
236
|
-
},
|
237
|
-
update: {
|
238
|
-
y: { scale: 'yscale', field: 'median' },
|
239
|
-
xc: { signal: 'bandWidth / 2' },
|
240
|
-
},
|
241
|
-
},
|
242
|
-
},
|
243
|
-
],
|
244
|
-
},
|
245
|
-
],
|
246
|
-
};
|
247
|
-
return (_jsx(VegaPlot, { data: data, spec: spec }));
|
248
|
-
}
|