@jbrowse/plugin-variants 3.0.5 → 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/components/Crosshair.js +1 -1
- package/dist/MultiLinearVariantDisplay/model.d.ts +19 -0
- package/dist/MultiLinearVariantMatrixDisplay/components/Crosshair.js +1 -1
- package/dist/MultiLinearVariantMatrixDisplay/model.d.ts +20 -0
- package/dist/MultiLinearVariantMatrixDisplay/model.js +4 -1
- package/dist/MultiLinearVariantMatrixRenderer/makeImageData.d.ts +1 -0
- 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 -34
- 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/VcfAdapter/configSchema.js +14 -1
- package/dist/VcfFeature/util.js +2 -2
- package/dist/VcfTabixAdapter/VcfTabixAdapter.js +11 -6
- package/dist/VcfTabixAdapter/configSchema.js +24 -2
- 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/dist/shared/minorAlleleFrequencyUtils.d.ts +3 -5
- package/dist/shared/minorAlleleFrequencyUtils.js +13 -8
- package/esm/MultiLinearVariantDisplay/components/Crosshair.js +1 -1
- package/esm/MultiLinearVariantDisplay/model.d.ts +19 -0
- package/esm/MultiLinearVariantMatrixDisplay/components/Crosshair.js +1 -1
- package/esm/MultiLinearVariantMatrixDisplay/model.d.ts +20 -0
- package/esm/MultiLinearVariantMatrixDisplay/model.js +4 -1
- package/esm/MultiLinearVariantMatrixRenderer/makeImageData.d.ts +1 -0
- 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 -34
- 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/VcfAdapter/configSchema.js +14 -1
- package/esm/VcfFeature/util.js +2 -2
- package/esm/VcfTabixAdapter/VcfTabixAdapter.js +11 -6
- package/esm/VcfTabixAdapter/configSchema.js +24 -2
- 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/esm/shared/minorAlleleFrequencyUtils.d.ts +3 -5
- package/esm/shared/minorAlleleFrequencyUtils.js +13 -8
- package/package.json +6 -6
- package/dist/shared/components/ClusterDialog.d.ts +0 -11
- package/dist/shared/components/ClusterDialog.js +0 -109
- package/esm/shared/components/ClusterDialog.d.ts +0 -11
- package/esm/shared/components/ClusterDialog.js +0 -103
|
@@ -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
|
+
}
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import type { Feature } from '@jbrowse/core/util';
|
|
2
2
|
export declare function findSecondLargestNumber(arr: Iterable<number>): number;
|
|
3
|
-
export declare function calculateAlleleCounts(feat: Feature):
|
|
4
|
-
alleleCounts: Map<any, any>;
|
|
5
|
-
mostFrequentAlt: any;
|
|
6
|
-
};
|
|
3
|
+
export declare function calculateAlleleCounts(feat: Feature): Map<any, any>;
|
|
7
4
|
export declare function calculateMinorAlleleFrequency(alleleCounts: Map<string, number>): number;
|
|
8
|
-
export declare function getFeaturesThatPassMinorAlleleFrequencyFilter(feats: Iterable<Feature>, minorAlleleFrequencyFilter: number): {
|
|
5
|
+
export declare function getFeaturesThatPassMinorAlleleFrequencyFilter(feats: Iterable<Feature>, minorAlleleFrequencyFilter: number, lengthCutoffFilter?: number): {
|
|
9
6
|
feature: Feature;
|
|
10
7
|
mostFrequentAlt: string;
|
|
8
|
+
alleleCounts: Map<string, number>;
|
|
11
9
|
}[];
|
|
@@ -22,6 +22,13 @@ export function calculateAlleleCounts(feat) {
|
|
|
22
22
|
alleleCounts.set(allele, (alleleCounts.get(allele) || 0) + 1);
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
|
+
return alleleCounts;
|
|
26
|
+
}
|
|
27
|
+
export function calculateMinorAlleleFrequency(alleleCounts) {
|
|
28
|
+
return (findSecondLargestNumber(alleleCounts.values()) /
|
|
29
|
+
(sum(alleleCounts.values()) || 1));
|
|
30
|
+
}
|
|
31
|
+
function getMostFrequentAlt(alleleCounts) {
|
|
25
32
|
let mostFrequentAlt;
|
|
26
33
|
let max = 0;
|
|
27
34
|
for (const [alt, altCount] of alleleCounts.entries()) {
|
|
@@ -32,22 +39,20 @@ export function calculateAlleleCounts(feat) {
|
|
|
32
39
|
}
|
|
33
40
|
}
|
|
34
41
|
}
|
|
35
|
-
return
|
|
36
|
-
}
|
|
37
|
-
export function calculateMinorAlleleFrequency(alleleCounts) {
|
|
38
|
-
return (findSecondLargestNumber(alleleCounts.values()) /
|
|
39
|
-
(sum(alleleCounts.values()) || 1));
|
|
42
|
+
return mostFrequentAlt;
|
|
40
43
|
}
|
|
41
|
-
export function getFeaturesThatPassMinorAlleleFrequencyFilter(feats, minorAlleleFrequencyFilter) {
|
|
44
|
+
export function getFeaturesThatPassMinorAlleleFrequencyFilter(feats, minorAlleleFrequencyFilter, lengthCutoffFilter = 10) {
|
|
42
45
|
const results = [];
|
|
43
46
|
for (const feature of feats) {
|
|
44
|
-
if (feature.get('end') - feature.get('start') <=
|
|
45
|
-
const
|
|
47
|
+
if (feature.get('end') - feature.get('start') <= lengthCutoffFilter) {
|
|
48
|
+
const alleleCounts = calculateAlleleCounts(feature);
|
|
46
49
|
if (calculateMinorAlleleFrequency(alleleCounts) >=
|
|
47
50
|
minorAlleleFrequencyFilter) {
|
|
51
|
+
const mostFrequentAlt = getMostFrequentAlt(alleleCounts);
|
|
48
52
|
results.push({
|
|
49
53
|
feature,
|
|
50
54
|
mostFrequentAlt,
|
|
55
|
+
alleleCounts,
|
|
51
56
|
});
|
|
52
57
|
}
|
|
53
58
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jbrowse/plugin-variants",
|
|
3
|
-
"version": "3.0
|
|
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.0
|
|
44
|
-
"@jbrowse/plugin-circular-view": "^3.0
|
|
45
|
-
"@jbrowse/plugin-linear-genome-view": "^3.0
|
|
46
|
-
"@jbrowse/sv-core": "^3.0
|
|
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;
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.default = ClusterDialog;
|
|
7
|
-
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
8
|
-
const react_1 = require("react");
|
|
9
|
-
const ui_1 = require("@jbrowse/core/ui");
|
|
10
|
-
const util_1 = require("@jbrowse/core/util");
|
|
11
|
-
const tracks_1 = require("@jbrowse/core/util/tracks");
|
|
12
|
-
const material_1 = require("@mui/material");
|
|
13
|
-
const copy_to_clipboard_1 = __importDefault(require("copy-to-clipboard"));
|
|
14
|
-
const file_saver_1 = require("file-saver");
|
|
15
|
-
const mobx_state_tree_1 = require("mobx-state-tree");
|
|
16
|
-
const mui_1 = require("tss-react/mui");
|
|
17
|
-
const useStyles = (0, mui_1.makeStyles)()(theme => ({
|
|
18
|
-
textAreaFont: {
|
|
19
|
-
fontFamily: 'Courier New',
|
|
20
|
-
},
|
|
21
|
-
mgap: {
|
|
22
|
-
display: 'flex',
|
|
23
|
-
flexDirection: 'column',
|
|
24
|
-
gap: theme.spacing(4),
|
|
25
|
-
},
|
|
26
|
-
}));
|
|
27
|
-
function ClusterDialog({ model, handleClose, }) {
|
|
28
|
-
const { classes } = useStyles();
|
|
29
|
-
const [results, setResults] = (0, react_1.useState)();
|
|
30
|
-
const [error, setError] = (0, react_1.useState)();
|
|
31
|
-
const [paste, setPaste] = (0, react_1.useState)('');
|
|
32
|
-
(0, react_1.useEffect)(() => {
|
|
33
|
-
;
|
|
34
|
-
(async () => {
|
|
35
|
-
try {
|
|
36
|
-
setError(undefined);
|
|
37
|
-
const view = (0, util_1.getContainingView)(model);
|
|
38
|
-
if (!view.initialized) {
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
const { rpcManager } = (0, util_1.getSession)(model);
|
|
42
|
-
const { sources, minorAlleleFrequencyFilter, adapterConfig } = model;
|
|
43
|
-
const sessionId = (0, tracks_1.getRpcSessionId)(model);
|
|
44
|
-
const ret = (await rpcManager.call(sessionId, 'MultiVariantGetGenotypeMatrix', {
|
|
45
|
-
regions: view.dynamicBlocks.contentBlocks,
|
|
46
|
-
sources,
|
|
47
|
-
minorAlleleFrequencyFilter,
|
|
48
|
-
sessionId,
|
|
49
|
-
adapterConfig,
|
|
50
|
-
}));
|
|
51
|
-
const entries = Object.values(ret);
|
|
52
|
-
const keys = Object.keys(ret);
|
|
53
|
-
const text = `try(library(fastcluster), silent=TRUE)
|
|
54
|
-
inputMatrix<-matrix(c(${entries.map(val => val.genotypes.join(',')).join(',\n')}
|
|
55
|
-
),nrow=${entries.length},byrow=TRUE)
|
|
56
|
-
rownames(inputMatrix)<-c(${keys.map(key => `'${key}'`).join(',')})
|
|
57
|
-
resultClusters<-hclust(dist(inputMatrix), method='single')
|
|
58
|
-
cat(resultClusters$order,sep='\\n')`;
|
|
59
|
-
setResults(text);
|
|
60
|
-
}
|
|
61
|
-
catch (e) {
|
|
62
|
-
if (!(0, util_1.isAbortException)(e) && (0, mobx_state_tree_1.isAlive)(model)) {
|
|
63
|
-
console.error(e);
|
|
64
|
-
setError(e);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
})();
|
|
68
|
-
}, [model]);
|
|
69
|
-
return ((0, jsx_runtime_1.jsxs)(ui_1.Dialog, { open: true, title: "Cluster by genotype", onClose: handleClose, children: [(0, jsx_runtime_1.jsx)(material_1.DialogContent, { children: (0, jsx_runtime_1.jsxs)("div", { className: classes.mgap, children: [(0, jsx_runtime_1.jsx)(material_1.Typography, { children: "This page will produce an R script that will perform hierarchical clustering on the visible genotype data using `hclust`." }), (0, jsx_runtime_1.jsx)(material_1.Typography, { children: "You can then paste the results in this form to specify the row ordering." }), results ? ((0, jsx_runtime_1.jsx)("div", { children: (0, jsx_runtime_1.jsxs)("div", { children: ["Step 1:", ' ', (0, jsx_runtime_1.jsx)(material_1.Button, { variant: "contained", onClick: () => {
|
|
70
|
-
(0, file_saver_1.saveAs)(new Blob([results || ''], {
|
|
71
|
-
type: 'text/plain;charset=utf-8',
|
|
72
|
-
}), 'cluster.R');
|
|
73
|
-
}, children: "Download Rscript" }), ' ', "or", ' ', (0, jsx_runtime_1.jsx)(material_1.Button, { variant: "contained", onClick: () => {
|
|
74
|
-
(0, copy_to_clipboard_1.default)(results || '');
|
|
75
|
-
}, children: "Copy Rscript to clipboard" }), (0, jsx_runtime_1.jsx)("div", { children: (0, jsx_runtime_1.jsx)(material_1.TextField, { multiline: true, fullWidth: true, variant: "outlined", placeholder: "Step 2. Paste results from Rscript here (sequence of numbers, one per line, specifying the new ordering)", rows: 10, value: paste, onChange: event => {
|
|
76
|
-
setPaste(event.target.value);
|
|
77
|
-
}, slotProps: {
|
|
78
|
-
input: {
|
|
79
|
-
classes: {
|
|
80
|
-
input: classes.textAreaFont,
|
|
81
|
-
},
|
|
82
|
-
},
|
|
83
|
-
} }) })] }) })) : ((0, jsx_runtime_1.jsx)(ui_1.LoadingEllipses, { variant: "h6", title: "Generating genotype matrix" })), error ? (0, jsx_runtime_1.jsx)(ui_1.ErrorMessage, { error: error }) : null] }) }), (0, jsx_runtime_1.jsxs)(material_1.DialogActions, { children: [(0, jsx_runtime_1.jsx)(material_1.Button, { disabled: !results, variant: "contained", onClick: () => {
|
|
84
|
-
const { sources } = model;
|
|
85
|
-
if (sources) {
|
|
86
|
-
try {
|
|
87
|
-
model.setLayout(paste
|
|
88
|
-
.split('\n')
|
|
89
|
-
.map(t => t.trim())
|
|
90
|
-
.filter(f => !!f)
|
|
91
|
-
.map(r => +r)
|
|
92
|
-
.map(idx => {
|
|
93
|
-
const ret = sources[idx - 1];
|
|
94
|
-
if (!ret) {
|
|
95
|
-
throw new Error(`out of bounds at ${idx}`);
|
|
96
|
-
}
|
|
97
|
-
return ret;
|
|
98
|
-
}));
|
|
99
|
-
}
|
|
100
|
-
catch (e) {
|
|
101
|
-
console.error(e);
|
|
102
|
-
setError(e);
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
handleClose();
|
|
106
|
-
}, children: "Apply clustering" }), (0, jsx_runtime_1.jsx)(material_1.Button, { variant: "contained", color: "secondary", onClick: () => {
|
|
107
|
-
handleClose();
|
|
108
|
-
}, children: "Cancel" })] })] }));
|
|
109
|
-
}
|
|
@@ -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;
|
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useEffect, useState } from 'react';
|
|
3
|
-
import { Dialog, ErrorMessage, LoadingEllipses } from '@jbrowse/core/ui';
|
|
4
|
-
import { getContainingView, getSession, isAbortException, } from '@jbrowse/core/util';
|
|
5
|
-
import { getRpcSessionId } from '@jbrowse/core/util/tracks';
|
|
6
|
-
import { Button, DialogActions, DialogContent, TextField, Typography, } from '@mui/material';
|
|
7
|
-
import copy from 'copy-to-clipboard';
|
|
8
|
-
import { saveAs } from 'file-saver';
|
|
9
|
-
import { isAlive } from 'mobx-state-tree';
|
|
10
|
-
import { makeStyles } from 'tss-react/mui';
|
|
11
|
-
const useStyles = makeStyles()(theme => ({
|
|
12
|
-
textAreaFont: {
|
|
13
|
-
fontFamily: 'Courier New',
|
|
14
|
-
},
|
|
15
|
-
mgap: {
|
|
16
|
-
display: 'flex',
|
|
17
|
-
flexDirection: 'column',
|
|
18
|
-
gap: theme.spacing(4),
|
|
19
|
-
},
|
|
20
|
-
}));
|
|
21
|
-
export default function ClusterDialog({ model, handleClose, }) {
|
|
22
|
-
const { classes } = useStyles();
|
|
23
|
-
const [results, setResults] = useState();
|
|
24
|
-
const [error, setError] = useState();
|
|
25
|
-
const [paste, setPaste] = useState('');
|
|
26
|
-
useEffect(() => {
|
|
27
|
-
;
|
|
28
|
-
(async () => {
|
|
29
|
-
try {
|
|
30
|
-
setError(undefined);
|
|
31
|
-
const view = getContainingView(model);
|
|
32
|
-
if (!view.initialized) {
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
const { rpcManager } = getSession(model);
|
|
36
|
-
const { sources, minorAlleleFrequencyFilter, adapterConfig } = model;
|
|
37
|
-
const sessionId = getRpcSessionId(model);
|
|
38
|
-
const ret = (await rpcManager.call(sessionId, 'MultiVariantGetGenotypeMatrix', {
|
|
39
|
-
regions: view.dynamicBlocks.contentBlocks,
|
|
40
|
-
sources,
|
|
41
|
-
minorAlleleFrequencyFilter,
|
|
42
|
-
sessionId,
|
|
43
|
-
adapterConfig,
|
|
44
|
-
}));
|
|
45
|
-
const entries = Object.values(ret);
|
|
46
|
-
const keys = Object.keys(ret);
|
|
47
|
-
const text = `try(library(fastcluster), silent=TRUE)
|
|
48
|
-
inputMatrix<-matrix(c(${entries.map(val => val.genotypes.join(',')).join(',\n')}
|
|
49
|
-
),nrow=${entries.length},byrow=TRUE)
|
|
50
|
-
rownames(inputMatrix)<-c(${keys.map(key => `'${key}'`).join(',')})
|
|
51
|
-
resultClusters<-hclust(dist(inputMatrix), method='single')
|
|
52
|
-
cat(resultClusters$order,sep='\\n')`;
|
|
53
|
-
setResults(text);
|
|
54
|
-
}
|
|
55
|
-
catch (e) {
|
|
56
|
-
if (!isAbortException(e) && isAlive(model)) {
|
|
57
|
-
console.error(e);
|
|
58
|
-
setError(e);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
})();
|
|
62
|
-
}, [model]);
|
|
63
|
-
return (_jsxs(Dialog, { open: true, title: "Cluster by genotype", onClose: handleClose, children: [_jsx(DialogContent, { children: _jsxs("div", { className: classes.mgap, children: [_jsx(Typography, { children: "This page will produce an R script that will perform hierarchical clustering on the visible genotype data using `hclust`." }), _jsx(Typography, { children: "You can then paste the results in this form to specify the row ordering." }), results ? (_jsx("div", { children: _jsxs("div", { children: ["Step 1:", ' ', _jsx(Button, { variant: "contained", onClick: () => {
|
|
64
|
-
saveAs(new Blob([results || ''], {
|
|
65
|
-
type: 'text/plain;charset=utf-8',
|
|
66
|
-
}), 'cluster.R');
|
|
67
|
-
}, children: "Download Rscript" }), ' ', "or", ' ', _jsx(Button, { variant: "contained", onClick: () => {
|
|
68
|
-
copy(results || '');
|
|
69
|
-
}, children: "Copy Rscript to clipboard" }), _jsx("div", { children: _jsx(TextField, { multiline: true, fullWidth: true, variant: "outlined", placeholder: "Step 2. Paste results from Rscript here (sequence of numbers, one per line, specifying the new ordering)", rows: 10, value: paste, onChange: event => {
|
|
70
|
-
setPaste(event.target.value);
|
|
71
|
-
}, slotProps: {
|
|
72
|
-
input: {
|
|
73
|
-
classes: {
|
|
74
|
-
input: classes.textAreaFont,
|
|
75
|
-
},
|
|
76
|
-
},
|
|
77
|
-
} }) })] }) })) : (_jsx(LoadingEllipses, { variant: "h6", title: "Generating genotype matrix" })), error ? _jsx(ErrorMessage, { error: error }) : null] }) }), _jsxs(DialogActions, { children: [_jsx(Button, { disabled: !results, variant: "contained", onClick: () => {
|
|
78
|
-
const { sources } = model;
|
|
79
|
-
if (sources) {
|
|
80
|
-
try {
|
|
81
|
-
model.setLayout(paste
|
|
82
|
-
.split('\n')
|
|
83
|
-
.map(t => t.trim())
|
|
84
|
-
.filter(f => !!f)
|
|
85
|
-
.map(r => +r)
|
|
86
|
-
.map(idx => {
|
|
87
|
-
const ret = sources[idx - 1];
|
|
88
|
-
if (!ret) {
|
|
89
|
-
throw new Error(`out of bounds at ${idx}`);
|
|
90
|
-
}
|
|
91
|
-
return ret;
|
|
92
|
-
}));
|
|
93
|
-
}
|
|
94
|
-
catch (e) {
|
|
95
|
-
console.error(e);
|
|
96
|
-
setError(e);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
handleClose();
|
|
100
|
-
}, children: "Apply clustering" }), _jsx(Button, { variant: "contained", color: "secondary", onClick: () => {
|
|
101
|
-
handleClose();
|
|
102
|
-
}, children: "Cancel" })] })] }));
|
|
103
|
-
}
|