@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.
Files changed (51) hide show
  1. package/dist/{deflate-287e693d.js → deflate-1679ef33.js} +1 -1
  2. package/dist/{index-1f1b6355.js → index-0f4fe21d.js} +2065 -1061
  3. package/dist/index.js +9 -6
  4. package/dist/{jpeg-1b2c1d25.js → jpeg-280f0ee1.js} +1 -1
  5. package/dist/{lerc-4f010cd7.js → lerc-12264a36.js} +1 -1
  6. package/dist/{lzw-e60fb582.js → lzw-70f852cc.js} +1 -1
  7. package/dist/{packbits-a8bfe098.js → packbits-393c67b2.js} +1 -1
  8. package/dist/{raw-01dff90e.js → raw-d8d7ab7f.js} +1 -1
  9. package/dist/{webimage-6b926ce3.js → webimage-5d24a8e2.js} +1 -1
  10. package/dist-tsc/CellSetCompositionBarPlot.d.ts +5 -0
  11. package/dist-tsc/CellSetCompositionBarPlot.d.ts.map +1 -0
  12. package/dist-tsc/CellSetCompositionBarPlot.js +166 -0
  13. package/dist-tsc/CellSetCompositionBarPlotSubscriber.d.ts +2 -0
  14. package/dist-tsc/CellSetCompositionBarPlotSubscriber.d.ts.map +1 -0
  15. package/dist-tsc/CellSetCompositionBarPlotSubscriber.js +40 -0
  16. package/dist-tsc/FeatureSetEnrichmentBarPlot.d.ts +5 -0
  17. package/dist-tsc/FeatureSetEnrichmentBarPlot.d.ts.map +1 -0
  18. package/dist-tsc/FeatureSetEnrichmentBarPlot.js +164 -0
  19. package/dist-tsc/FeatureSetEnrichmentBarPlotSubscriber.d.ts +2 -0
  20. package/dist-tsc/FeatureSetEnrichmentBarPlotSubscriber.d.ts.map +1 -0
  21. package/dist-tsc/FeatureSetEnrichmentBarPlotSubscriber.js +51 -0
  22. package/dist-tsc/Treemap.d.ts.map +1 -1
  23. package/dist-tsc/Treemap.js +2 -12
  24. package/dist-tsc/TreemapSubscriber.d.ts.map +1 -1
  25. package/dist-tsc/TreemapSubscriber.js +1 -0
  26. package/dist-tsc/VolcanoPlot.d.ts +2 -0
  27. package/dist-tsc/VolcanoPlot.d.ts.map +1 -0
  28. package/dist-tsc/VolcanoPlot.js +230 -0
  29. package/dist-tsc/VolcanoPlotOptions.d.ts +2 -0
  30. package/dist-tsc/VolcanoPlotOptions.d.ts.map +1 -0
  31. package/dist-tsc/VolcanoPlotOptions.js +23 -0
  32. package/dist-tsc/VolcanoPlotSubscriber.d.ts +2 -0
  33. package/dist-tsc/VolcanoPlotSubscriber.d.ts.map +1 -0
  34. package/dist-tsc/VolcanoPlotSubscriber.js +33 -0
  35. package/dist-tsc/index.d.ts +3 -0
  36. package/dist-tsc/index.js +3 -0
  37. package/dist-tsc/utils.d.ts +9 -0
  38. package/dist-tsc/utils.d.ts.map +1 -0
  39. package/dist-tsc/utils.js +40 -0
  40. package/package.json +7 -7
  41. package/src/CellSetCompositionBarPlot.js +205 -0
  42. package/src/CellSetCompositionBarPlotSubscriber.js +151 -0
  43. package/src/FeatureSetEnrichmentBarPlot.js +203 -0
  44. package/src/FeatureSetEnrichmentBarPlotSubscriber.js +166 -0
  45. package/src/Treemap.js +2 -17
  46. package/src/TreemapSubscriber.js +1 -0
  47. package/src/VolcanoPlot.js +313 -0
  48. package/src/VolcanoPlotOptions.js +136 -0
  49. package/src/VolcanoPlotSubscriber.js +162 -0
  50. package/src/index.js +3 -0
  51. package/src/utils.js +47 -0
package/dist/index.js CHANGED
@@ -1,16 +1,19 @@
1
- import { c, C, b, a, e, D, d, E, F, T } from "./index-1f1b6355.js";
1
+ import { b, e, C, d, a, h, D, f, E, F, c, T, V } from "./index-0f4fe21d.js";
2
2
  import "react";
3
3
  import "@vitessce/vit-s";
4
4
  import "react-dom";
5
5
  export {
6
- c as CellSetExpressionPlot,
6
+ b as CellSetCompositionBarPlotSubscriber,
7
+ e as CellSetExpressionPlot,
7
8
  C as CellSetExpressionPlotSubscriber,
8
- b as CellSetSizesPlot,
9
+ d as CellSetSizesPlot,
9
10
  a as CellSetSizesPlotSubscriber,
10
- e as DotPlot,
11
+ h as DotPlot,
11
12
  D as DotPlotSubscriber,
12
- d as ExpressionHistogram,
13
+ f as ExpressionHistogram,
13
14
  E as ExpressionHistogramSubscriber,
14
15
  F as FeatureBarPlotSubscriber,
15
- T as TreemapSubscriber
16
+ c as FeatureSetEnrichmentBarPlotSubscriber,
17
+ T as TreemapSubscriber,
18
+ V as VolcanoPlotSubscriber
16
19
  };
@@ -1,4 +1,4 @@
1
- import { B as BaseDecoder } from "./index-1f1b6355.js";
1
+ import { B as BaseDecoder } from "./index-0f4fe21d.js";
2
2
  import "react";
3
3
  import "@vitessce/vit-s";
4
4
  import "react-dom";
@@ -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-1f1b6355.js";
2
+ import { g as getDefaultExportFromCjs, B as BaseDecoder } from "./index-0f4fe21d.js";
3
3
  import "react";
4
4
  import "@vitessce/vit-s";
5
5
  import "react-dom";
@@ -1,4 +1,4 @@
1
- import { B as BaseDecoder } from "./index-1f1b6355.js";
1
+ import { B as BaseDecoder } from "./index-0f4fe21d.js";
2
2
  import "react";
3
3
  import "@vitessce/vit-s";
4
4
  import "react-dom";
@@ -1,4 +1,4 @@
1
- import { B as BaseDecoder } from "./index-1f1b6355.js";
1
+ import { B as BaseDecoder } from "./index-0f4fe21d.js";
2
2
  import "react";
3
3
  import "@vitessce/vit-s";
4
4
  import "react-dom";
@@ -1,4 +1,4 @@
1
- import { B as BaseDecoder } from "./index-1f1b6355.js";
1
+ import { B as BaseDecoder } from "./index-0f4fe21d.js";
2
2
  import "react";
3
3
  import "@vitessce/vit-s";
4
4
  import "react-dom";
@@ -1,4 +1,4 @@
1
- import { B as BaseDecoder } from "./index-1f1b6355.js";
1
+ import { B as BaseDecoder } from "./index-0f4fe21d.js";
2
2
  import "react";
3
3
  import "@vitessce/vit-s";
4
4
  import "react-dom";
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Cell set composition results displayed using a bar chart.
3
+ */
4
+ export default function CellSetCompositionBarPlot(props: any): JSX.Element;
5
+ //# sourceMappingURL=CellSetCompositionBarPlot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CellSetCompositionBarPlot.d.ts","sourceRoot":"","sources":["../src/CellSetCompositionBarPlot.js"],"names":[],"mappings":"AAOA;;GAEG;AACH,2EAkMC"}
@@ -0,0 +1,166 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import React, { useCallback, useMemo } from 'react';
3
+ import { clamp, isEqual } from 'lodash-es';
4
+ import { v4 as uuidv4 } from 'uuid';
5
+ import { VegaPlot, VEGA_THEMES } from '@vitessce/vega';
6
+ import { capitalize } from '@vitessce/utils';
7
+ import { getColorScale } from './utils.js';
8
+ /**
9
+ * Cell set composition results displayed using a bar chart.
10
+ */
11
+ export default function CellSetCompositionBarPlot(props) {
12
+ const { data, theme, width, height, marginRight = 200, marginBottom = 120, keyLength = 36, obsType, onBarSelect, obsSetsColumnNameMappingReversed, sampleSetsColumnNameMappingReversed, sampleSetSelection, obsSetSelection, obsSetColor, sampleSetColor, } = props;
13
+ const [obsSetColorScale, sampleSetColorScale] = useMemo(() => [
14
+ getColorScale(obsSetSelection, obsSetColor, theme),
15
+ getColorScale(sampleSetSelection, sampleSetColor, theme),
16
+ ], [obsSetSelection, sampleSetSelection, sampleSetColor, obsSetColor, theme]);
17
+ const computedData = useMemo(() => {
18
+ if (Array.isArray(data) && data.length === 1) {
19
+ // We expect only one returned data frame.
20
+ const { df, metadata } = data[0];
21
+ // Return in array-of-objects form that Vega-Lite likes.
22
+ const referenceCellType = metadata?.analysis_params?.reference_cell_type;
23
+ const coordinationValues = metadata?.coordination_values;
24
+ const obsSetColumnName = coordinationValues?.obsSetSelection?.[0]?.[0];
25
+ const obsSetGroupName = obsSetsColumnNameMappingReversed?.[obsSetColumnName];
26
+ const sampleSetColumnName = coordinationValues?.sampleSetFilter?.[0]?.[0];
27
+ const sampleSetGroupName = sampleSetsColumnNameMappingReversed?.[sampleSetColumnName];
28
+ // See https://github.com/keller-mark/compasce/issues/30 which should simplify this logic once implemented,
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];
33
+ let shouldSwapFoldChangeDirection = false;
34
+ if (isEqual(firstCovariateSetPath, sampleSetSelection[0])) {
35
+ shouldSwapFoldChangeDirection = true;
36
+ }
37
+ return df.obsSetId.map((obsSetId, i) => {
38
+ const key = uuidv4();
39
+ const isReferenceSet = (obsSetId === referenceCellType);
40
+ const name = `${obsSetId}${(isReferenceSet ? ' (reference set)' : '')}`;
41
+ const obsSetPath = [obsSetGroupName, obsSetId];
42
+ const color = obsSetColorScale(obsSetPath);
43
+ return {
44
+ name,
45
+ // Reconstruct set path array.
46
+ obsSetPath,
47
+ color,
48
+ // Unique key per bar
49
+ key,
50
+ // Add a property `keyName` which concatenates the key and the name,
51
+ // which is both unique and can easily be converted
52
+ // back to the name by taking a substring.
53
+ keyName: `${key}${name}`,
54
+ // Swap direction of foldChange/logFC if necessary
55
+ obsSetFoldChange: df.obsSetFoldChange[i] * (shouldSwapFoldChangeDirection ? -1 : 1),
56
+ logFoldChange: (Math.log2(df.obsSetFoldChange[i]) * (shouldSwapFoldChangeDirection ? -1 : 1)),
57
+ interceptExpectedSample: df.interceptExpectedSample[i],
58
+ effectExpectedSample: df.effectExpectedSample[i],
59
+ isCredibleEffect: df.isCredibleEffect[i],
60
+ // Boolean flag for wasReferenceObsSet (check metadata)
61
+ isReferenceSet: (obsSetId === referenceCellType),
62
+ };
63
+ }).filter(d => obsSetSelection
64
+ ?.find(setNamePath => isEqual(setNamePath, d.obsSetPath)));
65
+ }
66
+ return null;
67
+ }, [data, sampleSetSelection, obsSetsColumnNameMappingReversed,
68
+ sampleSetsColumnNameMappingReversed, obsSetSelection,
69
+ obsSetColorScale, sampleSetColorScale,
70
+ ]);
71
+ // Get an array of keys for sorting purposes.
72
+ const keys = computedData.map(d => d.keyName);
73
+ const colorScale = {
74
+ // Manually set the color scale so that Vega-Lite does
75
+ // not choose the colors automatically.
76
+ domain: computedData.map(d => d.key),
77
+ range: computedData.map(d => d.color),
78
+ };
79
+ const captializedObsType = capitalize(obsType);
80
+ const opacityScale = {
81
+ domain: [true, false],
82
+ range: [1.0, 0.3],
83
+ };
84
+ const strokeWidthScale = {
85
+ domain: [true, false],
86
+ range: [2.0, 0.5],
87
+ };
88
+ const spec = {
89
+ mark: { type: 'bar', stroke: 'black', cursor: 'pointer' },
90
+ params: [
91
+ {
92
+ name: 'bar_select',
93
+ select: {
94
+ type: 'point',
95
+ on: 'click[event.shiftKey === false]',
96
+ fields: ['obsSetPath'],
97
+ empty: 'none',
98
+ },
99
+ },
100
+ {
101
+ name: 'shift_bar_select',
102
+ select: {
103
+ type: 'point',
104
+ on: 'click[event.shiftKey]',
105
+ fields: ['obsSetPath'],
106
+ empty: 'none',
107
+ },
108
+ },
109
+ ],
110
+ encoding: {
111
+ y: {
112
+ field: 'keyName',
113
+ type: 'nominal',
114
+ axis: { labelExpr: `substring(datum.label, ${keyLength})` },
115
+ title: `${captializedObsType} Set`,
116
+ sort: keys,
117
+ },
118
+ x: {
119
+ // TODO: support using intercept+effect here based on user-selected options?
120
+ field: 'logFoldChange',
121
+ type: 'quantitative',
122
+ title: 'Log fold-change',
123
+ },
124
+ color: {
125
+ field: 'key',
126
+ type: 'nominal',
127
+ scale: colorScale,
128
+ legend: null,
129
+ },
130
+ fillOpacity: {
131
+ field: 'isCredibleEffect',
132
+ type: 'nominal',
133
+ scale: opacityScale,
134
+ },
135
+ strokeWidth: {
136
+ field: 'isReferenceSet',
137
+ type: 'nominal',
138
+ scale: strokeWidthScale,
139
+ },
140
+ tooltip: {
141
+ field: 'effectExpectedSample',
142
+ type: 'quantitative',
143
+ },
144
+ },
145
+ // TODO: for width, also subtract length of longest y-axis set name label.
146
+ width: clamp(width - marginRight, 10, Infinity),
147
+ height: clamp(height - marginBottom, 10, Infinity),
148
+ config: VEGA_THEMES[theme],
149
+ };
150
+ const handleSignal = (name, value) => {
151
+ if (name === 'bar_select') {
152
+ onBarSelect(value.obsSetPath);
153
+ }
154
+ else if (name === 'shift_bar_select') {
155
+ onBarSelect(value.obsSetPath, true);
156
+ }
157
+ };
158
+ const signalListeners = { bar_select: handleSignal, shift_bar_select: handleSignal };
159
+ const getTooltipText = useCallback(item => ({
160
+ [`${captializedObsType} Set`]: item.datum.name,
161
+ 'Log fold-change': item.datum.logFoldChange,
162
+ interceptExpectedSample: item.datum.interceptExpectedSample,
163
+ effectExpectedSample: item.datum.effectExpectedSample,
164
+ }), [captializedObsType]);
165
+ return (_jsx(VegaPlot, { data: computedData, spec: spec, signalListeners: signalListeners, getTooltipText: getTooltipText }));
166
+ }
@@ -0,0 +1,2 @@
1
+ export function CellSetCompositionBarPlotSubscriber(props: any): JSX.Element;
2
+ //# sourceMappingURL=CellSetCompositionBarPlotSubscriber.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CellSetCompositionBarPlotSubscriber.d.ts","sourceRoot":"","sources":["../src/CellSetCompositionBarPlotSubscriber.js"],"names":[],"mappings":"AAwBA,6EA8HC"}
@@ -0,0 +1,40 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /* eslint-disable no-unused-vars */
3
+ import React, { useMemo, useCallback } from 'react';
4
+ import { TitleInfo, useCoordination, useLoaders, useReady, useGridItemSize, useObsSetStatsData, useMatchingLoader, useColumnNameMapping, } from '@vitessce/vit-s';
5
+ import { ViewType, COMPONENT_COORDINATION_TYPES, ViewHelpMapping, DataType, } from '@vitessce/constants-internal';
6
+ import { capitalize } from '@vitessce/utils';
7
+ import CellSetCompositionBarPlot from './CellSetCompositionBarPlot.js';
8
+ import { useStyles } from './styles.js';
9
+ import { useRawSetPaths } from './utils.js';
10
+ export function CellSetCompositionBarPlotSubscriber(props) {
11
+ const { coordinationScopes, removeGridComponent, theme, helpText = ViewHelpMapping.OBS_SET_COMPOSITION_BAR_PLOT, } = props;
12
+ const classes = useStyles();
13
+ const loaders = useLoaders();
14
+ // Get "props" from the coordination space.
15
+ const [{ dataset, obsType, sampleType, featureType, featureValueType, obsFilter: cellFilter, obsHighlight: cellHighlight, obsSetSelection, obsSetColor, obsColorEncoding: cellColorEncoding, additionalObsSets: additionalCellSets, featurePointSignificanceThreshold, featurePointFoldChangeThreshold, featureLabelSignificanceThreshold, featureLabelFoldChangeThreshold, featureValueTransform, featureValueTransformCoefficient, gatingFeatureSelectionX, gatingFeatureSelectionY, featureSelection, sampleSetSelection, sampleSetColor, }, { setObsFilter: setCellFilter, setObsSetSelection, setObsHighlight: setCellHighlight, setObsSetColor: setCellSetColor, setObsColorEncoding: setCellColorEncoding, setAdditionalObsSets: setAdditionalCellSets, setFeaturePointSignificanceThreshold, setFeaturePointFoldChangeThreshold, setFeatureLabelSignificanceThreshold, setFeatureLabelFoldChangeThreshold, setFeatureValueTransform, setFeatureValueTransformCoefficient, setGatingFeatureSelectionX, setGatingFeatureSelectionY, setFeatureSelection, setSampleSetSelection, setSampleSetColor, }] = useCoordination(COMPONENT_COORDINATION_TYPES[ViewType.OBS_SET_COMPOSITION_BAR_PLOT], coordinationScopes);
16
+ const [width, height, containerRef] = useGridItemSize();
17
+ const obsSetsLoader = useMatchingLoader(loaders, dataset, DataType.OBS_SETS, { obsType });
18
+ const sampleSetsLoader = useMatchingLoader(loaders, dataset, DataType.SAMPLE_SETS, { sampleType });
19
+ const obsSetsColumnNameMapping = useColumnNameMapping(obsSetsLoader);
20
+ const obsSetsColumnNameMappingReversed = useColumnNameMapping(obsSetsLoader, true);
21
+ const sampleSetsColumnNameMapping = useColumnNameMapping(sampleSetsLoader);
22
+ const sampleSetsColumnNameMappingReversed = useColumnNameMapping(sampleSetsLoader, true);
23
+ const rawSampleSetSelection = useRawSetPaths(sampleSetsColumnNameMapping, sampleSetSelection);
24
+ const rawObsSetSelection = useRawSetPaths(obsSetsColumnNameMapping, obsSetSelection);
25
+ const [{ obsSetStats }, obsSetStatsStatus] = useObsSetStatsData(loaders, dataset, false, { obsType, sampleType },
26
+ // These volcanoOptions are passed to ObsSetStatsAnndataLoader.loadMulti():
27
+ { sampleSetSelection: rawSampleSetSelection, obsSetSelection: rawObsSetSelection });
28
+ const isReady = useReady([
29
+ obsSetStatsStatus,
30
+ ]);
31
+ // Support a click handler which selects individual cell set bars.
32
+ const onBarSelect = useCallback((setNamePath, isShiftDown = false) => {
33
+ // TODO: Implement different behavior when isShiftDown
34
+ setObsSetSelection([setNamePath]);
35
+ }, [setObsSetSelection]);
36
+ // TODO: support the following options
37
+ // - Use logFoldChange vs. intercept+effect for the bar y-value.
38
+ // - Boolean flag to allow hiding non-significant bars.
39
+ return (_jsx(TitleInfo, { title: `${capitalize(obsType)} Set Composition Analysis Plot`, removeGridComponent: removeGridComponent, theme: theme, isReady: isReady, helpText: helpText, children: _jsx("div", { ref: containerRef, className: classes.vegaContainer, children: obsSetStats ? (_jsx(CellSetCompositionBarPlot, { theme: theme, width: width, height: height, obsType: obsType, obsSetsColumnNameMapping: obsSetsColumnNameMapping, obsSetsColumnNameMappingReversed: obsSetsColumnNameMappingReversed, sampleSetsColumnNameMapping: sampleSetsColumnNameMapping, sampleSetsColumnNameMappingReversed: sampleSetsColumnNameMappingReversed, sampleSetSelection: sampleSetSelection, obsSetSelection: obsSetSelection, obsSetColor: obsSetColor, sampleSetColor: sampleSetColor, data: obsSetStats, onBarSelect: onBarSelect })) : (_jsxs("span", { children: ["Select at least one ", obsType, " set."] })) }) }));
40
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Feature set enrichment test results displayed using a bar chart.
3
+ */
4
+ export default function FeatureSetEnrichmentBarPlot(props: any): JSX.Element;
5
+ //# sourceMappingURL=FeatureSetEnrichmentBarPlot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FeatureSetEnrichmentBarPlot.d.ts","sourceRoot":"","sources":["../src/FeatureSetEnrichmentBarPlot.js"],"names":[],"mappings":"AAOA;;GAEG;AACH,6EAgMC"}
@@ -0,0 +1,164 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import React, { useCallback, useMemo } from 'react';
3
+ import { clamp } from 'lodash-es';
4
+ import { v4 as uuidv4 } from 'uuid';
5
+ import { VegaPlot, VEGA_THEMES } from '@vitessce/vega';
6
+ import { capitalize } from '@vitessce/utils';
7
+ import { getColorScale } from './utils.js';
8
+ /**
9
+ * Feature set enrichment test results displayed using a bar chart.
10
+ */
11
+ export default function FeatureSetEnrichmentBarPlot(props) {
12
+ const { data, theme, width, height, marginRight = 200, marginBottom = 120, keyLength = 36, featureType, onBarSelect, obsSetsColumnNameMappingReversed, sampleSetsColumnNameMappingReversed, sampleSetSelection, obsSetSelection, obsSetColor, sampleSetColor, pValueThreshold, } = props;
13
+ const [obsSetColorScale, sampleSetColorScale] = useMemo(() => [
14
+ getColorScale(obsSetSelection, obsSetColor, theme),
15
+ getColorScale(sampleSetSelection, sampleSetColor, theme),
16
+ ], [obsSetSelection, sampleSetSelection, sampleSetColor, obsSetColor, theme]);
17
+ const computedData = useMemo(() => {
18
+ if (Array.isArray(data)) {
19
+ let result = [];
20
+ data.forEach((comparisonObject) => {
21
+ const { df, metadata } = comparisonObject;
22
+ const coordinationValues = metadata?.coordination_values;
23
+ const rawObsSetPath = coordinationValues.obsSetFilter
24
+ ? coordinationValues.obsSetFilter[0]
25
+ : coordinationValues.obsSetSelection[0];
26
+ const obsSetPath = [...rawObsSetPath];
27
+ obsSetPath[0] = obsSetsColumnNameMappingReversed[rawObsSetPath[0]];
28
+ const color = obsSetColorScale(obsSetPath);
29
+ df.featureSetName.forEach((featureSetName, i) => {
30
+ const key = uuidv4();
31
+ result.push({
32
+ key,
33
+ name: featureSetName,
34
+ term: df.featureSetTerm[i],
35
+ color,
36
+ obsSetPath,
37
+ obsSetPaths: [obsSetPath],
38
+ obsSetNameToPval: { [obsSetPath.at(-1)]: df.featureSetSignificance[i] },
39
+ keyName: `${key}${featureSetName}`,
40
+ featureSetSignificance: df.featureSetSignificance[i],
41
+ minusLog10p: -Math.log10(df.featureSetSignificance[i]),
42
+ // Color based on obsSet
43
+ });
44
+ });
45
+ });
46
+ // TODO: instead of filtering, perhaps use virtual scrolling
47
+ // (would require custom renderer / not using Vega-Lite).
48
+ result = result
49
+ .map(d => ({
50
+ ...d,
51
+ minusLog10p: Math.min(50, d.minusLog10p), // Clamp infinite values at 50
52
+ }))
53
+ .filter(d => d.featureSetSignificance <= pValueThreshold)
54
+ .toSorted((a, b) => a.featureSetSignificance - b.featureSetSignificance)
55
+ .reduce((a, h) => {
56
+ // Only add the pathway once if it appears for multiple cell types?
57
+ const match = a.find(d => d.name === h.name);
58
+ if (match) {
59
+ match.obsSetPaths.push(h.obsSetPath);
60
+ match.obsSetNameToPval[h.obsSetPath.at(-1)] = h.featureSetSignificance;
61
+ return a;
62
+ }
63
+ return [...a, h];
64
+ }, []);
65
+ const MAX_ROWS = 25;
66
+ result = result.slice(0, MAX_ROWS);
67
+ return result;
68
+ }
69
+ return null;
70
+ }, [data, sampleSetSelection, obsSetsColumnNameMappingReversed,
71
+ sampleSetsColumnNameMappingReversed, obsSetSelection,
72
+ obsSetColorScale, sampleSetColorScale, pValueThreshold,
73
+ ]);
74
+ // Get an array of keys for sorting purposes.
75
+ const keys = computedData.map(d => d.keyName);
76
+ const colorScale = {
77
+ // Manually set the color scale so that Vega-Lite does
78
+ // not choose the colors automatically.
79
+ domain: computedData.map(d => d.key),
80
+ range: computedData.map(d => d.color),
81
+ };
82
+ const captializedFeatureType = capitalize(featureType);
83
+ const spec = {
84
+ mark: { type: 'bar', stroke: 'black', cursor: 'pointer' },
85
+ params: [
86
+ {
87
+ name: 'bar_select',
88
+ select: {
89
+ type: 'point',
90
+ on: 'click[event.shiftKey === false]',
91
+ fields: ['name'],
92
+ empty: 'none',
93
+ },
94
+ },
95
+ {
96
+ name: 'shift_bar_select',
97
+ select: {
98
+ type: 'point',
99
+ on: 'click[event.shiftKey]',
100
+ fields: ['name'],
101
+ empty: 'none',
102
+ },
103
+ },
104
+ ],
105
+ encoding: {
106
+ y: {
107
+ field: 'keyName',
108
+ type: 'nominal',
109
+ axis: { labelExpr: `substring(datum.label, ${keyLength})` },
110
+ title: `${captializedFeatureType} Set`,
111
+ sort: keys,
112
+ },
113
+ x: {
114
+ field: 'minusLog10p',
115
+ type: 'quantitative',
116
+ title: '- log10 p-value',
117
+ },
118
+ color: {
119
+ field: 'key',
120
+ type: 'nominal',
121
+ scale: colorScale,
122
+ legend: null,
123
+ },
124
+ /*
125
+ fillOpacity: {
126
+ field: 'isCredibleEffect',
127
+ type: 'nominal',
128
+ scale: opacityScale,
129
+ },
130
+ strokeWidth: {
131
+ field: 'isReferenceSet',
132
+ type: 'nominal',
133
+ scale: strokeWidthScale,
134
+ },
135
+ */
136
+ tooltip: {
137
+ field: 'featureSetSignificance',
138
+ type: 'quantitative',
139
+ },
140
+ },
141
+ // TODO: for width, also subtract length of longest y-axis set name label.
142
+ width: clamp(width - marginRight, 10, Infinity),
143
+ height: clamp(height - marginBottom, 10, Infinity),
144
+ config: VEGA_THEMES[theme],
145
+ };
146
+ const handleSignal = (name, value) => {
147
+ if (name === 'bar_select') {
148
+ onBarSelect(value.obsSetPath);
149
+ }
150
+ else if (name === 'shift_bar_select') {
151
+ onBarSelect(value.obsSetPath, true);
152
+ }
153
+ };
154
+ const signalListeners = { bar_select: handleSignal, shift_bar_select: handleSignal };
155
+ const getTooltipText = useCallback(item => ({
156
+ [`${captializedFeatureType} Set`]: item.datum.name,
157
+ 'Ontology Term': item.datum.term,
158
+ ...Object.fromEntries(Object.entries(item.datum.obsSetNameToPval).map(([cellSetName, pVal]) => ([
159
+ `p-value for ${cellSetName}`,
160
+ pVal,
161
+ ]))),
162
+ }), [captializedFeatureType]);
163
+ return (_jsx(VegaPlot, { data: computedData, spec: spec, signalListeners: signalListeners, getTooltipText: getTooltipText }));
164
+ }
@@ -0,0 +1,2 @@
1
+ export function FeatureSetEnrichmentBarPlotSubscriber(props: any): JSX.Element;
2
+ //# sourceMappingURL=FeatureSetEnrichmentBarPlotSubscriber.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FeatureSetEnrichmentBarPlotSubscriber.d.ts","sourceRoot":"","sources":["../src/FeatureSetEnrichmentBarPlotSubscriber.js"],"names":[],"mappings":"AA0BA,+EA2IC"}
@@ -0,0 +1,51 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /* eslint-disable no-unused-vars */
3
+ import React, { useCallback } from 'react';
4
+ import { TitleInfo, useCoordination, useLoaders, useReady, useGridItemSize, useFeatureSetStatsData, useMatchingLoader, useColumnNameMapping, useAsyncFunction, } from '@vitessce/vit-s';
5
+ import { ViewType, COMPONENT_COORDINATION_TYPES, ViewHelpMapping, DataType, AsyncFunctionType, } from '@vitessce/constants-internal';
6
+ import { capitalize } from '@vitessce/utils';
7
+ import FeatureSetEnrichmentBarPlot from './FeatureSetEnrichmentBarPlot.js';
8
+ import { useStyles } from './styles.js';
9
+ import { useRawSetPaths } from './utils.js';
10
+ export function FeatureSetEnrichmentBarPlotSubscriber(props) {
11
+ const { coordinationScopes, removeGridComponent, theme, helpText = ViewHelpMapping.FEATURE_SET_ENRICHMENT_BAR_PLOT, } = props;
12
+ const classes = useStyles();
13
+ const loaders = useLoaders();
14
+ const transformFeature = useAsyncFunction(AsyncFunctionType.TRANSFORM_FEATURE);
15
+ // Get "props" from the coordination space.
16
+ const [{ dataset, obsType, sampleType, featureType, featureValueType, obsFilter: cellFilter, obsHighlight: cellHighlight, obsSetSelection, obsSetColor, obsColorEncoding: cellColorEncoding, additionalObsSets: additionalCellSets, featurePointSignificanceThreshold, featurePointFoldChangeThreshold, featureLabelSignificanceThreshold, featureLabelFoldChangeThreshold, featureValueTransform, featureValueTransformCoefficient, gatingFeatureSelectionX, gatingFeatureSelectionY, featureSelection, sampleSetSelection, sampleSetColor, }, { setObsFilter: setCellFilter, setObsSetSelection, setObsHighlight: setCellHighlight, setObsSetColor: setCellSetColor, setObsColorEncoding: setCellColorEncoding, setAdditionalObsSets: setAdditionalCellSets, setFeaturePointSignificanceThreshold, setFeaturePointFoldChangeThreshold, setFeatureLabelSignificanceThreshold, setFeatureLabelFoldChangeThreshold, setFeatureValueTransform, setFeatureValueTransformCoefficient, setGatingFeatureSelectionX, setGatingFeatureSelectionY, setFeatureSelection, setSampleSetSelection, setSampleSetColor, }] = useCoordination(COMPONENT_COORDINATION_TYPES[ViewType.FEATURE_SET_ENRICHMENT_BAR_PLOT], coordinationScopes);
17
+ const [width, height, containerRef] = useGridItemSize();
18
+ const obsSetsLoader = useMatchingLoader(loaders, dataset, DataType.OBS_SETS, { obsType });
19
+ const sampleSetsLoader = useMatchingLoader(loaders, dataset, DataType.SAMPLE_SETS, { sampleType });
20
+ const obsSetsColumnNameMapping = useColumnNameMapping(obsSetsLoader);
21
+ const obsSetsColumnNameMappingReversed = useColumnNameMapping(obsSetsLoader, true);
22
+ const sampleSetsColumnNameMapping = useColumnNameMapping(sampleSetsLoader);
23
+ const sampleSetsColumnNameMappingReversed = useColumnNameMapping(sampleSetsLoader, true);
24
+ const rawSampleSetSelection = useRawSetPaths(sampleSetsColumnNameMapping, sampleSetSelection);
25
+ const rawObsSetSelection = useRawSetPaths(obsSetsColumnNameMapping, obsSetSelection);
26
+ const [{ featureSetStats }, featureSetStatsStatus] = useFeatureSetStatsData(loaders, dataset, false, { obsType, featureType, sampleType },
27
+ // These volcanoOptions are passed to ObsSetStatsAnndataLoader.loadMulti():
28
+ { sampleSetSelection: rawSampleSetSelection, obsSetSelection: rawObsSetSelection });
29
+ const isReady = useReady([
30
+ featureSetStatsStatus,
31
+ ]);
32
+ // Support a click handler which selects individual cell set bars.
33
+ const onBarSelect = useCallback(async (featureSetName, featureSetTerm, isShiftDown = false) => {
34
+ // TODO: Implement different behavior when isShiftDown
35
+ // TODO: get feature IDs using AsyncFunction transformFeature
36
+ // (pathway term in, gene names out).
37
+ const kgNode = { nodeType: 'pathway', term: featureSetTerm };
38
+ const targetFeatureType = featureType;
39
+ // Will not work since transformFeature currently:
40
+ // - matches based on kgId (rather than term)
41
+ // - only knows about Reactome pathways (not GO terms).
42
+ // console.log(await transformFeature(kgNode, targetFeatureType))
43
+ // setFeatureSelection(featureIds);
44
+ }, [setFeatureSelection]);
45
+ // TODO: support the following options
46
+ // - p-value threshold for which bars to show
47
+ // - max number of bars to show
48
+ // - Boolean flag: should same pathway which appears multiple times
49
+ // be de-duplicated (one bar per pathway, using most-significant result)?
50
+ return (_jsx(TitleInfo, { title: `${capitalize(featureType)} Set Enrichment Plot`, removeGridComponent: removeGridComponent, theme: theme, isReady: isReady, helpText: helpText, children: _jsx("div", { ref: containerRef, className: classes.vegaContainer, children: featureSetStats ? (_jsx(FeatureSetEnrichmentBarPlot, { theme: theme, width: width, height: height, obsType: obsType, featureType: featureType, obsSetsColumnNameMapping: obsSetsColumnNameMapping, obsSetsColumnNameMappingReversed: obsSetsColumnNameMappingReversed, sampleSetsColumnNameMapping: sampleSetsColumnNameMapping, sampleSetsColumnNameMappingReversed: sampleSetsColumnNameMappingReversed, sampleSetSelection: sampleSetSelection, obsSetSelection: obsSetSelection, obsSetColor: obsSetColor, sampleSetColor: sampleSetColor, data: featureSetStats, onBarSelect: onBarSelect, pValueThreshold: 0.01 })) : (_jsxs("span", { children: ["Select at least one ", obsType, " set."] })) }) }));
51
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"Treemap.d.ts","sourceRoot":"","sources":["../src/Treemap.js"],"names":[],"mappings":"AAqCA;;;;;;;;GAQG;AACH,yDA0KC"}
1
+ {"version":3,"file":"Treemap.d.ts","sourceRoot":"","sources":["../src/Treemap.js"],"names":[],"mappings":"AAsBA;;;;;;;;GAQG;AACH,yDA0KC"}
@@ -2,13 +2,12 @@ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  /* eslint-disable indent */
3
3
  /* eslint-disable camelcase */
4
4
  import React, { useMemo, useEffect, useRef } from 'react';
5
- import { scaleOrdinal } from 'd3-scale';
6
5
  import { select } from 'd3-selection';
7
6
  import { treemap, treemapBinary, hierarchy as d3_hierarchy } from 'd3-hierarchy';
8
7
  import { rollup as d3_rollup } from 'd3-array';
9
8
  import { isEqual } from 'lodash-es';
10
- import { colorArrayToString } from '@vitessce/sets-utils';
11
- import { getDefaultColor, pluralize as plur } from '@vitessce/utils';
9
+ import { pluralize as plur } from '@vitessce/utils';
10
+ import { getColorScale } from './utils.js';
12
11
  // Based on Observable's built-in DOM.uid function.
13
12
  // This is intended to be used with SVG clipPaths
14
13
  // which require a unique href value to reference
@@ -20,15 +19,6 @@ function uidGenerator(prefix) {
20
19
  return { id: `${prefix}-${i}`, href: `#${prefix}-${i}` };
21
20
  };
22
21
  }
23
- // Create a d3-scale ordinal scale mapping set paths to color strings.
24
- function getColorScale(setSelectionArr, setColorArr, theme) {
25
- return scaleOrdinal()
26
- .domain(setSelectionArr || [])
27
- .range(setSelectionArr
28
- ?.map(setNamePath => (setColorArr?.find(d => isEqual(d.path, setNamePath))?.color
29
- || getDefaultColor(theme)))
30
- ?.map(colorArrayToString) || []);
31
- }
32
22
  /**
33
23
  * Renders a treemap plot using D3.
34
24
  * References:
@@ -1 +1 @@
1
- {"version":3,"file":"TreemapSubscriber.d.ts","sourceRoot":"","sources":["../src/TreemapSubscriber.js"],"names":[],"mappings":"AAyBA,2DA2OC"}
1
+ {"version":3,"file":"TreemapSubscriber.d.ts","sourceRoot":"","sources":["../src/TreemapSubscriber.js"],"names":[],"mappings":"AAyBA,2DA4OC"}
@@ -96,6 +96,7 @@ export function TreemapSubscriber(props) {
96
96
  ];
97
97
  }, [obsIndex, sampleEdges, sampleSets, obsSetColor,
98
98
  sampleSetColor, mergedObsSets, obsSetSelection, mergedSampleSets,
99
+ sampleSetSelection,
99
100
  // TODO: consider filtering-related coordination values
100
101
  ]);
101
102
  return (_jsx(TitleInfo, { title: `Treemap of ${capitalize(plur(obsType, 2))}`, info: `${commaNumber(obsCount)} ${plur(obsType, obsCount)} from ${commaNumber(sampleCount)} ${plur(sampleType, sampleCount)}`, removeGridComponent: removeGridComponent, urls: urls, theme: theme, isReady: isReady, helpText: helpText, 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: height, obsType: obsType, sampleType: sampleType, obsSetColor: obsSetColor, sampleSetColor: sampleSetColor, obsSetSelection: obsSetSelection, sampleSetSelection: sampleSetSelection }) }) }));
@@ -0,0 +1,2 @@
1
+ export default function VolcanoPlot(props: any): JSX.Element;
2
+ //# sourceMappingURL=VolcanoPlot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VolcanoPlot.d.ts","sourceRoot":"","sources":["../src/VolcanoPlot.js"],"names":[],"mappings":"AAWA,6DA6SC"}