@vitessce/biomarker-select 3.5.9 → 3.5.10
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.js +963 -38
- package/dist-tsc/ComparativeHeadingSubscriber.d.ts.map +1 -1
- package/dist-tsc/ComparativeHeadingSubscriber.js +19 -5
- package/dist-tsc/SampleSetPairManagerSubscriber.d.ts +2 -0
- package/dist-tsc/SampleSetPairManagerSubscriber.d.ts.map +1 -0
- package/dist-tsc/SampleSetPairManagerSubscriber.js +76 -0
- package/dist-tsc/default-async-functions.d.ts.map +1 -1
- package/dist-tsc/default-async-functions.js +12 -5
- package/dist-tsc/index.d.ts +1 -0
- package/dist-tsc/index.js +1 -0
- package/package.json +5 -4
- package/src/ComparativeHeadingSubscriber.js +35 -5
- package/src/SampleSetPairManagerSubscriber.js +146 -0
- package/src/default-async-functions.js +12 -5
- package/src/index.js +1 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ComparativeHeadingSubscriber.d.ts","sourceRoot":"","sources":["../src/ComparativeHeadingSubscriber.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ComparativeHeadingSubscriber.d.ts","sourceRoot":"","sources":["../src/ComparativeHeadingSubscriber.js"],"names":[],"mappings":"AAsCA,sEA8EC"}
|
|
@@ -11,6 +11,13 @@ const useStyles = makeStyles(theme => ({
|
|
|
11
11
|
flexDirection: 'column',
|
|
12
12
|
justifyContent: 'center',
|
|
13
13
|
height: '100%',
|
|
14
|
+
'& div': {
|
|
15
|
+
display: 'flex',
|
|
16
|
+
flexDirection: 'row',
|
|
17
|
+
},
|
|
18
|
+
'& div > button': {
|
|
19
|
+
height: 'auto',
|
|
20
|
+
},
|
|
14
21
|
},
|
|
15
22
|
headingContainer: {
|
|
16
23
|
backgroundColor: 'transparent',
|
|
@@ -28,10 +35,7 @@ const useStyles = makeStyles(theme => ({
|
|
|
28
35
|
}));
|
|
29
36
|
export function ComparativeHeadingSubscriber(props) {
|
|
30
37
|
const { coordinationScopes, } = props;
|
|
31
|
-
const [{ sampleSetSelection, featureSelection, }, { setSampleSetSelection,
|
|
32
|
-
// TODO: buttons for modification of featureSelection
|
|
33
|
-
// setFeatureSelection,
|
|
34
|
-
}] = useCoordination(COMPONENT_COORDINATION_TYPES[ViewType.COMPARATIVE_HEADING], coordinationScopes);
|
|
38
|
+
const [{ sampleSetSelection, featureSelection, }, { setSampleSetSelection, setFeatureSelection, }] = useCoordination(COMPONENT_COORDINATION_TYPES[ViewType.COMPARATIVE_HEADING], coordinationScopes);
|
|
35
39
|
const classes = useStyles();
|
|
36
40
|
const swapSampleSets = useCallback(() => {
|
|
37
41
|
if (sampleSetSelection?.length === 2) {
|
|
@@ -41,5 +45,15 @@ export function ComparativeHeadingSubscriber(props) {
|
|
|
41
45
|
]);
|
|
42
46
|
}
|
|
43
47
|
}, [sampleSetSelection, setSampleSetSelection]);
|
|
44
|
-
|
|
48
|
+
const clearSampleSetSelection = useCallback(() => {
|
|
49
|
+
if (sampleSetSelection?.length === 2) {
|
|
50
|
+
setSampleSetSelection(null);
|
|
51
|
+
}
|
|
52
|
+
}, [sampleSetSelection, setSampleSetSelection]);
|
|
53
|
+
const clearFeatureSelection = useCallback(() => {
|
|
54
|
+
if (Array.isArray(featureSelection) && featureSelection.length > 0) {
|
|
55
|
+
setFeatureSelection(null);
|
|
56
|
+
}
|
|
57
|
+
}, [featureSelection, setFeatureSelection]);
|
|
58
|
+
return (_jsxs("div", { className: classes.headingContainer, children: [sampleSetSelection && sampleSetSelection.length === 2 ? (_jsxs("div", { className: classes.headingSectionContainer, children: [_jsx("div", { style: { width: '45%' }, children: _jsx("h2", { className: classes.headingText, children: sampleSetSelection?.[0]?.at(-1) }) }), _jsx("div", { style: { width: '5%' }, children: _jsx("h2", { className: classes.headingText, style: { textAlign: 'right' }, children: "vs.\u00A0" }) }), _jsx("div", { style: { width: '50%' }, children: _jsx("h2", { className: classes.headingText, children: sampleSetSelection?.[1]?.at(-1) }) }), _jsx("div", { className: classes.buttonContainer, children: _jsxs("div", { children: [_jsx("button", { onClick: swapSampleSets, type: "button", children: "Swap" }), _jsx("button", { onClick: clearSampleSetSelection, type: "button", children: "Clear" })] }) })] })) : (_jsx("div", { className: classes.headingSectionContainer, children: _jsx("div", { children: _jsx("h2", { className: classes.headingText, children: "All samples" }) }) })), featureSelection && featureSelection.length > 0 ? (_jsxs("div", { className: classes.headingSectionContainer, children: [_jsx("div", { children: _jsx("h3", { className: classes.headingText, children: "Selected Biomarkers:\u00A0" }) }), featureSelection?.map((featureName, i) => (_jsx("div", { children: _jsxs("h3", { className: classes.headingText, children: [featureName, i < featureSelection.length - 1 ? (_jsx("span", { children: ",\u00A0" })) : null] }) }, featureName))), _jsx("div", { className: classes.buttonContainer, children: _jsx("div", { children: _jsx("button", { onClick: clearFeatureSelection, type: "button", children: "Clear" }) }) })] })) : null] }));
|
|
45
59
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SampleSetPairManagerSubscriber.d.ts","sourceRoot":"","sources":["../src/SampleSetPairManagerSubscriber.js"],"names":[],"mappings":"AA6BA,wEAoHC"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import React, { useMemo, useCallback } from 'react';
|
|
3
|
+
import { isEqual } from 'lodash-es';
|
|
4
|
+
import clsx from 'clsx';
|
|
5
|
+
import { makeStyles } from '@material-ui/core';
|
|
6
|
+
import { TitleInfo, useReady, useCoordination, useLoaders, useComparisonMetadata, useMatchingLoader, useColumnNameMapping, } from '@vitessce/vit-s';
|
|
7
|
+
import { ViewType, DataType, COMPONENT_COORDINATION_TYPES, ViewHelpMapping } from '@vitessce/constants-internal';
|
|
8
|
+
const useStyles = makeStyles(() => ({
|
|
9
|
+
selectedPair: {
|
|
10
|
+
fontWeight: 'bold',
|
|
11
|
+
},
|
|
12
|
+
pairUl: {
|
|
13
|
+
paddingLeft: '15px',
|
|
14
|
+
marginTop: 0,
|
|
15
|
+
fontSize: '12px',
|
|
16
|
+
'& button': {
|
|
17
|
+
fontSize: '12px',
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
}));
|
|
21
|
+
export function SampleSetPairManagerSubscriber(props) {
|
|
22
|
+
const { coordinationScopes, removeGridComponent, theme, title = 'Sample Sets', closeButtonVisible, helpText = ViewHelpMapping.SAMPLE_SET_PAIR_MANAGER, } = props;
|
|
23
|
+
const classes = useStyles();
|
|
24
|
+
const loaders = useLoaders();
|
|
25
|
+
// Get "props" from the coordination space.
|
|
26
|
+
const [{ dataset, obsType, sampleType, sampleSetSelection, }, { setSampleSetSelection, }] = useCoordination(COMPONENT_COORDINATION_TYPES[ViewType.SAMPLE_SET_PAIR_MANAGER], coordinationScopes);
|
|
27
|
+
const sampleSetsLoader = useMatchingLoader(loaders, dataset, DataType.SAMPLE_SETS, { sampleType });
|
|
28
|
+
const sampleSetsColumnNameMappingReversed = useColumnNameMapping(sampleSetsLoader, true);
|
|
29
|
+
const [{ comparisonMetadata }, cmpMetadataStatus] = useComparisonMetadata(loaders, dataset, false, {}, {}, { obsType, sampleType });
|
|
30
|
+
const isReady = useReady([
|
|
31
|
+
cmpMetadataStatus,
|
|
32
|
+
]);
|
|
33
|
+
const stratificationOptions = useMemo(() => {
|
|
34
|
+
/*
|
|
35
|
+
return array of objects like {
|
|
36
|
+
stratificationId: 'aki-vs-hr',
|
|
37
|
+
name: 'Acute kidney injury (AKI) vs. Healthy reference',
|
|
38
|
+
stratificationType: 'sampleSet',
|
|
39
|
+
sampleSets: [
|
|
40
|
+
['Disease Type', 'AKI'],
|
|
41
|
+
['Disease Type', 'Reference'],
|
|
42
|
+
],
|
|
43
|
+
},
|
|
44
|
+
*/
|
|
45
|
+
if (comparisonMetadata?.sample_group_pairs) {
|
|
46
|
+
return comparisonMetadata.sample_group_pairs.map((sampleGroupPair) => {
|
|
47
|
+
const [sampleGroupCol, sampleGroupValues] = sampleGroupPair;
|
|
48
|
+
const [sampleGroupCtrl, sampleGroupCase] = sampleGroupValues;
|
|
49
|
+
const groupName = sampleSetsColumnNameMappingReversed?.[sampleGroupCol];
|
|
50
|
+
return {
|
|
51
|
+
stratificationId: `${sampleGroupCol}_${sampleGroupCtrl}-vs-${sampleGroupCase}`,
|
|
52
|
+
name: `${groupName}: ${sampleGroupCtrl} vs. ${sampleGroupCase}`,
|
|
53
|
+
stratificationType: 'sampleSet',
|
|
54
|
+
sampleSets: [
|
|
55
|
+
// With sampleSets coming from the comparison_metadata,
|
|
56
|
+
// need to use loader options from obsSets and sampleSets to get mapping
|
|
57
|
+
// from column name to group name.
|
|
58
|
+
[groupName, sampleGroupCtrl],
|
|
59
|
+
[groupName, sampleGroupCase],
|
|
60
|
+
],
|
|
61
|
+
};
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
return null;
|
|
65
|
+
}, [comparisonMetadata, sampleSetsColumnNameMappingReversed]);
|
|
66
|
+
const onSelectPair = useCallback((sampleSetPair) => {
|
|
67
|
+
setSampleSetSelection(sampleSetPair);
|
|
68
|
+
}, [sampleSetSelection, setSampleSetSelection]);
|
|
69
|
+
return (_jsx(TitleInfo, { title: title, closeButtonVisible: closeButtonVisible, removeGridComponent: removeGridComponent, isScroll: true, theme: theme, isReady: isReady, helpText: helpText, children: _jsx("ul", { className: classes.pairUl, children: stratificationOptions?.map((pairObj) => {
|
|
70
|
+
const isSelected = Array.isArray(sampleSetSelection)
|
|
71
|
+
&& sampleSetSelection.length === 2
|
|
72
|
+
&& (isEqual(pairObj.sampleSets, sampleSetSelection)
|
|
73
|
+
|| isEqual(pairObj.sampleSets, [sampleSetSelection?.[1], sampleSetSelection?.[0]]));
|
|
74
|
+
return (_jsxs("li", { className: clsx({ [classes.selectedPair]: isSelected }), children: [pairObj.name, "\u00A0", !isSelected ? (_jsx("button", { type: "button", onClick: () => onSelectPair(pairObj.sampleSets), children: "Select" })) : null] }, pairObj.stratificationId));
|
|
75
|
+
}) }) }));
|
|
76
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"default-async-functions.d.ts","sourceRoot":"","sources":["../src/default-async-functions.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"default-async-functions.d.ts","sourceRoot":"","sources":["../src/default-async-functions.js"],"names":[],"mappings":"AAyHA;;;;;;;GAOG;AACH,qDALG;IAAyB,WAAW,EAA5B,WAAW;CACnB,WAAQ,MAAM,kBACN,IAAI,GAAG,kBAAkB,GACvB,OAAO,CAAC,MAAM,EAAE,CAAC,CAiB7B;AAkBD;;;;;;;GAOG;AACH,kDALG;IAAyB,WAAW,EAA5B,WAAW;CACnB,QAAQ,MAAM,kBACN,kBAAkB,GAChB,OAAO,CAAC,MAAM,EAAE,CAAC,CAmC7B;AAED;;;;;;GAMG;AACH,qDAJG;IAAyB,WAAW,EAA5B,WAAW;CACnB,SAAQ,MAAM,GACJ,OAAO,CAAC,MAAM,EAAE,CAAC,CA2B7B;AAED;;;;;;;GAOG;AACH,gDALG;IAAyB,WAAW,EAA5B,WAAW;CACnB,kBAAQ,MAAM,kBACN,MAAM,GACJ,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAoBxC;iCAjQsD,uBAAuB;wCADsE,iBAAiB;4BAAjB,iBAAiB"}
|
|
@@ -44,14 +44,18 @@ function loadCellTypeNodes() {
|
|
|
44
44
|
* @returns {Promise<KgNode[]>}
|
|
45
45
|
*/
|
|
46
46
|
function loadPathwayNodes() {
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
const reactomeNodes = fetch(`${KG_BASE_URL}/Reactome_2022.nodes.csv`);
|
|
48
|
+
// TODO: load both GO and Reactome nodes, concat together.
|
|
49
|
+
// const goNodes = fetch(`${KG_BASE_URL}/GO_Biological_Process_2021.nodes.csv`);
|
|
50
|
+
return reactomeNodes.then(res => res.text())
|
|
49
51
|
.then((res) => {
|
|
50
52
|
const result = csvParse(res);
|
|
51
53
|
return result.map((/** @type {any} */ d) => ({
|
|
52
54
|
kgId: d.id,
|
|
53
|
-
label: d.pathway,
|
|
54
|
-
term: `reactome:${d.acc}`,
|
|
55
|
+
label: d.pathway, // For reactome
|
|
56
|
+
term: `reactome:${d.acc}`, // For reactome
|
|
57
|
+
// label: d.ontology_label, // For GO_BP
|
|
58
|
+
// term: d.acc, // For GO_BP
|
|
55
59
|
nodeType: 'pathway',
|
|
56
60
|
}));
|
|
57
61
|
});
|
|
@@ -124,7 +128,10 @@ export async function autocompleteFeature({ queryClient }, partial, targetModali
|
|
|
124
128
|
return results.map((/** @type {any} */ result) => result.item);
|
|
125
129
|
}
|
|
126
130
|
async function loadPathwayToGeneEdges() {
|
|
127
|
-
|
|
131
|
+
const reactomeEdges = fetch(`${KG_BASE_URL}/Reactome_2022.Reactome.Gene.edges.csv`);
|
|
132
|
+
// TODO: load both GO and Reactome edges, concat together.
|
|
133
|
+
// const goEdges = fetch(`${KG_BASE_URL}/GO_Biological_Process_2021.GO_BP.Gene.edges.csv`);
|
|
134
|
+
return reactomeEdges
|
|
128
135
|
.then(res => res.text())
|
|
129
136
|
.then((res) => {
|
|
130
137
|
const result = csvParse(res);
|
package/dist-tsc/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { BiomarkerSelectSubscriber } from "./BiomarkerSelectSubscriber.js";
|
|
2
2
|
export { ComparativeHeadingSubscriber } from "./ComparativeHeadingSubscriber.js";
|
|
3
|
+
export { SampleSetPairManagerSubscriber } from "./SampleSetPairManagerSubscriber.js";
|
|
3
4
|
export { autocompleteFeature, transformFeature, getAlternativeTerms, getTermMapping } from "./default-async-functions.js";
|
|
4
5
|
//# sourceMappingURL=index.d.ts.map
|
package/dist-tsc/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export { BiomarkerSelectSubscriber } from './BiomarkerSelectSubscriber.js';
|
|
2
2
|
export { ComparativeHeadingSubscriber } from './ComparativeHeadingSubscriber.js';
|
|
3
|
+
export { SampleSetPairManagerSubscriber } from './SampleSetPairManagerSubscriber.js';
|
|
3
4
|
export { autocompleteFeature, transformFeature, getAlternativeTerms, getTermMapping, } from './default-async-functions.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vitessce/biomarker-select",
|
|
3
|
-
"version": "3.5.
|
|
3
|
+
"version": "3.5.10",
|
|
4
4
|
"author": "Gehlenborg Lab",
|
|
5
5
|
"homepage": "http://vitessce.io",
|
|
6
6
|
"repository": {
|
|
@@ -24,9 +24,10 @@
|
|
|
24
24
|
"react-window": "^1.8.10",
|
|
25
25
|
"fuse.js": "^7.0.0",
|
|
26
26
|
"d3-dsv": "^1.1.1",
|
|
27
|
-
"
|
|
28
|
-
"@vitessce/
|
|
29
|
-
"@vitessce/
|
|
27
|
+
"clsx": "^1.1.1",
|
|
28
|
+
"@vitessce/constants-internal": "3.5.10",
|
|
29
|
+
"@vitessce/vit-s": "3.5.10",
|
|
30
|
+
"@vitessce/types": "3.5.10"
|
|
30
31
|
},
|
|
31
32
|
"devDependencies": {
|
|
32
33
|
"@testing-library/jest-dom": "^5.16.4",
|
|
@@ -13,6 +13,13 @@ const useStyles = makeStyles(theme => ({
|
|
|
13
13
|
flexDirection: 'column',
|
|
14
14
|
justifyContent: 'center',
|
|
15
15
|
height: '100%',
|
|
16
|
+
'& div': {
|
|
17
|
+
display: 'flex',
|
|
18
|
+
flexDirection: 'row',
|
|
19
|
+
},
|
|
20
|
+
'& div > button': {
|
|
21
|
+
height: 'auto',
|
|
22
|
+
},
|
|
16
23
|
},
|
|
17
24
|
headingContainer: {
|
|
18
25
|
backgroundColor: 'transparent',
|
|
@@ -39,8 +46,7 @@ export function ComparativeHeadingSubscriber(props) {
|
|
|
39
46
|
featureSelection,
|
|
40
47
|
}, {
|
|
41
48
|
setSampleSetSelection,
|
|
42
|
-
|
|
43
|
-
// setFeatureSelection,
|
|
49
|
+
setFeatureSelection,
|
|
44
50
|
}] = useCoordination(
|
|
45
51
|
COMPONENT_COORDINATION_TYPES[ViewType.COMPARATIVE_HEADING],
|
|
46
52
|
coordinationScopes,
|
|
@@ -57,6 +63,18 @@ export function ComparativeHeadingSubscriber(props) {
|
|
|
57
63
|
}
|
|
58
64
|
}, [sampleSetSelection, setSampleSetSelection]);
|
|
59
65
|
|
|
66
|
+
const clearSampleSetSelection = useCallback(() => {
|
|
67
|
+
if (sampleSetSelection?.length === 2) {
|
|
68
|
+
setSampleSetSelection(null);
|
|
69
|
+
}
|
|
70
|
+
}, [sampleSetSelection, setSampleSetSelection]);
|
|
71
|
+
|
|
72
|
+
const clearFeatureSelection = useCallback(() => {
|
|
73
|
+
if (Array.isArray(featureSelection) && featureSelection.length > 0) {
|
|
74
|
+
setFeatureSelection(null);
|
|
75
|
+
}
|
|
76
|
+
}, [featureSelection, setFeatureSelection]);
|
|
77
|
+
|
|
60
78
|
return (
|
|
61
79
|
<div className={classes.headingContainer}>
|
|
62
80
|
{sampleSetSelection && sampleSetSelection.length === 2 ? (
|
|
@@ -65,21 +83,33 @@ export function ComparativeHeadingSubscriber(props) {
|
|
|
65
83
|
<div style={{ width: '5%' }}><h2 className={classes.headingText} style={{ textAlign: 'right' }}>vs. </h2></div>
|
|
66
84
|
<div style={{ width: '50%' }}><h2 className={classes.headingText}>{sampleSetSelection?.[1]?.at(-1)}</h2></div>
|
|
67
85
|
<div className={classes.buttonContainer}>
|
|
68
|
-
<
|
|
86
|
+
<div>
|
|
87
|
+
<button onClick={swapSampleSets} type="button">Swap</button>
|
|
88
|
+
<button onClick={clearSampleSetSelection} type="button">Clear</button>
|
|
89
|
+
</div>
|
|
69
90
|
</div>
|
|
70
91
|
</div>
|
|
71
|
-
) :
|
|
92
|
+
) : (
|
|
93
|
+
<div className={classes.headingSectionContainer}>
|
|
94
|
+
<div><h2 className={classes.headingText}>All samples</h2></div>
|
|
95
|
+
</div>
|
|
96
|
+
)}
|
|
72
97
|
{featureSelection && featureSelection.length > 0 ? (
|
|
73
98
|
<div className={classes.headingSectionContainer}>
|
|
74
99
|
<div><h3 className={classes.headingText}>Selected Biomarkers: </h3></div>
|
|
75
100
|
{featureSelection?.map((featureName, i) => (
|
|
76
|
-
<div>
|
|
101
|
+
<div key={featureName}>
|
|
77
102
|
<h3 className={classes.headingText}>
|
|
78
103
|
{featureName}
|
|
79
104
|
{i < featureSelection.length - 1 ? (<span>, </span>) : null}
|
|
80
105
|
</h3>
|
|
81
106
|
</div>
|
|
82
107
|
))}
|
|
108
|
+
<div className={classes.buttonContainer}>
|
|
109
|
+
<div>
|
|
110
|
+
<button onClick={clearFeatureSelection} type="button">Clear</button>
|
|
111
|
+
</div>
|
|
112
|
+
</div>
|
|
83
113
|
</div>
|
|
84
114
|
) : null}
|
|
85
115
|
</div>
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import React, { useMemo, useCallback } from 'react';
|
|
2
|
+
import { isEqual } from 'lodash-es';
|
|
3
|
+
import clsx from 'clsx';
|
|
4
|
+
import { makeStyles } from '@material-ui/core';
|
|
5
|
+
import {
|
|
6
|
+
TitleInfo,
|
|
7
|
+
useReady,
|
|
8
|
+
useCoordination,
|
|
9
|
+
useLoaders,
|
|
10
|
+
useComparisonMetadata,
|
|
11
|
+
useMatchingLoader,
|
|
12
|
+
useColumnNameMapping,
|
|
13
|
+
} from '@vitessce/vit-s';
|
|
14
|
+
import { ViewType, DataType, COMPONENT_COORDINATION_TYPES, ViewHelpMapping } from '@vitessce/constants-internal';
|
|
15
|
+
|
|
16
|
+
const useStyles = makeStyles(() => ({
|
|
17
|
+
selectedPair: {
|
|
18
|
+
fontWeight: 'bold',
|
|
19
|
+
},
|
|
20
|
+
pairUl: {
|
|
21
|
+
paddingLeft: '15px',
|
|
22
|
+
marginTop: 0,
|
|
23
|
+
fontSize: '12px',
|
|
24
|
+
'& button': {
|
|
25
|
+
fontSize: '12px',
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
}));
|
|
29
|
+
|
|
30
|
+
export function SampleSetPairManagerSubscriber(props) {
|
|
31
|
+
const {
|
|
32
|
+
coordinationScopes,
|
|
33
|
+
removeGridComponent,
|
|
34
|
+
theme,
|
|
35
|
+
title = 'Sample Sets',
|
|
36
|
+
closeButtonVisible,
|
|
37
|
+
helpText = ViewHelpMapping.SAMPLE_SET_PAIR_MANAGER,
|
|
38
|
+
} = props;
|
|
39
|
+
|
|
40
|
+
const classes = useStyles();
|
|
41
|
+
const loaders = useLoaders();
|
|
42
|
+
|
|
43
|
+
// Get "props" from the coordination space.
|
|
44
|
+
const [{
|
|
45
|
+
dataset,
|
|
46
|
+
obsType,
|
|
47
|
+
sampleType,
|
|
48
|
+
sampleSetSelection,
|
|
49
|
+
}, {
|
|
50
|
+
setSampleSetSelection,
|
|
51
|
+
}] = useCoordination(
|
|
52
|
+
COMPONENT_COORDINATION_TYPES[ViewType.SAMPLE_SET_PAIR_MANAGER],
|
|
53
|
+
coordinationScopes,
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
const sampleSetsLoader = useMatchingLoader(
|
|
57
|
+
loaders, dataset, DataType.SAMPLE_SETS, { sampleType },
|
|
58
|
+
);
|
|
59
|
+
const sampleSetsColumnNameMappingReversed = useColumnNameMapping(sampleSetsLoader, true);
|
|
60
|
+
|
|
61
|
+
const [{ comparisonMetadata }, cmpMetadataStatus] = useComparisonMetadata(
|
|
62
|
+
loaders, dataset, false, {}, {}, { obsType, sampleType },
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
const isReady = useReady([
|
|
66
|
+
cmpMetadataStatus,
|
|
67
|
+
]);
|
|
68
|
+
|
|
69
|
+
const stratificationOptions = useMemo(() => {
|
|
70
|
+
/*
|
|
71
|
+
return array of objects like {
|
|
72
|
+
stratificationId: 'aki-vs-hr',
|
|
73
|
+
name: 'Acute kidney injury (AKI) vs. Healthy reference',
|
|
74
|
+
stratificationType: 'sampleSet',
|
|
75
|
+
sampleSets: [
|
|
76
|
+
['Disease Type', 'AKI'],
|
|
77
|
+
['Disease Type', 'Reference'],
|
|
78
|
+
],
|
|
79
|
+
},
|
|
80
|
+
*/
|
|
81
|
+
if (comparisonMetadata?.sample_group_pairs) {
|
|
82
|
+
return comparisonMetadata.sample_group_pairs.map((sampleGroupPair) => {
|
|
83
|
+
const [sampleGroupCol, sampleGroupValues] = sampleGroupPair;
|
|
84
|
+
const [sampleGroupCtrl, sampleGroupCase] = sampleGroupValues;
|
|
85
|
+
const groupName = sampleSetsColumnNameMappingReversed?.[sampleGroupCol];
|
|
86
|
+
return {
|
|
87
|
+
stratificationId: `${sampleGroupCol}_${sampleGroupCtrl}-vs-${sampleGroupCase}`,
|
|
88
|
+
name: `${groupName}: ${sampleGroupCtrl} vs. ${sampleGroupCase}`,
|
|
89
|
+
stratificationType: 'sampleSet',
|
|
90
|
+
sampleSets: [
|
|
91
|
+
// With sampleSets coming from the comparison_metadata,
|
|
92
|
+
// need to use loader options from obsSets and sampleSets to get mapping
|
|
93
|
+
// from column name to group name.
|
|
94
|
+
[groupName, sampleGroupCtrl],
|
|
95
|
+
[groupName, sampleGroupCase],
|
|
96
|
+
],
|
|
97
|
+
};
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
return null;
|
|
101
|
+
}, [comparisonMetadata, sampleSetsColumnNameMappingReversed]);
|
|
102
|
+
|
|
103
|
+
const onSelectPair = useCallback((sampleSetPair) => {
|
|
104
|
+
setSampleSetSelection(sampleSetPair);
|
|
105
|
+
}, [sampleSetSelection, setSampleSetSelection]);
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
return (
|
|
109
|
+
<TitleInfo
|
|
110
|
+
title={title}
|
|
111
|
+
closeButtonVisible={closeButtonVisible}
|
|
112
|
+
removeGridComponent={removeGridComponent}
|
|
113
|
+
isScroll
|
|
114
|
+
theme={theme}
|
|
115
|
+
isReady={isReady}
|
|
116
|
+
helpText={helpText}
|
|
117
|
+
>
|
|
118
|
+
<ul className={classes.pairUl}>
|
|
119
|
+
{stratificationOptions?.map((pairObj) => {
|
|
120
|
+
const isSelected = Array.isArray(sampleSetSelection)
|
|
121
|
+
&& sampleSetSelection.length === 2
|
|
122
|
+
&& (
|
|
123
|
+
isEqual(pairObj.sampleSets, sampleSetSelection)
|
|
124
|
+
|| isEqual(pairObj.sampleSets, [sampleSetSelection?.[1], sampleSetSelection?.[0]])
|
|
125
|
+
);
|
|
126
|
+
return (
|
|
127
|
+
<li
|
|
128
|
+
key={pairObj.stratificationId}
|
|
129
|
+
className={clsx({ [classes.selectedPair]: isSelected })}
|
|
130
|
+
>
|
|
131
|
+
{pairObj.name}
|
|
132
|
+
{!isSelected ? (
|
|
133
|
+
<button
|
|
134
|
+
type="button"
|
|
135
|
+
onClick={() => onSelectPair(pairObj.sampleSets)}
|
|
136
|
+
>
|
|
137
|
+
Select
|
|
138
|
+
</button>
|
|
139
|
+
) : null}
|
|
140
|
+
</li>
|
|
141
|
+
);
|
|
142
|
+
})}
|
|
143
|
+
</ul>
|
|
144
|
+
</TitleInfo>
|
|
145
|
+
);
|
|
146
|
+
}
|
|
@@ -49,14 +49,18 @@ function loadCellTypeNodes() {
|
|
|
49
49
|
* @returns {Promise<KgNode[]>}
|
|
50
50
|
*/
|
|
51
51
|
function loadPathwayNodes() {
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
const reactomeNodes = fetch(`${KG_BASE_URL}/Reactome_2022.nodes.csv`);
|
|
53
|
+
// TODO: load both GO and Reactome nodes, concat together.
|
|
54
|
+
// const goNodes = fetch(`${KG_BASE_URL}/GO_Biological_Process_2021.nodes.csv`);
|
|
55
|
+
return reactomeNodes.then(res => res.text())
|
|
54
56
|
.then((res) => {
|
|
55
57
|
const result = csvParse(res);
|
|
56
58
|
return result.map((/** @type {any} */ d) => ({
|
|
57
59
|
kgId: d.id,
|
|
58
|
-
label: d.pathway,
|
|
59
|
-
term: `reactome:${d.acc}`,
|
|
60
|
+
label: d.pathway, // For reactome
|
|
61
|
+
term: `reactome:${d.acc}`, // For reactome
|
|
62
|
+
// label: d.ontology_label, // For GO_BP
|
|
63
|
+
// term: d.acc, // For GO_BP
|
|
60
64
|
nodeType: 'pathway',
|
|
61
65
|
}));
|
|
62
66
|
});
|
|
@@ -141,7 +145,10 @@ export async function autocompleteFeature({ queryClient }, partial, targetModali
|
|
|
141
145
|
}
|
|
142
146
|
|
|
143
147
|
async function loadPathwayToGeneEdges() {
|
|
144
|
-
|
|
148
|
+
const reactomeEdges = fetch(`${KG_BASE_URL}/Reactome_2022.Reactome.Gene.edges.csv`);
|
|
149
|
+
// TODO: load both GO and Reactome edges, concat together.
|
|
150
|
+
// const goEdges = fetch(`${KG_BASE_URL}/GO_Biological_Process_2021.GO_BP.Gene.edges.csv`);
|
|
151
|
+
return reactomeEdges
|
|
145
152
|
.then(res => res.text())
|
|
146
153
|
.then((res) => {
|
|
147
154
|
const result = csvParse(res);
|
package/src/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { BiomarkerSelectSubscriber } from './BiomarkerSelectSubscriber.js';
|
|
2
2
|
export { ComparativeHeadingSubscriber } from './ComparativeHeadingSubscriber.js';
|
|
3
|
+
export { SampleSetPairManagerSubscriber } from './SampleSetPairManagerSubscriber.js';
|
|
3
4
|
export {
|
|
4
5
|
autocompleteFeature,
|
|
5
6
|
transformFeature,
|