@vitessce/biomarker-select 3.9.2 → 3.9.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.js +5804 -4938
- package/dist-tsc/BiomarkerSelectAlt.d.ts +2 -0
- package/dist-tsc/BiomarkerSelectAlt.d.ts.map +1 -0
- package/dist-tsc/BiomarkerSelectAlt.js +11 -0
- package/dist-tsc/BiomarkerSelectAltGeneAutocomplete.d.ts +2 -0
- package/dist-tsc/BiomarkerSelectAltGeneAutocomplete.d.ts.map +1 -0
- package/dist-tsc/BiomarkerSelectAltGeneAutocomplete.js +33 -0
- package/dist-tsc/BiomarkerSelectAltSampleGroups.d.ts +2 -0
- package/dist-tsc/BiomarkerSelectAltSampleGroups.d.ts.map +1 -0
- package/dist-tsc/BiomarkerSelectAltSampleGroups.js +92 -0
- package/dist-tsc/BiomarkerSelectAltSubscriber.d.ts +14 -0
- package/dist-tsc/BiomarkerSelectAltSubscriber.d.ts.map +1 -0
- package/dist-tsc/BiomarkerSelectAltSubscriber.js +112 -0
- package/dist-tsc/ComparativeHeadingSubscriber.js +1 -1
- package/dist-tsc/index.d.ts +1 -0
- package/dist-tsc/index.js +1 -0
- package/dist-tsc/select-specific.d.ts.map +1 -1
- package/dist-tsc/select-specific.js +1 -0
- package/package.json +6 -5
- package/src/BiomarkerSelectAlt.js +49 -0
- package/src/BiomarkerSelectAltGeneAutocomplete.js +103 -0
- package/src/BiomarkerSelectAltSampleGroups.js +153 -0
- package/src/BiomarkerSelectAltSubscriber.js +178 -0
- package/src/ComparativeHeadingSubscriber.js +4 -4
- package/src/index.js +1 -0
- package/src/select-specific.js +1 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BiomarkerSelectAlt.d.ts","sourceRoot":"","sources":["../src/BiomarkerSelectAlt.js"],"names":[],"mappings":"AAOA,4DAyCC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { Grid } from '@vitessce/styles';
|
|
4
|
+
import { BiomarkerSelectAltGeneAutocomplete } from './BiomarkerSelectAltGeneAutocomplete.js';
|
|
5
|
+
import { BiomarkerSelectAltSampleGroups } from './BiomarkerSelectAltSampleGroups.js';
|
|
6
|
+
import { useStyles } from './styles.js';
|
|
7
|
+
export function BiomarkerSelectAlt(props) {
|
|
8
|
+
const { setFeatureSelection, setSampleSetFilter, setSampleSetSelection, currentModalityAgnosticSelection, setCurrentModalityAgnosticSelection, setCurrentModalitySpecificSelection, autocompleteNode, stratifications, } = props;
|
|
9
|
+
const { classes } = useStyles();
|
|
10
|
+
return (_jsx(Grid, { container: true, sx: { border: '0px solid red' }, children: _jsxs(Grid, { container: true, size: 12, className: classes.header, children: [_jsx(Grid, { container: true, size: 4, justifyContent: "flex-end", children: _jsx(BiomarkerSelectAltGeneAutocomplete, { setFeatureSelection: setFeatureSelection, autocompleteNode: autocompleteNode, currentModalityAgnosticSelection: currentModalityAgnosticSelection, setCurrentModalityAgnosticSelection: setCurrentModalityAgnosticSelection, setCurrentModalitySpecificSelection: setCurrentModalitySpecificSelection }) }), _jsx(Grid, { container: true, size: 5, justifyContent: "flex-start", flexDirection: "column", children: _jsx(BiomarkerSelectAltSampleGroups, { setSampleSetFilter: setSampleSetFilter, setSampleSetSelection: setSampleSetSelection, stratifications: stratifications }) })] }) }));
|
|
11
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BiomarkerSelectAltGeneAutocomplete.d.ts","sourceRoot":"","sources":["../src/BiomarkerSelectAltGeneAutocomplete.js"],"names":[],"mappings":"AAYA,4EA0FC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
/* eslint-disable no-unused-vars */
|
|
3
|
+
import React, { useState } from 'react';
|
|
4
|
+
import { Grid, Button, Typography, Dialog, Info as InfoIcon, SimpleAutocomplete, } from '@vitessce/styles';
|
|
5
|
+
import { useStyles } from './styles.js';
|
|
6
|
+
export function BiomarkerSelectAltGeneAutocomplete(props) {
|
|
7
|
+
const { setFeatureSelection, autocompleteNode, currentModalityAgnosticSelection, setCurrentModalityAgnosticSelection, setCurrentModalitySpecificSelection, } = props;
|
|
8
|
+
const { classes } = useStyles();
|
|
9
|
+
const [selectedItem, setSelectedItem] = useState(null);
|
|
10
|
+
const [biomarkerInfoOpen, setBiomarkerInfoOpen] = useState(false);
|
|
11
|
+
function confirmSelectedItem() {
|
|
12
|
+
// eslint-disable-next-line max-len
|
|
13
|
+
if (selectedItem && !currentModalityAgnosticSelection?.find(item => item.kgId === selectedItem?.kgId)) {
|
|
14
|
+
setCurrentModalityAgnosticSelection([
|
|
15
|
+
...(currentModalityAgnosticSelection || []),
|
|
16
|
+
selectedItem,
|
|
17
|
+
]);
|
|
18
|
+
// TODO: directly set featureSelection coordination value here instead?
|
|
19
|
+
// console.log('Setting specific selection to:', selectedItem);
|
|
20
|
+
const nextModalitySpecificSelection = [
|
|
21
|
+
...(currentModalityAgnosticSelection || []),
|
|
22
|
+
selectedItem,
|
|
23
|
+
];
|
|
24
|
+
setFeatureSelection(nextModalitySpecificSelection.map(d => d.label));
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function clearBiomarkerSelection() {
|
|
28
|
+
setCurrentModalityAgnosticSelection([]);
|
|
29
|
+
setCurrentModalitySpecificSelection([]);
|
|
30
|
+
setFeatureSelection([]);
|
|
31
|
+
}
|
|
32
|
+
return (_jsxs(_Fragment, { children: [_jsxs(Grid, { container: true, size: 12, children: [_jsx(Grid, { size: 8, children: _jsx(SimpleAutocomplete, { getMatches: autocompleteNode, onChange: item => setSelectedItem(item.data), textInputLabel: "Enter a gene", getItemLabel: item => `${item.label} (${item.data.nodeType})` }) }), selectedItem ? (_jsxs(Grid, { size: 4, children: ["\u00A0", _jsx(Button, { variant: "contained", onClick: confirmSelectedItem, children: "Select" })] })) : null] }), selectedItem ? (_jsxs(_Fragment, { children: [_jsx(Grid, { container: true, size: 12, flexDirection: "row", children: _jsxs(Button, { onClick: () => setBiomarkerInfoOpen(true), children: ["View ", selectedItem.nodeType, " info"] }) }), _jsxs(Dialog, { open: biomarkerInfoOpen, onClose: () => setBiomarkerInfoOpen(false), maxWidth: "md", children: [_jsx(Typography, { variant: "h4", title: selectedItem.term, children: selectedItem.label }), _jsxs(Grid, { container: true, size: 12, children: [_jsx(InfoIcon, {}), _jsxs(Typography, { variant: "h6", children: ["About this ", selectedItem.nodeType] })] }), _jsx(Grid, { container: true, size: 12, sx: { width: '800px' }, children: _jsx("iframe", { title: `Embedded metadata page for ontology term ${selectedItem.term}`, src: `https://identifiers.org/${selectedItem.term}`, width: "100%", height: "500", style: { border: 0 } }) }, selectedItem.term)] })] })) : null] }));
|
|
33
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BiomarkerSelectAltSampleGroups.d.ts","sourceRoot":"","sources":["../src/BiomarkerSelectAltSampleGroups.js"],"names":[],"mappings":"AAKA,wEAmJC"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import React, { useState, useMemo } from 'react';
|
|
3
|
+
import { Grid, NativeSelect } from '@vitessce/styles';
|
|
4
|
+
import { isEqual } from 'lodash-es';
|
|
5
|
+
export function BiomarkerSelectAltSampleGroups(props) {
|
|
6
|
+
const { setSampleSetFilter, setSampleSetSelection, stratifications, } = props;
|
|
7
|
+
const [lhsSelectedGroup, setLhsSelectedGroup] = useState(null);
|
|
8
|
+
const [rhsSelectedGroup, setRhsSelectedGroup] = useState(null);
|
|
9
|
+
const sampleSetOptions = stratifications?.filter(s => s.stratificationType === 'sampleSet');
|
|
10
|
+
const hasSampleSetOptions = sampleSetOptions && sampleSetOptions.length > 0;
|
|
11
|
+
const lhsOptions = useMemo(() => {
|
|
12
|
+
if (sampleSetOptions) {
|
|
13
|
+
const result = [];
|
|
14
|
+
const withDuplicates = sampleSetOptions.map(o => o.sampleSets).flat();
|
|
15
|
+
withDuplicates.forEach((setPath) => {
|
|
16
|
+
if (!result.find(r => isEqual(r.path, setPath))) {
|
|
17
|
+
const rhsOptionsForLhs = [];
|
|
18
|
+
sampleSetOptions.forEach((o) => {
|
|
19
|
+
const pathPair = o.sampleSets;
|
|
20
|
+
if (isEqual(pathPair[0], setPath)) {
|
|
21
|
+
const otherPath = pathPair[1];
|
|
22
|
+
rhsOptionsForLhs.push({
|
|
23
|
+
name: `${otherPath[0]}: ${otherPath[1]}`,
|
|
24
|
+
path: otherPath,
|
|
25
|
+
sampleSets: o.sampleSets,
|
|
26
|
+
stratificationId: o.stratificationId,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
else if (isEqual(pathPair[1], setPath)) {
|
|
30
|
+
const otherPath = pathPair[0];
|
|
31
|
+
rhsOptionsForLhs.push({
|
|
32
|
+
name: `${otherPath[0]}: ${otherPath[1]}`,
|
|
33
|
+
path: otherPath,
|
|
34
|
+
// Reverse the order.
|
|
35
|
+
sampleSets: [o.sampleSets[1], o.sampleSets[0]],
|
|
36
|
+
stratificationId: o.stratificationId,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
result.push({
|
|
41
|
+
name: `${setPath[0]}: ${setPath[1]}`,
|
|
42
|
+
path: setPath,
|
|
43
|
+
rhsOptions: rhsOptionsForLhs,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
return result;
|
|
48
|
+
}
|
|
49
|
+
return [];
|
|
50
|
+
}, [sampleSetOptions]);
|
|
51
|
+
const rhsOptions = useMemo(() => {
|
|
52
|
+
if (sampleSetOptions && lhsOptions && lhsSelectedGroup) {
|
|
53
|
+
const lhsOption = lhsOptions.find(o => o.name === lhsSelectedGroup);
|
|
54
|
+
return lhsOption ? lhsOption.rhsOptions : [];
|
|
55
|
+
}
|
|
56
|
+
return [];
|
|
57
|
+
}, [sampleSetOptions, lhsOptions, lhsSelectedGroup]);
|
|
58
|
+
function handleFirstGroupChange(event) {
|
|
59
|
+
setLhsSelectedGroup(event.target.value);
|
|
60
|
+
// Update the sampleSetFilter and sampleSetSelection.
|
|
61
|
+
if (event.target.value === '__all__') {
|
|
62
|
+
setSampleSetFilter(null);
|
|
63
|
+
setSampleSetSelection(null);
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
const lhsOption = lhsOptions.find(o => o.name === event.target.value);
|
|
67
|
+
if (lhsOption) {
|
|
68
|
+
setSampleSetFilter([lhsOption.path]);
|
|
69
|
+
setSampleSetSelection([lhsOption.path]);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function handleSecondGroupChange(event) {
|
|
74
|
+
setRhsSelectedGroup(event.target.value);
|
|
75
|
+
// Update the sampleSetFilter and sampleSetSelection.
|
|
76
|
+
if (event.target.value === '__none__') {
|
|
77
|
+
const lhsOption = lhsOptions.find(o => o.name === lhsSelectedGroup);
|
|
78
|
+
if (lhsOption) {
|
|
79
|
+
setSampleSetFilter([lhsOption.path]);
|
|
80
|
+
setSampleSetSelection([lhsOption.path]);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
const rhsOption = rhsOptions.find(o => o.name === event.target.value);
|
|
85
|
+
if (rhsOption) {
|
|
86
|
+
setSampleSetFilter(rhsOption.sampleSets);
|
|
87
|
+
setSampleSetSelection(rhsOption.sampleSets);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return (_jsxs(_Fragment, { children: [_jsxs(Grid, { container: true, size: 12, children: [_jsx(Grid, { container: true, size: 4, children: _jsx("span", { style: { lineHeight: '50px' }, children: "in:\u00A0" }) }), _jsx(Grid, { container: true, size: 8, children: _jsxs(NativeSelect, { onChange: handleFirstGroupChange, value: lhsSelectedGroup ?? '__all__', variant: "standard", sx: { width: '100%' }, children: [_jsx("option", { value: "__all__", children: "All" }), hasSampleSetOptions ? (_jsx(_Fragment, { children: lhsOptions.map(o => (_jsx("option", { value: o.name, children: o.name }))) })) : null] }) })] }), _jsxs(Grid, { container: true, size: 12, children: [_jsx(Grid, { container: true, size: 4, children: _jsx("span", { style: { lineHeight: '50px' }, children: "compare to:\u00A0" }) }), _jsx(Grid, { container: true, size: 8, children: _jsxs(NativeSelect, { onChange: handleSecondGroupChange, value: rhsSelectedGroup ?? '__none__', variant: "standard", sx: { width: '100%' }, children: [_jsx("option", { value: "__none__", children: "None" }), hasSampleSetOptions ? (_jsx(_Fragment, { children: rhsOptions.map(o => (_jsx("option", { value: o.name, children: o.name }))) })) : null] }) })] })] }));
|
|
92
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Alternative biomarker select UI.
|
|
3
|
+
* @param {object} props
|
|
4
|
+
* @param {{ name: string, stratificationType: string, sampleSets: [string[], string[]]}[]} props.stratificationOptions
|
|
5
|
+
* @returns
|
|
6
|
+
*/
|
|
7
|
+
export function BiomarkerSelectAltSubscriber(props: {
|
|
8
|
+
stratificationOptions: {
|
|
9
|
+
name: string;
|
|
10
|
+
stratificationType: string;
|
|
11
|
+
sampleSets: [string[], string[]];
|
|
12
|
+
}[];
|
|
13
|
+
}): JSX.Element;
|
|
14
|
+
//# sourceMappingURL=BiomarkerSelectAltSubscriber.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BiomarkerSelectAltSubscriber.d.ts","sourceRoot":"","sources":["../src/BiomarkerSelectAltSubscriber.js"],"names":[],"mappings":"AAkBA;;;;;GAKG;AACH,oDAHG;IAA+F,qBAAqB,EAA5G;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,kBAAkB,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,CAAC,CAAA;KAAC,EAAE;CACvF,eA2JF"}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
/* eslint-disable max-len */
|
|
3
|
+
/* eslint-disable no-unused-vars */
|
|
4
|
+
import React, { useState, useCallback, useMemo } from 'react';
|
|
5
|
+
import { useAsyncFunction, useViewConfigStoreApi, useSetViewConfig, useViewConfig, useCoordination, useLoaders, useComparisonMetadata, useMatchingLoader, useColumnNameMapping, useCoordinationScopes, } from '@vitessce/vit-s';
|
|
6
|
+
import { AsyncFunctionType, ViewType, COMPONENT_COORDINATION_TYPES, DataType } from '@vitessce/constants-internal';
|
|
7
|
+
import { BiomarkerSelectAlt } from './BiomarkerSelectAlt.js';
|
|
8
|
+
/**
|
|
9
|
+
* Alternative biomarker select UI.
|
|
10
|
+
* @param {object} props
|
|
11
|
+
* @param {{ name: string, stratificationType: string, sampleSets: [string[], string[]]}[]} props.stratificationOptions
|
|
12
|
+
* @returns
|
|
13
|
+
*/
|
|
14
|
+
export function BiomarkerSelectAltSubscriber(props) {
|
|
15
|
+
const { coordinationScopes: coordinationScopesRaw, } = props;
|
|
16
|
+
const loaders = useLoaders();
|
|
17
|
+
const coordinationScopes = useCoordinationScopes(coordinationScopesRaw);
|
|
18
|
+
const [{ dataset, obsType, sampleType, sampleSetFilter, sampleSetSelection, featureSelection, }, { setSampleSetFilter, setSampleSetSelection, setFeatureSelection, }] = useCoordination(COMPONENT_COORDINATION_TYPES[ViewType.BIOMARKER_SELECT], coordinationScopes);
|
|
19
|
+
const viewConfigStoreApi = useViewConfigStoreApi();
|
|
20
|
+
const viewConfig = useViewConfig();
|
|
21
|
+
const setViewConfig = useSetViewConfig(viewConfigStoreApi);
|
|
22
|
+
// Need obsSets and sampleSets options to obtain mapping between
|
|
23
|
+
// group names and column names.
|
|
24
|
+
const obsSetsLoader = useMatchingLoader(loaders, dataset, DataType.OBS_SETS, { obsType });
|
|
25
|
+
const sampleSetsLoader = useMatchingLoader(loaders, dataset, DataType.SAMPLE_SETS, { sampleType });
|
|
26
|
+
const sampleSetsColumnNameMappingReversed = useColumnNameMapping(sampleSetsLoader, true);
|
|
27
|
+
const [mode] = useState(null);
|
|
28
|
+
const [currentModalityAgnosticSelection, setCurrentModalityAgnosticSelection] = useState(null);
|
|
29
|
+
const [currentModalitySpecificSelection, setCurrentModalitySpecificSelection] = useState(null);
|
|
30
|
+
const [currentStratificationSelection, setCurrentStratificationSelection] = useState(null);
|
|
31
|
+
const autocompleteFeature = useAsyncFunction(AsyncFunctionType.AUTOCOMPLETE_FEATURE);
|
|
32
|
+
const transformFeature = useAsyncFunction(AsyncFunctionType.TRANSFORM_FEATURE);
|
|
33
|
+
const autocompleteNode = useCallback(async (inputValue) => {
|
|
34
|
+
const results = await autocompleteFeature(inputValue);
|
|
35
|
+
return results.map(item => ({
|
|
36
|
+
label: item.label,
|
|
37
|
+
data: item,
|
|
38
|
+
}));
|
|
39
|
+
}, [autocompleteFeature]);
|
|
40
|
+
const getEdges = useCallback(async (node, targetModality) => transformFeature(node, targetModality), [transformFeature]);
|
|
41
|
+
const [{ comparisonMetadata }, cmpMetadataStatus, cmpMetadataUrls] = useComparisonMetadata(loaders, dataset, false, {}, {}, { obsType, sampleType });
|
|
42
|
+
const stratificationOptions = useMemo(() => {
|
|
43
|
+
/*
|
|
44
|
+
return array of objects like {
|
|
45
|
+
stratificationId: 'aki-vs-hr',
|
|
46
|
+
name: 'Acute kidney injury (AKI) vs. Healthy reference',
|
|
47
|
+
stratificationType: 'sampleSet', // key changed from 'groupType'. value changed from 'clinical'
|
|
48
|
+
sampleSets: [
|
|
49
|
+
['Disease Type', 'AKI'],
|
|
50
|
+
['Disease Type', 'Reference'],
|
|
51
|
+
],
|
|
52
|
+
},
|
|
53
|
+
*/
|
|
54
|
+
if (comparisonMetadata?.sample_group_pairs) {
|
|
55
|
+
return comparisonMetadata.sample_group_pairs.map((sampleGroupPair) => {
|
|
56
|
+
const [sampleGroupCol, sampleGroupValues] = sampleGroupPair;
|
|
57
|
+
const [sampleGroupCtrl, sampleGroupCase] = sampleGroupValues;
|
|
58
|
+
const groupName = sampleSetsColumnNameMappingReversed?.[sampleGroupCol];
|
|
59
|
+
return {
|
|
60
|
+
stratificationId: `${sampleGroupCol}_${sampleGroupCtrl}-vs-${sampleGroupCase}`,
|
|
61
|
+
name: `${groupName}: ${sampleGroupCtrl} vs. ${sampleGroupCase}`,
|
|
62
|
+
stratificationType: 'sampleSet',
|
|
63
|
+
sampleSets: [
|
|
64
|
+
// With sampleSets coming from the comparison_metadata,
|
|
65
|
+
// need to use loader options from obsSets and sampleSets to get mapping
|
|
66
|
+
// from column name to group name.
|
|
67
|
+
[groupName, sampleGroupCtrl],
|
|
68
|
+
[groupName, sampleGroupCase],
|
|
69
|
+
],
|
|
70
|
+
};
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
return null;
|
|
74
|
+
}, [comparisonMetadata, sampleSetsColumnNameMappingReversed]);
|
|
75
|
+
// TODO: Remove mode/step logic
|
|
76
|
+
// TODO: remove currentModalityAgnostic/SpecificSelection and use featureSelection + sampleSetSelection as the source of truth.
|
|
77
|
+
// Get rid of the local state within the children components and pass down the coordination values and setters directly
|
|
78
|
+
// so that everything stays in sync.
|
|
79
|
+
// E.g., if a user selects a gene from the volcano plot, the autocomplete input should reflect that selection
|
|
80
|
+
// and allow the user to view the corresponding gene info / gene card.
|
|
81
|
+
return (_jsx(_Fragment, { children: _jsx(BiomarkerSelectAlt, { setFeatureSelection: setFeatureSelection, setSampleSetFilter: setSampleSetFilter, setSampleSetSelection: setSampleSetSelection, currentModalityAgnosticSelection: currentModalityAgnosticSelection, setCurrentModalityAgnosticSelection: setCurrentModalityAgnosticSelection, setCurrentModalitySpecificSelection: setCurrentModalitySpecificSelection, autocompleteNode: autocompleteNode, stratifications: stratificationOptions, onFinish: () => {
|
|
82
|
+
if (mode === 'exploratory') {
|
|
83
|
+
// mode is exploratory, configure accordingly.
|
|
84
|
+
// TODO
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
// mode is confirmatory, configure accordingly.
|
|
88
|
+
// TODO
|
|
89
|
+
}
|
|
90
|
+
const newViewConfig = {
|
|
91
|
+
...viewConfig,
|
|
92
|
+
coordinationSpace: {
|
|
93
|
+
...viewConfig.coordinationSpace,
|
|
94
|
+
sampleSetFilter: {
|
|
95
|
+
...viewConfig.coordinationSpace.sampleSetFilter,
|
|
96
|
+
__comparison__: currentStratificationSelection?.sampleSets,
|
|
97
|
+
},
|
|
98
|
+
sampleSetSelection: {
|
|
99
|
+
...viewConfig.coordinationSpace.sampleSetSelection,
|
|
100
|
+
__comparison__: currentStratificationSelection?.sampleSets,
|
|
101
|
+
},
|
|
102
|
+
featureSelection: {
|
|
103
|
+
...viewConfig.coordinationSpace.featureSelection,
|
|
104
|
+
__comparison__: currentModalitySpecificSelection ? currentModalitySpecificSelection.map(d => d.label) : null,
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
// TODO: can the normal coordination value setters be used instead?
|
|
109
|
+
// (e.g., setFeatureSelection, setSampleSetSelection)
|
|
110
|
+
setViewConfig(newViewConfig);
|
|
111
|
+
} }) }));
|
|
112
|
+
}
|
|
@@ -56,5 +56,5 @@ export function ComparativeHeadingSubscriber(props) {
|
|
|
56
56
|
setFeatureSelection(null);
|
|
57
57
|
}
|
|
58
58
|
}, [featureSelection, setFeatureSelection]);
|
|
59
|
-
return (_jsxs("div", { className: classes.headingContainer, children: [sampleSetSelection && sampleSetSelection.length === 2 ? (_jsxs("div", { className: classes.headingSectionContainer, children: [_jsx("div", { style: { width: '45%' }, children: _jsx("
|
|
59
|
+
return (_jsxs("div", { className: classes.headingContainer, children: [sampleSetSelection && sampleSetSelection.length === 2 ? (_jsxs("div", { className: classes.headingSectionContainer, children: [_jsx("div", { style: { width: '45%' }, children: _jsx("h3", { className: classes.headingText, children: sampleSetSelection?.[0]?.at(-1) }) }), _jsx("div", { style: { width: '5%' }, children: _jsx("h3", { className: classes.headingText, style: { textAlign: 'right' }, children: "vs.\u00A0" }) }), _jsx("div", { style: { width: '50%' }, children: _jsx("h3", { 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("h3", { 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] }));
|
|
60
60
|
}
|
package/dist-tsc/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { BiomarkerSelectSubscriber } from "./BiomarkerSelectSubscriber.js";
|
|
2
|
+
export { BiomarkerSelectAltSubscriber } from "./BiomarkerSelectAltSubscriber.js";
|
|
2
3
|
export { ComparativeHeadingSubscriber } from "./ComparativeHeadingSubscriber.js";
|
|
3
4
|
export { SampleSetPairManagerSubscriber } from "./SampleSetPairManagerSubscriber.js";
|
|
4
5
|
export { autocompleteFeature, transformFeature, getAlternativeTerms, getTermMapping } from "./default-async-functions.js";
|
package/dist-tsc/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { BiomarkerSelectSubscriber } from './BiomarkerSelectSubscriber.js';
|
|
2
|
+
export { BiomarkerSelectAltSubscriber } from './BiomarkerSelectAltSubscriber.js';
|
|
2
3
|
export { ComparativeHeadingSubscriber } from './ComparativeHeadingSubscriber.js';
|
|
3
4
|
export { SampleSetPairManagerSubscriber } from './SampleSetPairManagerSubscriber.js';
|
|
4
5
|
export { autocompleteFeature, transformFeature, getAlternativeTerms, getTermMapping, } from './default-async-functions.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"select-specific.d.ts","sourceRoot":"","sources":["../src/select-specific.js"],"names":[],"mappings":"AA+BA,
|
|
1
|
+
{"version":3,"file":"select-specific.d.ts","sourceRoot":"","sources":["../src/select-specific.js"],"names":[],"mappings":"AA+BA,wDA6FC"}
|
|
@@ -64,6 +64,7 @@ export function SelectSpecific(props) {
|
|
|
64
64
|
const newSelection = Array.from(newRowSelectionModel.ids)
|
|
65
65
|
.map(kgId => data.find(d => d.target.kgId === kgId)?.target)
|
|
66
66
|
.filter(Boolean);
|
|
67
|
+
// console.log('New specific selection:', newSelection);
|
|
67
68
|
setCurrentModalitySpecificSelection(newSelection);
|
|
68
69
|
}
|
|
69
70
|
return (_jsxs(_Fragment, { children: [_jsx(Grid, { size: 6, children: _jsx(Typography, { variant: "h6", children: "Select a feature type:" }) }), _jsx(Grid, { container: true, size: 6, children: _jsx(Grid, { children: _jsxs(FormControl, { fullWidth: true, children: [_jsx(NativeSelect, { defaultValue: "gene", classes: { select: classes.selectInput }, inputProps: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vitessce/biomarker-select",
|
|
3
|
-
"version": "3.9.
|
|
3
|
+
"version": "3.9.3",
|
|
4
4
|
"author": "Gehlenborg Lab",
|
|
5
5
|
"homepage": "http://vitessce.io",
|
|
6
6
|
"repository": {
|
|
@@ -21,10 +21,11 @@
|
|
|
21
21
|
"fuse.js": "^7.0.0",
|
|
22
22
|
"d3-dsv": "^1.1.1",
|
|
23
23
|
"clsx": "^1.1.1",
|
|
24
|
-
"
|
|
25
|
-
"@vitessce/styles": "3.9.
|
|
26
|
-
"@vitessce/
|
|
27
|
-
"@vitessce/
|
|
24
|
+
"lodash-es": "^4.17.21",
|
|
25
|
+
"@vitessce/styles": "3.9.3",
|
|
26
|
+
"@vitessce/constants-internal": "3.9.3",
|
|
27
|
+
"@vitessce/vit-s": "3.9.3",
|
|
28
|
+
"@vitessce/types": "3.9.3"
|
|
28
29
|
},
|
|
29
30
|
"devDependencies": {
|
|
30
31
|
"@testing-library/jest-dom": "^6.6.3",
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Grid } from '@vitessce/styles';
|
|
3
|
+
import { BiomarkerSelectAltGeneAutocomplete } from './BiomarkerSelectAltGeneAutocomplete.js';
|
|
4
|
+
import { BiomarkerSelectAltSampleGroups } from './BiomarkerSelectAltSampleGroups.js';
|
|
5
|
+
import { useStyles } from './styles.js';
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
export function BiomarkerSelectAlt(props) {
|
|
9
|
+
const {
|
|
10
|
+
setFeatureSelection,
|
|
11
|
+
setSampleSetFilter,
|
|
12
|
+
setSampleSetSelection,
|
|
13
|
+
|
|
14
|
+
currentModalityAgnosticSelection,
|
|
15
|
+
setCurrentModalityAgnosticSelection,
|
|
16
|
+
setCurrentModalitySpecificSelection,
|
|
17
|
+
|
|
18
|
+
autocompleteNode,
|
|
19
|
+
|
|
20
|
+
stratifications,
|
|
21
|
+
} = props;
|
|
22
|
+
const { classes } = useStyles();
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<Grid container sx={{ border: '0px solid red' }}>
|
|
27
|
+
<Grid container size={12} className={classes.header}>
|
|
28
|
+
<Grid container size={4} justifyContent="flex-end">
|
|
29
|
+
<BiomarkerSelectAltGeneAutocomplete
|
|
30
|
+
setFeatureSelection={setFeatureSelection}
|
|
31
|
+
autocompleteNode={autocompleteNode}
|
|
32
|
+
|
|
33
|
+
currentModalityAgnosticSelection={currentModalityAgnosticSelection}
|
|
34
|
+
setCurrentModalityAgnosticSelection={setCurrentModalityAgnosticSelection}
|
|
35
|
+
setCurrentModalitySpecificSelection={setCurrentModalitySpecificSelection}
|
|
36
|
+
/>
|
|
37
|
+
</Grid>
|
|
38
|
+
<Grid container size={5} justifyContent="flex-start" flexDirection="column">
|
|
39
|
+
<BiomarkerSelectAltSampleGroups
|
|
40
|
+
setSampleSetFilter={setSampleSetFilter}
|
|
41
|
+
setSampleSetSelection={setSampleSetSelection}
|
|
42
|
+
|
|
43
|
+
stratifications={stratifications}
|
|
44
|
+
/>
|
|
45
|
+
</Grid>
|
|
46
|
+
</Grid>
|
|
47
|
+
</Grid>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/* eslint-disable no-unused-vars */
|
|
2
|
+
import React, { useState } from 'react';
|
|
3
|
+
import {
|
|
4
|
+
Grid, Button,
|
|
5
|
+
Typography,
|
|
6
|
+
Dialog,
|
|
7
|
+
Info as InfoIcon,
|
|
8
|
+
SimpleAutocomplete,
|
|
9
|
+
} from '@vitessce/styles';
|
|
10
|
+
import { useStyles } from './styles.js';
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
export function BiomarkerSelectAltGeneAutocomplete(props) {
|
|
14
|
+
const {
|
|
15
|
+
setFeatureSelection,
|
|
16
|
+
autocompleteNode,
|
|
17
|
+
currentModalityAgnosticSelection,
|
|
18
|
+
setCurrentModalityAgnosticSelection,
|
|
19
|
+
setCurrentModalitySpecificSelection,
|
|
20
|
+
} = props;
|
|
21
|
+
const { classes } = useStyles();
|
|
22
|
+
|
|
23
|
+
const [selectedItem, setSelectedItem] = useState(null);
|
|
24
|
+
|
|
25
|
+
const [biomarkerInfoOpen, setBiomarkerInfoOpen] = useState(false);
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
function confirmSelectedItem() {
|
|
29
|
+
// eslint-disable-next-line max-len
|
|
30
|
+
if (selectedItem && !currentModalityAgnosticSelection?.find(item => item.kgId === selectedItem?.kgId)) {
|
|
31
|
+
setCurrentModalityAgnosticSelection([
|
|
32
|
+
...(currentModalityAgnosticSelection || []),
|
|
33
|
+
selectedItem,
|
|
34
|
+
]);
|
|
35
|
+
// TODO: directly set featureSelection coordination value here instead?
|
|
36
|
+
// console.log('Setting specific selection to:', selectedItem);
|
|
37
|
+
const nextModalitySpecificSelection = [
|
|
38
|
+
...(currentModalityAgnosticSelection || []),
|
|
39
|
+
selectedItem,
|
|
40
|
+
];
|
|
41
|
+
setFeatureSelection(nextModalitySpecificSelection.map(d => d.label));
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function clearBiomarkerSelection() {
|
|
46
|
+
setCurrentModalityAgnosticSelection([]);
|
|
47
|
+
setCurrentModalitySpecificSelection([]);
|
|
48
|
+
setFeatureSelection([]);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return (
|
|
52
|
+
<>
|
|
53
|
+
<Grid container size={12}>
|
|
54
|
+
<Grid size={8}>
|
|
55
|
+
<SimpleAutocomplete
|
|
56
|
+
getMatches={autocompleteNode}
|
|
57
|
+
onChange={item => setSelectedItem(item.data)}
|
|
58
|
+
textInputLabel="Enter a gene"
|
|
59
|
+
getItemLabel={item => `${item.label} (${item.data.nodeType})`}
|
|
60
|
+
/>
|
|
61
|
+
</Grid>
|
|
62
|
+
{selectedItem ? (
|
|
63
|
+
<Grid size={4}>
|
|
64
|
+
|
|
65
|
+
<Button
|
|
66
|
+
variant="contained"
|
|
67
|
+
onClick={confirmSelectedItem}
|
|
68
|
+
>
|
|
69
|
+
Select
|
|
70
|
+
</Button>
|
|
71
|
+
</Grid>
|
|
72
|
+
) : null}
|
|
73
|
+
</Grid>
|
|
74
|
+
{selectedItem ? (
|
|
75
|
+
<>
|
|
76
|
+
<Grid container size={12} flexDirection="row">
|
|
77
|
+
<Button onClick={() => setBiomarkerInfoOpen(true)}>
|
|
78
|
+
View {selectedItem.nodeType} info
|
|
79
|
+
</Button>
|
|
80
|
+
</Grid>
|
|
81
|
+
<Dialog open={biomarkerInfoOpen} onClose={() => setBiomarkerInfoOpen(false)} maxWidth="md">
|
|
82
|
+
<Typography variant="h4" title={selectedItem.term}>
|
|
83
|
+
{selectedItem.label}
|
|
84
|
+
</Typography>
|
|
85
|
+
<Grid container size={12}>
|
|
86
|
+
<InfoIcon />
|
|
87
|
+
<Typography variant="h6">About this {selectedItem.nodeType}</Typography>
|
|
88
|
+
</Grid>
|
|
89
|
+
<Grid container size={12} key={selectedItem.term} sx={{ width: '800px' }}>
|
|
90
|
+
<iframe
|
|
91
|
+
title={`Embedded metadata page for ontology term ${selectedItem.term}`}
|
|
92
|
+
src={`https://identifiers.org/${selectedItem.term}`}
|
|
93
|
+
width="100%"
|
|
94
|
+
height="500"
|
|
95
|
+
style={{ border: 0 }}
|
|
96
|
+
/>
|
|
97
|
+
</Grid>
|
|
98
|
+
</Dialog>
|
|
99
|
+
</>
|
|
100
|
+
) : null}
|
|
101
|
+
</>
|
|
102
|
+
);
|
|
103
|
+
}
|