@jbrowse/plugin-variants 3.1.0 → 3.2.0
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/MultiLinearVariantDisplay/model.d.ts +19 -0
- package/dist/MultiLinearVariantMatrixDisplay/model.d.ts +20 -0
- package/dist/MultiLinearVariantMatrixDisplay/model.js +4 -1
- package/dist/MultiLinearVariantMatrixRenderer/makeImageData.js +9 -1
- package/dist/MultiLinearVariantRenderer/makeImageData.js +9 -1
- package/dist/VariantRPC/MultiVariantClusterGenotypeMatrix.d.ts +28 -0
- package/dist/VariantRPC/MultiVariantClusterGenotypeMatrix.js +33 -0
- package/dist/VariantRPC/MultiVariantGetGenotypeMatrix.d.ts +13 -11
- package/dist/VariantRPC/MultiVariantGetGenotypeMatrix.js +5 -57
- package/dist/VariantRPC/MultiVariantGetSimplifiedFeatures.d.ts +11 -8
- package/dist/VariantRPC/MultiVariantGetSimplifiedFeatures.js +1 -2
- package/dist/VariantRPC/cluster.d.ts +17 -0
- package/dist/VariantRPC/cluster.js +84 -0
- package/dist/VariantRPC/getGenotypeMatrix.d.ts +6 -0
- package/dist/VariantRPC/getGenotypeMatrix.js +55 -0
- package/dist/VariantRPC/types.d.ts +13 -0
- package/dist/VariantRPC/types.js +2 -0
- package/dist/VcfAdapter/VcfAdapter.js +6 -3
- package/dist/VcfFeature/util.js +2 -2
- package/dist/VcfTabixAdapter/VcfTabixAdapter.js +11 -6
- package/dist/index.js +2 -0
- package/dist/shared/MultiVariantBaseModel.d.ts +19 -0
- package/dist/shared/MultiVariantBaseModel.js +27 -35
- package/dist/shared/components/ClusterDialog/ClusterDialog.d.ts +6 -0
- package/dist/shared/components/ClusterDialog/ClusterDialog.js +29 -0
- package/dist/shared/components/ClusterDialog/ClusterDialogAuto.d.ts +7 -0
- package/dist/shared/components/ClusterDialog/ClusterDialogAuto.js +69 -0
- package/dist/shared/components/ClusterDialog/ClusterDialogManual.d.ts +7 -0
- package/dist/shared/components/ClusterDialog/ClusterDialogManual.js +144 -0
- package/dist/shared/components/ClusterDialog/types.d.ts +9 -0
- package/dist/shared/components/ClusterDialog/types.js +2 -0
- package/dist/shared/components/SourcesDataGrid.js +47 -40
- package/dist/shared/components/SourcesGridHeader.js +2 -2
- package/dist/shared/getSources.d.ts +15 -0
- package/dist/shared/getSources.js +34 -0
- package/esm/MultiLinearVariantDisplay/model.d.ts +19 -0
- package/esm/MultiLinearVariantMatrixDisplay/model.d.ts +20 -0
- package/esm/MultiLinearVariantMatrixDisplay/model.js +4 -1
- package/esm/MultiLinearVariantMatrixRenderer/makeImageData.js +9 -1
- package/esm/MultiLinearVariantRenderer/makeImageData.js +9 -1
- package/esm/VariantRPC/MultiVariantClusterGenotypeMatrix.d.ts +28 -0
- package/esm/VariantRPC/MultiVariantClusterGenotypeMatrix.js +26 -0
- package/esm/VariantRPC/MultiVariantGetGenotypeMatrix.d.ts +13 -11
- package/esm/VariantRPC/MultiVariantGetGenotypeMatrix.js +5 -57
- package/esm/VariantRPC/MultiVariantGetSimplifiedFeatures.d.ts +11 -8
- package/esm/VariantRPC/MultiVariantGetSimplifiedFeatures.js +1 -2
- package/esm/VariantRPC/cluster.d.ts +17 -0
- package/esm/VariantRPC/cluster.js +79 -0
- package/esm/VariantRPC/getGenotypeMatrix.d.ts +6 -0
- package/esm/VariantRPC/getGenotypeMatrix.js +52 -0
- package/esm/VariantRPC/types.d.ts +13 -0
- package/esm/VariantRPC/types.js +1 -0
- package/esm/VcfAdapter/VcfAdapter.js +7 -4
- package/esm/VcfFeature/util.js +2 -2
- package/esm/VcfTabixAdapter/VcfTabixAdapter.js +11 -6
- package/esm/index.js +2 -0
- package/esm/shared/MultiVariantBaseModel.d.ts +19 -0
- package/esm/shared/MultiVariantBaseModel.js +27 -35
- package/esm/shared/components/ClusterDialog/ClusterDialog.d.ts +6 -0
- package/esm/shared/components/ClusterDialog/ClusterDialog.js +24 -0
- package/esm/shared/components/ClusterDialog/ClusterDialogAuto.d.ts +7 -0
- package/esm/shared/components/ClusterDialog/ClusterDialogAuto.js +67 -0
- package/esm/shared/components/ClusterDialog/ClusterDialogManual.d.ts +7 -0
- package/esm/shared/components/ClusterDialog/ClusterDialogManual.js +139 -0
- package/esm/shared/components/ClusterDialog/types.d.ts +9 -0
- package/esm/shared/components/ClusterDialog/types.js +1 -0
- package/esm/shared/components/SourcesDataGrid.js +47 -40
- package/esm/shared/components/SourcesGridHeader.js +2 -2
- package/esm/shared/getSources.d.ts +15 -0
- package/esm/shared/getSources.js +31 -0
- package/package.json +6 -6
- package/dist/shared/components/ClusterDialog.d.ts +0 -11
- package/dist/shared/components/ClusterDialog.js +0 -113
- package/esm/shared/components/ClusterDialog.d.ts +0 -11
- package/esm/shared/components/ClusterDialog.js +0 -107
|
@@ -3,15 +3,17 @@ import { ConfigurationReference } from '@jbrowse/core/configuration';
|
|
|
3
3
|
import { getSession } from '@jbrowse/core/util';
|
|
4
4
|
import { stopStopToken } from '@jbrowse/core/util/stopToken';
|
|
5
5
|
import { linearBareDisplayStateModelFactory } from '@jbrowse/plugin-linear-genome-view';
|
|
6
|
+
import CategoryIcon from '@mui/icons-material/Category';
|
|
6
7
|
import FilterListIcon from '@mui/icons-material/FilterList';
|
|
7
8
|
import HeightIcon from '@mui/icons-material/Height';
|
|
8
9
|
import SplitscreenIcon from '@mui/icons-material/Splitscreen';
|
|
9
10
|
import VisibilityIcon from '@mui/icons-material/Visibility';
|
|
10
11
|
import deepEqual from 'fast-deep-equal';
|
|
11
12
|
import { types } from 'mobx-state-tree';
|
|
13
|
+
import { getSources } from './getSources';
|
|
12
14
|
const SetColorDialog = lazy(() => import('./components/SetColorDialog'));
|
|
13
15
|
const MAFFilterDialog = lazy(() => import('./components/MAFFilterDialog'));
|
|
14
|
-
const ClusterDialog = lazy(() => import('./components/ClusterDialog'));
|
|
16
|
+
const ClusterDialog = lazy(() => import('./components/ClusterDialog/ClusterDialog'));
|
|
15
17
|
const SetRowHeightDialog = lazy(() => import('./components/SetRowHeightDialog'));
|
|
16
18
|
export default function MultiVariantBaseModelF(configSchema) {
|
|
17
19
|
return types
|
|
@@ -86,40 +88,26 @@ export default function MultiVariantBaseModelF(configSchema) {
|
|
|
86
88
|
get preSources() {
|
|
87
89
|
return self.layout.length ? self.layout : self.sourcesVolatile;
|
|
88
90
|
},
|
|
91
|
+
get sourcesWithoutLayout() {
|
|
92
|
+
return self.sourcesVolatile
|
|
93
|
+
? getSources({
|
|
94
|
+
sources: self.sourcesVolatile,
|
|
95
|
+
renderingMode: self.renderingMode,
|
|
96
|
+
sampleInfo: self.sampleInfo,
|
|
97
|
+
})
|
|
98
|
+
: undefined;
|
|
99
|
+
},
|
|
89
100
|
get sources() {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
const id = `${row.name} HP${i}`;
|
|
101
|
-
rows.push({
|
|
102
|
-
...sources[row.name],
|
|
103
|
-
...row,
|
|
104
|
-
label: id,
|
|
105
|
-
HP: i,
|
|
106
|
-
id: id,
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
else {
|
|
112
|
-
rows.push({
|
|
113
|
-
...sources[row.name],
|
|
114
|
-
...row,
|
|
115
|
-
label: row.name,
|
|
116
|
-
id: row.name,
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
return rows;
|
|
121
|
-
}
|
|
122
|
-
return undefined;
|
|
101
|
+
const sourcesWithLayout = self.layout.length
|
|
102
|
+
? self.layout
|
|
103
|
+
: self.sourcesVolatile;
|
|
104
|
+
return sourcesWithLayout
|
|
105
|
+
? getSources({
|
|
106
|
+
sources: sourcesWithLayout,
|
|
107
|
+
renderingMode: self.renderingMode,
|
|
108
|
+
sampleInfo: self.sampleInfo,
|
|
109
|
+
})
|
|
110
|
+
: undefined;
|
|
123
111
|
},
|
|
124
112
|
}))
|
|
125
113
|
.views(self => {
|
|
@@ -222,6 +210,7 @@ export default function MultiVariantBaseModelF(configSchema) {
|
|
|
222
210
|
},
|
|
223
211
|
{
|
|
224
212
|
label: 'Cluster by genotype',
|
|
213
|
+
icon: CategoryIcon,
|
|
225
214
|
onClick: () => {
|
|
226
215
|
getSession(self).queueDialog(handleClose => [
|
|
227
216
|
ClusterDialog,
|
|
@@ -256,13 +245,16 @@ export default function MultiVariantBaseModelF(configSchema) {
|
|
|
256
245
|
var _a;
|
|
257
246
|
return self.rowHeight * (((_a = self.sources) === null || _a === void 0 ? void 0 : _a.length) || 1);
|
|
258
247
|
},
|
|
248
|
+
get featuresReady() {
|
|
249
|
+
return !!self.featuresVolatile;
|
|
250
|
+
},
|
|
259
251
|
}))
|
|
260
252
|
.views(self => ({
|
|
261
253
|
renderProps() {
|
|
262
254
|
const superProps = self.adapterProps();
|
|
263
255
|
return {
|
|
264
256
|
...superProps,
|
|
265
|
-
notReady: superProps.notReady || !self.sources || !self.
|
|
257
|
+
notReady: superProps.notReady || !self.sources || !self.featuresReady,
|
|
266
258
|
height: self.height,
|
|
267
259
|
totalHeight: self.totalHeight,
|
|
268
260
|
renderingMode: self.renderingMode,
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { Dialog } from '@jbrowse/core/ui';
|
|
4
|
+
import { FormControlLabel, Radio, RadioGroup, Typography } from '@mui/material';
|
|
5
|
+
import { observer } from 'mobx-react';
|
|
6
|
+
import ClusterDialogAuto from './ClusterDialogAuto';
|
|
7
|
+
import ClusterDialogManual from './ClusterDialogManual';
|
|
8
|
+
function Header({ activeMode, setActiveMode, }) {
|
|
9
|
+
return (_jsxs("div", { children: [_jsx(Typography, { style: { marginBottom: 30 }, children: "This procedure will cluster the visible genotype data using hierarchical clustering" }), _jsx(RadioGroup, { children: Object.entries({
|
|
10
|
+
auto: (_jsx("div", { children: "Run in-app clustering (slow for large data, built in JS clustering)" })),
|
|
11
|
+
manual: (_jsx("div", { children: "Download R script to run clustering (faster for large data, uses hclust, may be more accurate)" })),
|
|
12
|
+
}).map(([key, val]) => (_jsx(FormControlLabel, { control: _jsx(Radio, { checked: activeMode === key, onChange: () => {
|
|
13
|
+
setActiveMode(key);
|
|
14
|
+
} }), label: val }, key))) })] }));
|
|
15
|
+
}
|
|
16
|
+
const ClusterDialog = observer(function ({ model, handleClose, }) {
|
|
17
|
+
const [activeMode, setActiveMode] = useState('auto');
|
|
18
|
+
return (_jsx(Dialog, { open: true, title: "Cluster by genotype", onClose: (_, reason) => {
|
|
19
|
+
if (reason !== 'backdropClick') {
|
|
20
|
+
handleClose();
|
|
21
|
+
}
|
|
22
|
+
}, children: activeMode === 'auto' ? (_jsx(ClusterDialogAuto, { model: model, handleClose: handleClose, children: _jsx(Header, { activeMode: activeMode, setActiveMode: setActiveMode }) })) : (_jsx(ClusterDialogManual, { model: model, handleClose: handleClose, children: _jsx(Header, { activeMode: activeMode, setActiveMode: setActiveMode }) })) }));
|
|
23
|
+
});
|
|
24
|
+
export default ClusterDialog;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ReducedModel } from './types';
|
|
2
|
+
declare const ClusterDialogAuto: ({ model, children, handleClose, }: {
|
|
3
|
+
model: ReducedModel;
|
|
4
|
+
children: React.ReactNode;
|
|
5
|
+
handleClose: () => void;
|
|
6
|
+
}) => import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export default ClusterDialogAuto;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { ErrorMessage } from '@jbrowse/core/ui';
|
|
4
|
+
import { getContainingView, getSession, isAbortException, } from '@jbrowse/core/util';
|
|
5
|
+
import { createStopToken, stopStopToken } from '@jbrowse/core/util/stopToken';
|
|
6
|
+
import { getRpcSessionId } from '@jbrowse/core/util/tracks';
|
|
7
|
+
import { Button, DialogActions, DialogContent } from '@mui/material';
|
|
8
|
+
import { observer } from 'mobx-react';
|
|
9
|
+
import { isAlive } from 'mobx-state-tree';
|
|
10
|
+
const ClusterDialogAuto = observer(function ({ model, children, handleClose, }) {
|
|
11
|
+
const [progress, setProgress] = useState('');
|
|
12
|
+
const [error, setError] = useState();
|
|
13
|
+
const [stopToken, setStopToken] = useState('');
|
|
14
|
+
return (_jsxs(_Fragment, { children: [_jsxs(DialogContent, { children: [children, _jsxs("div", { children: [progress ? (_jsxs("div", { style: { padding: 50 }, children: [_jsxs("span", { style: { width: 400 }, children: ["Progress: ", progress] }), _jsx(Button, { onClick: () => {
|
|
15
|
+
stopStopToken(stopToken);
|
|
16
|
+
}, children: "Stop" })] })) : null, error ? _jsx(ErrorMessage, { error: error }) : null] })] }), _jsxs(DialogActions, { children: [_jsx(Button, { variant: "contained", onClick: async () => {
|
|
17
|
+
try {
|
|
18
|
+
setError(undefined);
|
|
19
|
+
const view = getContainingView(model);
|
|
20
|
+
if (!view.initialized) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
const { rpcManager } = getSession(model);
|
|
24
|
+
const { sourcesWithoutLayout, minorAlleleFrequencyFilter, adapterConfig, } = model;
|
|
25
|
+
if (sourcesWithoutLayout) {
|
|
26
|
+
const sessionId = getRpcSessionId(model);
|
|
27
|
+
const stopToken = createStopToken();
|
|
28
|
+
setStopToken(stopToken);
|
|
29
|
+
const ret = (await rpcManager.call(sessionId, 'MultiVariantClusterGenotypeMatrix', {
|
|
30
|
+
regions: view.dynamicBlocks.contentBlocks,
|
|
31
|
+
sources: sourcesWithoutLayout,
|
|
32
|
+
minorAlleleFrequencyFilter,
|
|
33
|
+
sessionId,
|
|
34
|
+
adapterConfig,
|
|
35
|
+
stopToken,
|
|
36
|
+
statusCallback: (arg) => {
|
|
37
|
+
setProgress(arg);
|
|
38
|
+
},
|
|
39
|
+
}));
|
|
40
|
+
model.setLayout(ret.order.map(idx => {
|
|
41
|
+
const ret = sourcesWithoutLayout[idx];
|
|
42
|
+
if (!ret) {
|
|
43
|
+
throw new Error(`out of bounds at ${idx}`);
|
|
44
|
+
}
|
|
45
|
+
return ret;
|
|
46
|
+
}));
|
|
47
|
+
}
|
|
48
|
+
handleClose();
|
|
49
|
+
}
|
|
50
|
+
catch (e) {
|
|
51
|
+
if (!isAbortException(e) && isAlive(model)) {
|
|
52
|
+
console.error(e);
|
|
53
|
+
setError(e);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
finally {
|
|
57
|
+
setProgress('');
|
|
58
|
+
setStopToken('');
|
|
59
|
+
}
|
|
60
|
+
}, children: "Run clustering" }), _jsx(Button, { variant: "contained", color: "secondary", onClick: () => {
|
|
61
|
+
handleClose();
|
|
62
|
+
if (stopToken) {
|
|
63
|
+
stopStopToken(stopToken);
|
|
64
|
+
}
|
|
65
|
+
}, children: "Cancel" })] })] }));
|
|
66
|
+
});
|
|
67
|
+
export default ClusterDialogAuto;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ReducedModel } from './types';
|
|
2
|
+
declare const ClusterDialogManuals: ({ model, handleClose, children, }: {
|
|
3
|
+
model: ReducedModel;
|
|
4
|
+
handleClose: () => void;
|
|
5
|
+
children: React.ReactNode;
|
|
6
|
+
}) => import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export default ClusterDialogManuals;
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useState } from 'react';
|
|
3
|
+
import { ErrorMessage, LoadingEllipses } from '@jbrowse/core/ui';
|
|
4
|
+
import { getContainingView, getSession, isAbortException, useLocalStorage, } from '@jbrowse/core/util';
|
|
5
|
+
import { getRpcSessionId } from '@jbrowse/core/util/tracks';
|
|
6
|
+
import { Button, DialogActions, DialogContent, FormControlLabel, Paper, Radio, RadioGroup, TextField, Typography, } from '@mui/material';
|
|
7
|
+
import copy from 'copy-to-clipboard';
|
|
8
|
+
import { saveAs } from 'file-saver';
|
|
9
|
+
import { observer } from 'mobx-react';
|
|
10
|
+
import { isAlive } from 'mobx-state-tree';
|
|
11
|
+
import { makeStyles } from 'tss-react/mui';
|
|
12
|
+
const useStyles = makeStyles()(theme => ({
|
|
13
|
+
textAreaFont: {
|
|
14
|
+
fontFamily: 'Courier New',
|
|
15
|
+
},
|
|
16
|
+
mgap: {
|
|
17
|
+
display: 'flex',
|
|
18
|
+
flexDirection: 'column',
|
|
19
|
+
gap: theme.spacing(4),
|
|
20
|
+
},
|
|
21
|
+
}));
|
|
22
|
+
const ClusterDialogManuals = observer(function ({ model, handleClose, children, }) {
|
|
23
|
+
const { classes } = useStyles();
|
|
24
|
+
const [paste, setPaste] = useState('');
|
|
25
|
+
const [ret, setRet] = useState();
|
|
26
|
+
const [error, setError] = useState();
|
|
27
|
+
const [loading, setLoading] = useState(false);
|
|
28
|
+
const [showAdvanced, setShowAdvanced] = useState(false);
|
|
29
|
+
const [clusterMethod, setClusterMethod] = useLocalStorage('cluster-clusterMethod', 'single');
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
;
|
|
32
|
+
(async () => {
|
|
33
|
+
try {
|
|
34
|
+
setError(undefined);
|
|
35
|
+
setRet(undefined);
|
|
36
|
+
setLoading(true);
|
|
37
|
+
const view = getContainingView(model);
|
|
38
|
+
if (!view.initialized) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const { rpcManager } = getSession(model);
|
|
42
|
+
const { sourcesWithoutLayout, minorAlleleFrequencyFilter, adapterConfig, } = model;
|
|
43
|
+
const sessionId = getRpcSessionId(model);
|
|
44
|
+
const ret = (await rpcManager.call(sessionId, 'MultiVariantGetGenotypeMatrix', {
|
|
45
|
+
regions: view.dynamicBlocks.contentBlocks,
|
|
46
|
+
sources: sourcesWithoutLayout,
|
|
47
|
+
minorAlleleFrequencyFilter,
|
|
48
|
+
sessionId,
|
|
49
|
+
adapterConfig,
|
|
50
|
+
}));
|
|
51
|
+
setRet(ret);
|
|
52
|
+
}
|
|
53
|
+
catch (e) {
|
|
54
|
+
if (!isAbortException(e) && isAlive(model)) {
|
|
55
|
+
console.error(e);
|
|
56
|
+
setError(e);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
finally {
|
|
60
|
+
setLoading(false);
|
|
61
|
+
}
|
|
62
|
+
})();
|
|
63
|
+
}, [model]);
|
|
64
|
+
const results = ret
|
|
65
|
+
? `inputMatrix<-matrix(c(${Object.values(ret)
|
|
66
|
+
.map(val => val.join(','))
|
|
67
|
+
.join(',\n')}
|
|
68
|
+
),nrow=${Object.values(ret).length},byrow=TRUE)
|
|
69
|
+
rownames(inputMatrix)<-c(${Object.keys(ret)
|
|
70
|
+
.map(key => `'${key}'`)
|
|
71
|
+
.join(',')})
|
|
72
|
+
resultClusters<-hclust(dist(inputMatrix), method='${clusterMethod}')
|
|
73
|
+
cat(resultClusters$order,sep='\\n')`
|
|
74
|
+
: undefined;
|
|
75
|
+
const resultsTsv = ret
|
|
76
|
+
? Object.entries(ret)
|
|
77
|
+
.map(([key, val]) => [key, ...val].join('\t'))
|
|
78
|
+
.join('\n')
|
|
79
|
+
: undefined;
|
|
80
|
+
return (_jsxs(_Fragment, { children: [_jsxs(DialogContent, { children: [children, _jsxs(Paper, { style: { padding: 16 }, children: [_jsxs("div", { style: {
|
|
81
|
+
display: 'flex',
|
|
82
|
+
gap: '8px',
|
|
83
|
+
flexWrap: 'wrap',
|
|
84
|
+
marginBottom: '16px',
|
|
85
|
+
}, children: [_jsx(Button, { variant: "contained", onClick: () => {
|
|
86
|
+
saveAs(new Blob([results || ''], {
|
|
87
|
+
type: 'text/plain;charset=utf-8',
|
|
88
|
+
}), 'cluster.R');
|
|
89
|
+
}, children: "Download Rscript" }), ' ', "or", ' ', _jsx(Button, { variant: "contained", onClick: () => {
|
|
90
|
+
copy(results || '');
|
|
91
|
+
}, children: "Copy Rscript to clipboard" }), ' ', "or", ' ', _jsx(Button, { variant: "contained", onClick: () => {
|
|
92
|
+
saveAs(new Blob([resultsTsv || ''], {
|
|
93
|
+
type: 'text/plain;charset=utf-8',
|
|
94
|
+
}), 'genotypes.tsv');
|
|
95
|
+
}, children: "Download TSV" }), _jsxs("div", { children: [_jsx(Button, { variant: "contained", onClick: () => {
|
|
96
|
+
setShowAdvanced(!showAdvanced);
|
|
97
|
+
}, children: showAdvanced
|
|
98
|
+
? 'Hide advanced options'
|
|
99
|
+
: 'Show advanced options' }), showAdvanced ? (_jsxs("div", { children: [_jsx(Typography, { variant: "h6", children: "Advanced options" }), _jsx(RadioGroup, { children: Object.entries({
|
|
100
|
+
single: 'Single',
|
|
101
|
+
complete: 'Complete',
|
|
102
|
+
}).map(([key, val]) => (_jsx(FormControlLabel, { control: _jsx(Radio, { checked: clusterMethod === key, onChange: () => {
|
|
103
|
+
setClusterMethod(key);
|
|
104
|
+
} }), label: val }, key))) })] })) : null] }), results ? (_jsx("div", {})) : loading ? (_jsx(LoadingEllipses, { variant: "h6", title: "Generating genotype matrix" })) : error ? (_jsx(ErrorMessage, { error: error })) : null] }), _jsxs("div", { children: [_jsx(Typography, { variant: "subtitle2", gutterBottom: true, style: { marginTop: '16px' }, children: "Clustering Results:" }), _jsx(TextField, { multiline: true, fullWidth: true, variant: "outlined", placeholder: "Paste results from Rscript here (sequence of numbers, one per line, specifying the new ordering)", rows: 10, value: paste, onChange: event => {
|
|
105
|
+
setPaste(event.target.value);
|
|
106
|
+
}, slotProps: {
|
|
107
|
+
input: {
|
|
108
|
+
classes: {
|
|
109
|
+
input: classes.textAreaFont,
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
} })] })] })] }), _jsxs(DialogActions, { children: [_jsx(Button, { variant: "contained", onClick: () => {
|
|
113
|
+
const { sourcesWithoutLayout } = model;
|
|
114
|
+
if (sourcesWithoutLayout) {
|
|
115
|
+
try {
|
|
116
|
+
model.setLayout(paste
|
|
117
|
+
.split('\n')
|
|
118
|
+
.map(t => t.trim())
|
|
119
|
+
.filter(f => !!f)
|
|
120
|
+
.map(r => +r)
|
|
121
|
+
.map(idx => {
|
|
122
|
+
const ret = sourcesWithoutLayout[idx - 1];
|
|
123
|
+
if (!ret) {
|
|
124
|
+
throw new Error(`out of bounds at ${idx}`);
|
|
125
|
+
}
|
|
126
|
+
return ret;
|
|
127
|
+
}));
|
|
128
|
+
}
|
|
129
|
+
catch (e) {
|
|
130
|
+
console.error(e);
|
|
131
|
+
getSession(model).notifyError(`${e}`, e);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
handleClose();
|
|
135
|
+
}, children: "Apply clustering" }), _jsx(Button, { variant: "contained", color: "secondary", onClick: () => {
|
|
136
|
+
handleClose();
|
|
137
|
+
}, children: "Cancel" })] })] }));
|
|
138
|
+
});
|
|
139
|
+
export default ClusterDialogManuals;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Source } from '../../types';
|
|
2
|
+
import type { AnyConfigurationModel } from '@jbrowse/core/configuration';
|
|
3
|
+
export interface ReducedModel {
|
|
4
|
+
sourcesWithoutLayout?: Source[];
|
|
5
|
+
minorAlleleFrequencyFilter?: number;
|
|
6
|
+
adapterConfig: AnyConfigurationModel;
|
|
7
|
+
setLayout: (arg: Source[]) => void;
|
|
8
|
+
clearLayout: () => void;
|
|
9
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -14,49 +14,56 @@ const useStyles = makeStyles()({
|
|
|
14
14
|
});
|
|
15
15
|
export default function SourcesDataGrid({ rows, onChange, setSelected, }) {
|
|
16
16
|
const { classes } = useStyles();
|
|
17
|
-
const { id: _id, name: _name, label: _label, color: _color, baseUri: _baseUri, HP: _HP, ...rest } = rows[0];
|
|
18
17
|
const [currSort, setCurrSort] = useState({
|
|
19
18
|
idx: 0,
|
|
20
19
|
field: null,
|
|
21
20
|
});
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
elt
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
21
|
+
if (rows.length) {
|
|
22
|
+
const { id: _id, name: _name, label: _label, color: _color, baseUri: _baseUri, HP: _HP, ...rest } = rows[0];
|
|
23
|
+
return (_jsx("div", { style: { height: 400, width: '100%' }, children: _jsx(DataGrid, { checkboxSelection: true, disableRowSelectionOnClick: true, onRowSelectionModelChange: arg => {
|
|
24
|
+
setSelected(arg);
|
|
25
|
+
}, rows: rows, rowHeight: 25, columnHeaderHeight: 33, columns: [
|
|
26
|
+
{
|
|
27
|
+
field: 'color',
|
|
28
|
+
headerName: 'Color',
|
|
29
|
+
renderCell: params => {
|
|
30
|
+
const { value, id } = params;
|
|
31
|
+
return (_jsx(ColorPicker, { color: value || 'blue', onChange: c => {
|
|
32
|
+
const elt = rows.find(f => f.name === id);
|
|
33
|
+
if (elt) {
|
|
34
|
+
elt.color = c;
|
|
35
|
+
}
|
|
36
|
+
onChange([...rows]);
|
|
37
|
+
} }));
|
|
38
|
+
},
|
|
37
39
|
},
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
40
|
+
{
|
|
41
|
+
field: 'label',
|
|
42
|
+
headerName: 'Name',
|
|
43
|
+
width: measureGridWidth(rows.map(r => r.label)),
|
|
44
|
+
},
|
|
45
|
+
...Object.keys(rest).map(val => ({
|
|
46
|
+
field: val,
|
|
47
|
+
renderCell: ({ value }) => (_jsx("div", { className: classes.cell, children: _jsx(SanitizedHTML, { html: getStr(value) }) })),
|
|
48
|
+
width: measureGridWidth(rows.map(r => `${r[val]}`)),
|
|
49
|
+
})),
|
|
50
|
+
], sortModel: [], onSortModelChange: args => {
|
|
51
|
+
const sort = args[0];
|
|
52
|
+
const idx = (currSort.idx + 1) % 2;
|
|
53
|
+
const field = sort.field || currSort.field;
|
|
54
|
+
setCurrSort({ idx, field });
|
|
55
|
+
onChange(field
|
|
56
|
+
? [...rows].sort((a, b) => {
|
|
57
|
+
const aa = getStr(a[field]);
|
|
58
|
+
const bb = getStr(b[field]);
|
|
59
|
+
return idx === 1
|
|
60
|
+
? aa.localeCompare(bb)
|
|
61
|
+
: bb.localeCompare(aa);
|
|
62
|
+
})
|
|
63
|
+
: rows);
|
|
64
|
+
} }) }));
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
return _jsx("div", { children: "No rows, check sample metadata configuration" });
|
|
68
|
+
}
|
|
62
69
|
}
|
|
@@ -22,12 +22,12 @@ export default function SourcesGridHeader({ selected, onChange, rows, showTips,
|
|
|
22
22
|
onChange(moveDown([...rows], selected, rows.length));
|
|
23
23
|
}, disabled: !selected.length, children: [_jsx(KeyboardDoubleArrowDownIcon, {}), showTips ? 'Move selected items to bottom' : null] }), _jsx(ColorPopover, { anchorEl: anchorEl, color: widgetColor, onChange: c => {
|
|
24
24
|
setWidgetColor(c);
|
|
25
|
-
|
|
25
|
+
for (const id of selected) {
|
|
26
26
|
const elt = rows.find(f => f.name === id);
|
|
27
27
|
if (elt) {
|
|
28
28
|
elt.color = c;
|
|
29
29
|
}
|
|
30
|
-
}
|
|
30
|
+
}
|
|
31
31
|
onChange([...rows]);
|
|
32
32
|
}, onClose: () => {
|
|
33
33
|
setAnchorEl(null);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { SampleInfo, Source } from './types';
|
|
2
|
+
export declare function getSources({ sources, layout, renderingMode, sampleInfo, }: {
|
|
3
|
+
sources: Source[];
|
|
4
|
+
layout?: Source[];
|
|
5
|
+
renderingMode: string;
|
|
6
|
+
sampleInfo?: Record<string, SampleInfo>;
|
|
7
|
+
}): {
|
|
8
|
+
label: string;
|
|
9
|
+
id: string;
|
|
10
|
+
baseUri?: string;
|
|
11
|
+
name: string;
|
|
12
|
+
color?: string;
|
|
13
|
+
group?: string;
|
|
14
|
+
HP?: number;
|
|
15
|
+
}[];
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export function getSources({ sources, layout = sources, renderingMode, sampleInfo, }) {
|
|
2
|
+
const rows = [];
|
|
3
|
+
const sourceMap = Object.fromEntries(sources.map(s => [s.name, s]));
|
|
4
|
+
for (const row of layout) {
|
|
5
|
+
if (renderingMode === 'phased') {
|
|
6
|
+
const info = sampleInfo === null || sampleInfo === void 0 ? void 0 : sampleInfo[row.name];
|
|
7
|
+
if (info === null || info === void 0 ? void 0 : info.isPhased) {
|
|
8
|
+
const ploidy = info.maxPloidy;
|
|
9
|
+
for (let i = 0; i < ploidy; i++) {
|
|
10
|
+
const id = `${row.name} HP${i}`;
|
|
11
|
+
rows.push({
|
|
12
|
+
...sourceMap[row.name],
|
|
13
|
+
...row,
|
|
14
|
+
label: id,
|
|
15
|
+
HP: i,
|
|
16
|
+
id: id,
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
rows.push({
|
|
23
|
+
...sourceMap[row.name],
|
|
24
|
+
...row,
|
|
25
|
+
label: row.name,
|
|
26
|
+
id: row.name,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return rows;
|
|
31
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jbrowse/plugin-variants",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.2.0",
|
|
4
4
|
"description": "JBrowse 2 variant adapters, tracks, etc.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jbrowse",
|
|
@@ -40,10 +40,10 @@
|
|
|
40
40
|
"@gmod/bgzf-filehandle": "^2.0.1",
|
|
41
41
|
"@gmod/tabix": "^2.0.0",
|
|
42
42
|
"@gmod/vcf": "^6.0.8",
|
|
43
|
-
"@jbrowse/core": "^3.
|
|
44
|
-
"@jbrowse/plugin-circular-view": "^3.
|
|
45
|
-
"@jbrowse/plugin-linear-genome-view": "^3.
|
|
46
|
-
"@jbrowse/sv-core": "^3.
|
|
43
|
+
"@jbrowse/core": "^3.2.0",
|
|
44
|
+
"@jbrowse/plugin-circular-view": "^3.2.0",
|
|
45
|
+
"@jbrowse/plugin-linear-genome-view": "^3.2.0",
|
|
46
|
+
"@jbrowse/sv-core": "^3.2.0",
|
|
47
47
|
"@mui/icons-material": "^6.0.0",
|
|
48
48
|
"@mui/material": "^6.0.0",
|
|
49
49
|
"@mui/x-data-grid": "^7.0.0",
|
|
@@ -62,5 +62,5 @@
|
|
|
62
62
|
"distModule": "esm/index.js",
|
|
63
63
|
"srcModule": "src/index.ts",
|
|
64
64
|
"module": "esm/index.js",
|
|
65
|
-
"gitHead": "
|
|
65
|
+
"gitHead": "c750e3f56706a490c19ba75abd807fec5e38aebf"
|
|
66
66
|
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import type { Source } from '../types';
|
|
2
|
-
import type { AnyConfigurationModel } from '@jbrowse/core/configuration';
|
|
3
|
-
export default function ClusterDialog({ model, handleClose, }: {
|
|
4
|
-
model: {
|
|
5
|
-
sources?: Source[];
|
|
6
|
-
minorAlleleFrequencyFilter?: number;
|
|
7
|
-
adapterConfig: AnyConfigurationModel;
|
|
8
|
-
setLayout: (arg: Source[]) => void;
|
|
9
|
-
};
|
|
10
|
-
handleClose: () => void;
|
|
11
|
-
}): import("react/jsx-runtime").JSX.Element;
|