@jbrowse/plugin-variants 2.13.1 → 2.14.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/ChordVariantDisplay/models/stateModelFactory.d.ts +3 -3
- package/dist/ChordVariantDisplay/models/stateModelFactory.js +3 -1
- package/dist/LinearVariantDisplay/model.d.ts +1 -1
- package/dist/StructuralVariantChordRenderer/Chord.js +7 -5
- package/dist/StructuralVariantChordRenderer/ReactComponent.d.ts +2 -2
- package/dist/StructuralVariantChordRenderer/ReactComponent.js +3 -6
- package/dist/VariantFeatureWidget/AnnotGrid.js +3 -1
- package/dist/VariantFeatureWidget/BreakendOptionDialog.js +9 -3
- package/dist/VariantFeatureWidget/BreakendPanel.js +4 -2
- package/dist/VariantFeatureWidget/VariantAnnotationTable.js +1 -1
- package/dist/VariantFeatureWidget/VariantFeatureWidget.js +6 -6
- package/dist/VariantFeatureWidget/VariantSampleGrid.js +7 -3
- package/dist/VcfAdapter/VcfAdapter.d.ts +11 -7
- package/dist/VcfAdapter/VcfAdapter.js +69 -50
- package/dist/VcfFeature/index.d.ts +1 -1
- package/dist/VcfFeature/index.js +3 -6
- package/dist/VcfFeature/util.d.ts +1 -1
- package/dist/VcfFeature/util.js +15 -13
- package/dist/VcfTabixAdapter/VcfTabixAdapter.js +1 -1
- package/dist/extensionPoints.js +1 -1
- package/esm/ChordVariantDisplay/models/stateModelFactory.d.ts +3 -3
- package/esm/ChordVariantDisplay/models/stateModelFactory.js +3 -1
- package/esm/LinearVariantDisplay/model.d.ts +1 -1
- package/esm/StructuralVariantChordRenderer/Chord.js +7 -5
- package/esm/StructuralVariantChordRenderer/ReactComponent.d.ts +2 -2
- package/esm/StructuralVariantChordRenderer/ReactComponent.js +3 -6
- package/esm/VariantFeatureWidget/AnnotGrid.js +3 -1
- package/esm/VariantFeatureWidget/BreakendOptionDialog.js +9 -3
- package/esm/VariantFeatureWidget/BreakendPanel.js +4 -2
- package/esm/VariantFeatureWidget/VariantAnnotationTable.js +1 -1
- package/esm/VariantFeatureWidget/VariantFeatureWidget.js +6 -6
- package/esm/VariantFeatureWidget/VariantSampleGrid.js +7 -3
- package/esm/VcfAdapter/VcfAdapter.d.ts +11 -7
- package/esm/VcfAdapter/VcfAdapter.js +69 -50
- package/esm/VcfFeature/index.d.ts +1 -1
- package/esm/VcfFeature/index.js +3 -6
- package/esm/VcfFeature/util.d.ts +1 -1
- package/esm/VcfFeature/util.js +15 -13
- package/esm/VcfTabixAdapter/VcfTabixAdapter.js +1 -1
- package/esm/extensionPoints.js +1 -1
- package/package.json +3 -3
|
@@ -52,7 +52,7 @@ declare const stateModelFactory: (configSchema: AnyConfigurationSchemaType) => i
|
|
|
52
52
|
error: unknown;
|
|
53
53
|
message: string | undefined;
|
|
54
54
|
}, import("mobx-state-tree")._NotCustomized, import("mobx-state-tree")._NotCustomized>>;
|
|
55
|
-
onHorizontalScroll?:
|
|
55
|
+
onHorizontalScroll?: () => void;
|
|
56
56
|
blockState?: Record<string, any>;
|
|
57
57
|
}>;
|
|
58
58
|
readonly DisplayBlurb: import("react").FC<{
|
|
@@ -100,7 +100,7 @@ declare const stateModelFactory: (configSchema: AnyConfigurationSchemaType) => i
|
|
|
100
100
|
} & {
|
|
101
101
|
readonly blockDefinitions: import("@jbrowse/plugin-circular-view/src/CircularView/models/slices").Slice[];
|
|
102
102
|
renderProps(): any;
|
|
103
|
-
readonly rendererType: import("@jbrowse/core/pluggableElementTypes").RendererType;
|
|
103
|
+
readonly rendererType: import("@jbrowse/core/pluggableElementTypes").RendererType | undefined;
|
|
104
104
|
isCompatibleWithRenderer(renderer: import("@jbrowse/core/pluggableElementTypes").RendererType): renderer is import("@jbrowse/core/pluggableElementTypes").CircularChordRendererType;
|
|
105
105
|
readonly selectedFeatureId: string | undefined;
|
|
106
106
|
} & {
|
|
@@ -118,7 +118,7 @@ declare const stateModelFactory: (configSchema: AnyConfigurationSchemaType) => i
|
|
|
118
118
|
afterAttach(): void;
|
|
119
119
|
} & {
|
|
120
120
|
renderSvg(opts: import("@jbrowse/plugin-circular-view/src/CircularView/models/model").ExportSvgOptions & {
|
|
121
|
-
theme
|
|
121
|
+
theme?: import("@mui/material").ThemeOptions;
|
|
122
122
|
}): Promise<import("react").JSX.Element>;
|
|
123
123
|
} & {
|
|
124
124
|
/**
|
|
@@ -42,7 +42,9 @@ const stateModelFactory = (configSchema) => {
|
|
|
42
42
|
radius: view.radiusPx,
|
|
43
43
|
blockDefinitions: self.blockDefinitions,
|
|
44
44
|
config: self.configuration.renderer,
|
|
45
|
-
onChordClick: (arg) =>
|
|
45
|
+
onChordClick: (arg) => {
|
|
46
|
+
self.onChordClick(arg);
|
|
47
|
+
},
|
|
46
48
|
};
|
|
47
49
|
},
|
|
48
50
|
}));
|
|
@@ -139,7 +139,7 @@ export default function stateModelFactory(configSchema: AnyConfigurationSchemaTy
|
|
|
139
139
|
error: unknown;
|
|
140
140
|
message: string | undefined;
|
|
141
141
|
}, import("mobx-state-tree")._NotCustomized, import("mobx-state-tree")._NotCustomized>>;
|
|
142
|
-
onHorizontalScroll?:
|
|
142
|
+
onHorizontalScroll?: () => void;
|
|
143
143
|
blockState?: Record<string, any>;
|
|
144
144
|
}>;
|
|
145
145
|
readonly DisplayBlurb: import("react").FC<{
|
|
@@ -54,6 +54,7 @@ const Chord = (0, mobx_react_1.observer)(function Chord({ feature, blocksForRefs
|
|
|
54
54
|
let endBlock;
|
|
55
55
|
const alt = (_a = feature.get('ALT')) === null || _a === void 0 ? void 0 : _a[0];
|
|
56
56
|
const bnd = alt && (0, vcf_1.parseBreakend)(alt);
|
|
57
|
+
const startPos = feature.get('start');
|
|
57
58
|
if (bnd) {
|
|
58
59
|
// VCF BND
|
|
59
60
|
const matePosition = bnd.MatePosition.split(':');
|
|
@@ -64,7 +65,7 @@ const Chord = (0, mobx_react_1.observer)(function Chord({ feature, blocksForRefs
|
|
|
64
65
|
// VCF TRA
|
|
65
66
|
const chr2 = (_c = (_b = feature.get('INFO')) === null || _b === void 0 ? void 0 : _b.CHR2) === null || _c === void 0 ? void 0 : _c[0];
|
|
66
67
|
const end = (_e = (_d = feature.get('INFO')) === null || _d === void 0 ? void 0 : _d.END) === null || _e === void 0 ? void 0 : _e[0];
|
|
67
|
-
endPosition = parseInt(end, 10);
|
|
68
|
+
endPosition = Number.parseInt(end, 10);
|
|
68
69
|
endBlock = blocksForRefs[chr2];
|
|
69
70
|
}
|
|
70
71
|
else if (svType === 'mate') {
|
|
@@ -74,8 +75,11 @@ const Chord = (0, mobx_react_1.observer)(function Chord({ feature, blocksForRefs
|
|
|
74
75
|
endPosition = mate.start;
|
|
75
76
|
endBlock = blocksForRefs[chr2];
|
|
76
77
|
}
|
|
78
|
+
else {
|
|
79
|
+
console.warn('unknown sv type', svType);
|
|
80
|
+
endPosition = startPos + 1;
|
|
81
|
+
}
|
|
77
82
|
if (endBlock) {
|
|
78
|
-
const startPos = feature.get('start');
|
|
79
83
|
const startRadians = bpToRadians(startBlock, startPos);
|
|
80
84
|
const endRadians = bpToRadians(endBlock, endPosition);
|
|
81
85
|
const startXY = (0, util_1.polarToCartesian)(radius, startRadians);
|
|
@@ -88,9 +92,7 @@ const Chord = (0, mobx_react_1.observer)(function Chord({ feature, blocksForRefs
|
|
|
88
92
|
feature,
|
|
89
93
|
});
|
|
90
94
|
return (react_1.default.createElement("path", { "data-testid": `chord-${feature.id()}`, cursor: "crosshair", fill: "none", d: ['M', ...startXY, 'Q', ...controlXY, ...endXY].join(' '), ...(0, util_1.getStrokeProps)(hovered ? hoverStrokeColor : strokeColor), strokeWidth: hovered ? 3 : 1, onClick: evt => {
|
|
91
|
-
|
|
92
|
-
onClick(feature, startBlock.region, endBlock.region, evt);
|
|
93
|
-
}
|
|
95
|
+
onClick(feature, startBlock.region, endBlock.region, evt);
|
|
94
96
|
}, onMouseOver: () => {
|
|
95
97
|
if (!selected) {
|
|
96
98
|
setHovered(true);
|
|
@@ -2,11 +2,11 @@ import React from 'react';
|
|
|
2
2
|
import { Feature } from '@jbrowse/core/util';
|
|
3
3
|
import { AnyConfigurationModel } from '@jbrowse/core/configuration';
|
|
4
4
|
import { Block, AnyRegion } from './Chord';
|
|
5
|
-
declare const StructuralVariantChordsReactComponent: ({ features, config, displayModel, blockDefinitions, radius, bezierRadius,
|
|
5
|
+
declare const StructuralVariantChordsReactComponent: ({ features, config, displayModel, blockDefinitions, radius, bezierRadius, onChordClick, }: {
|
|
6
6
|
features: Map<string, Feature>;
|
|
7
7
|
radius: number;
|
|
8
8
|
config: AnyConfigurationModel;
|
|
9
|
-
displayModel
|
|
9
|
+
displayModel?: {
|
|
10
10
|
id: string;
|
|
11
11
|
selectedFeatureId: string;
|
|
12
12
|
};
|
|
@@ -30,7 +30,8 @@ const react_1 = __importStar(require("react"));
|
|
|
30
30
|
const mobx_react_1 = require("mobx-react");
|
|
31
31
|
// locals
|
|
32
32
|
const Chord_1 = __importDefault(require("./Chord"));
|
|
33
|
-
const StructuralVariantChordsReactComponent = (0, mobx_react_1.observer)(function ({ features, config, displayModel, blockDefinitions, radius, bezierRadius,
|
|
33
|
+
const StructuralVariantChordsReactComponent = (0, mobx_react_1.observer)(function ({ features, config, displayModel, blockDefinitions, radius, bezierRadius, onChordClick, }) {
|
|
34
|
+
const { id, selectedFeatureId } = displayModel || {};
|
|
34
35
|
// make a map of refName -> blockDefinition
|
|
35
36
|
const blocksForRefsMemo = (0, react_1.useMemo)(() => {
|
|
36
37
|
const blocksForRefs = {};
|
|
@@ -44,10 +45,6 @@ const StructuralVariantChordsReactComponent = (0, mobx_react_1.observer)(functio
|
|
|
44
45
|
}
|
|
45
46
|
return blocksForRefs;
|
|
46
47
|
}, [blockDefinitions]);
|
|
47
|
-
return (react_1.default.createElement("g", {
|
|
48
|
-
const id = feature.id();
|
|
49
|
-
const selected = String(selectedFeatureId) === String(id);
|
|
50
|
-
return (react_1.default.createElement(Chord_1.default, { key: id, feature: feature, config: config, radius: radius, bezierRadius: bezierRadius, blocksForRefs: blocksForRefsMemo, selected: selected, onClick: onChordClick }));
|
|
51
|
-
})));
|
|
48
|
+
return (react_1.default.createElement("g", { "data-testid": "structuralVariantChordRenderer" }, [...features.values()].map(feature => (react_1.default.createElement(Chord_1.default, { key: feature.id(), feature: feature, config: config, radius: radius, bezierRadius: bezierRadius, blocksForRefs: blocksForRefsMemo, selected: String(selectedFeatureId) === String(id), onClick: onChordClick })))));
|
|
52
49
|
});
|
|
53
50
|
exports.default = StructuralVariantChordsReactComponent;
|
|
@@ -32,6 +32,8 @@ function VariantAnnotPanel({ rows, columns, }) {
|
|
|
32
32
|
const [checked, setChecked] = (0, react_1.useState)(false);
|
|
33
33
|
const widths = columns.map(e => (0, util_1.measureGridWidth)(rows.map(r => r[e.field])));
|
|
34
34
|
return rows.length ? (react_1.default.createElement("div", null,
|
|
35
|
-
react_1.default.createElement(material_1.FormControlLabel, { control: react_1.default.createElement(material_1.Checkbox, { checked: checked, onChange: event =>
|
|
35
|
+
react_1.default.createElement(material_1.FormControlLabel, { control: react_1.default.createElement(material_1.Checkbox, { checked: checked, onChange: event => {
|
|
36
|
+
setChecked(event.target.checked);
|
|
37
|
+
} }), label: react_1.default.createElement(material_1.Typography, { variant: "body2" }, "Show options") }),
|
|
36
38
|
react_1.default.createElement(x_data_grid_1.DataGrid, { rowHeight: 25, rows: rows, columns: columns.map((c, i) => ({ ...c, width: widths[i] })), slots: { toolbar: checked ? x_data_grid_1.GridToolbar : null } }))) : null;
|
|
37
39
|
}
|
|
@@ -50,8 +50,12 @@ const BreakendOptionDialog = (0, mobx_react_1.observer)(function ({ model, handl
|
|
|
50
50
|
const [mirror, setMirror] = (0, react_1.useState)(true);
|
|
51
51
|
return (react_1.default.createElement(ui_1.Dialog, { open: true, onClose: handleClose, title: "Breakpoint split view options" },
|
|
52
52
|
react_1.default.createElement(material_1.DialogContent, null,
|
|
53
|
-
react_1.default.createElement(Checkbox2, { checked: copyTracks, onChange: event =>
|
|
54
|
-
|
|
53
|
+
react_1.default.createElement(Checkbox2, { checked: copyTracks, onChange: event => {
|
|
54
|
+
setCopyTracks(event.target.checked);
|
|
55
|
+
}, label: "Copy tracks into the new view" }),
|
|
56
|
+
react_1.default.createElement(Checkbox2, { checked: mirror, onChange: event => {
|
|
57
|
+
setMirror(event.target.checked);
|
|
58
|
+
}, label: "Mirror tracks vertically in vertically stacked view" })),
|
|
55
59
|
react_1.default.createElement(material_1.DialogActions, null,
|
|
56
60
|
react_1.default.createElement(material_1.Button, { onClick: () => {
|
|
57
61
|
const { view } = model;
|
|
@@ -84,6 +88,8 @@ const BreakendOptionDialog = (0, mobx_react_1.observer)(function ({ model, handl
|
|
|
84
88
|
}
|
|
85
89
|
handleClose();
|
|
86
90
|
}, variant: "contained", color: "primary", autoFocus: true }, "OK"),
|
|
87
|
-
react_1.default.createElement(material_1.Button, { onClick: () =>
|
|
91
|
+
react_1.default.createElement(material_1.Button, { onClick: () => {
|
|
92
|
+
handleClose();
|
|
93
|
+
}, color: "secondary", variant: "contained" }, "Cancel"))));
|
|
88
94
|
});
|
|
89
95
|
exports.default = BreakendOptionDialog;
|
|
@@ -34,7 +34,9 @@ function LocStringList({ locStrings, model, }) {
|
|
|
34
34
|
const session = (0, util_1.getSession)(model);
|
|
35
35
|
return (react_1.default.createElement("div", null,
|
|
36
36
|
react_1.default.createElement(material_1.Typography, null, "Link to linear view of breakend endpoints"),
|
|
37
|
-
react_1.default.createElement("ul", null, locStrings.map((locString, index) => (
|
|
37
|
+
react_1.default.createElement("ul", null, locStrings.map((locString, index) => (
|
|
38
|
+
/* biome-ignore lint/suspicious/noArrayIndexKey: */
|
|
39
|
+
react_1.default.createElement("li", { key: `${locString}-${index}` },
|
|
38
40
|
react_1.default.createElement(material_1.Link, { href: "#", onClick: event => {
|
|
39
41
|
var _a;
|
|
40
42
|
event.preventDefault();
|
|
@@ -58,7 +60,7 @@ function LaunchBreakpointSplitViewPanel({ locStrings, model, feature, viewType,
|
|
|
58
60
|
const simpleFeature = new util_1.SimpleFeature(feature);
|
|
59
61
|
return (react_1.default.createElement("div", null,
|
|
60
62
|
react_1.default.createElement(material_1.Typography, null, "Launch split views with breakend source and target"),
|
|
61
|
-
react_1.default.createElement("ul", null, locStrings.map(locString => (react_1.default.createElement("li", { key:
|
|
63
|
+
react_1.default.createElement("ul", null, locStrings.map(locString => (react_1.default.createElement("li", { key: JSON.stringify(locString) },
|
|
62
64
|
react_1.default.createElement(material_1.Link, { href: "#", onClick: event => {
|
|
63
65
|
event.preventDefault();
|
|
64
66
|
session.queueDialog(handleClose => [
|
|
@@ -12,5 +12,5 @@ function VariantAnnotationTable({ data, fields, title, }) {
|
|
|
12
12
|
react_1.default.createElement(AnnotGrid_1.default, { rows: data.map((elt, id) => ({
|
|
13
13
|
id,
|
|
14
14
|
...Object.fromEntries(elt.split('|').map((e, i) => [fields[i], e])),
|
|
15
|
-
}))
|
|
15
|
+
})), columns: fields.map(c => ({ field: c })) }))) : null;
|
|
16
16
|
}
|
|
@@ -14,17 +14,17 @@ const BreakendPanel_1 = __importDefault(require("./BreakendPanel"));
|
|
|
14
14
|
const VariantAnnotationTable_1 = __importDefault(require("./VariantAnnotationTable"));
|
|
15
15
|
const variantFieldDescriptions_1 = require("./variantFieldDescriptions");
|
|
16
16
|
function AnnPanel({ descriptions, feature, }) {
|
|
17
|
-
var _a, _b, _c, _d;
|
|
17
|
+
var _a, _b, _c, _d, _e;
|
|
18
18
|
const annDesc = (_b = (_a = descriptions === null || descriptions === void 0 ? void 0 : descriptions.INFO) === null || _a === void 0 ? void 0 : _a.ANN) === null || _b === void 0 ? void 0 : _b.Description;
|
|
19
|
-
const annFields = ((_c = annDesc === null || annDesc === void 0 ? void 0 : annDesc.match(/.*Functional annotations:'(.*)'$/)) === null || _c === void 0 ? void 0 : _c[1].split('|')) || [];
|
|
20
|
-
const ann = ((
|
|
19
|
+
const annFields = ((_d = (_c = annDesc === null || annDesc === void 0 ? void 0 : annDesc.match(/.*Functional annotations:'(.*)'$/)) === null || _c === void 0 ? void 0 : _c[1]) === null || _d === void 0 ? void 0 : _d.split('|')) || [];
|
|
20
|
+
const ann = ((_e = feature.INFO) === null || _e === void 0 ? void 0 : _e.ANN) || [];
|
|
21
21
|
return (react_1.default.createElement(VariantAnnotationTable_1.default, { fields: annFields, data: ann, title: "Variant ANN field" }));
|
|
22
22
|
}
|
|
23
23
|
function CsqPanel({ descriptions, feature, }) {
|
|
24
|
-
var _a, _b, _c, _d;
|
|
24
|
+
var _a, _b, _c, _d, _e;
|
|
25
25
|
const csqDescription = (_b = (_a = descriptions === null || descriptions === void 0 ? void 0 : descriptions.INFO) === null || _a === void 0 ? void 0 : _a.CSQ) === null || _b === void 0 ? void 0 : _b.Description;
|
|
26
|
-
const csqFields = ((_c = csqDescription === null || csqDescription === void 0 ? void 0 : csqDescription.match(/.*Format: (.*)/)) === null || _c === void 0 ? void 0 : _c[1].split('|')) || [];
|
|
27
|
-
const csq = ((
|
|
26
|
+
const csqFields = ((_d = (_c = csqDescription === null || csqDescription === void 0 ? void 0 : csqDescription.match(/.*Format: (.*)/)) === null || _c === void 0 ? void 0 : _c[1]) === null || _d === void 0 ? void 0 : _d.split('|')) || [];
|
|
27
|
+
const csq = ((_e = feature.INFO) === null || _e === void 0 ? void 0 : _e.CSQ) || [];
|
|
28
28
|
return (react_1.default.createElement(VariantAnnotationTable_1.default, { fields: csqFields, data: csq, title: "Variant CSQ field" }));
|
|
29
29
|
}
|
|
30
30
|
const VariantFeatureWidget = (0, mobx_react_1.observer)(function (props) {
|
|
@@ -32,7 +32,9 @@ const util_1 = require("@jbrowse/core/util");
|
|
|
32
32
|
function SampleFilters({ columns, filter, setFilter, }) {
|
|
33
33
|
return (react_1.default.createElement(react_1.default.Fragment, null,
|
|
34
34
|
react_1.default.createElement(material_1.Typography, null, "These filters can use a plain text search or regex style query, e.g. in the genotype field, entering 1 will query for all genotypes that include the first alternate allele e.g. 0|1 or 1|1, entering [1-9]\\d* will find any non-zero allele e.g. 0|2 or 2/33"),
|
|
35
|
-
columns.map(({ field }) => (react_1.default.createElement(material_1.TextField, { key: `filter-${field}`, placeholder: `Filter ${field}`, value: filter[field] || '', onChange: event =>
|
|
35
|
+
columns.map(({ field }) => (react_1.default.createElement(material_1.TextField, { key: `filter-${field}`, placeholder: `Filter ${field}`, value: filter[field] || '', onChange: event => {
|
|
36
|
+
setFilter({ ...filter, [field]: event.target.value });
|
|
37
|
+
} })))));
|
|
36
38
|
}
|
|
37
39
|
function VariantSamples(props) {
|
|
38
40
|
var _a;
|
|
@@ -59,7 +61,7 @@ function VariantSamples(props) {
|
|
|
59
61
|
? filters.every(key => {
|
|
60
62
|
const currFilter = filter[key];
|
|
61
63
|
return currFilter
|
|
62
|
-
?
|
|
64
|
+
? new RegExp(currFilter, 'i').exec(row[key])
|
|
63
65
|
: true;
|
|
64
66
|
})
|
|
65
67
|
: true);
|
|
@@ -82,7 +84,9 @@ function VariantSamples(props) {
|
|
|
82
84
|
// https://github.com/mui-org/material-ui-x/issues/1197
|
|
83
85
|
return !preFilteredRows.length ? null : (react_1.default.createElement(BaseFeatureDetail_1.BaseCard, { ...props, title: "Samples" },
|
|
84
86
|
error ? react_1.default.createElement(material_1.Typography, { color: "error" }, `${error}`) : null,
|
|
85
|
-
react_1.default.createElement(material_1.FormControlLabel, { control: react_1.default.createElement(material_1.Checkbox, { checked: checked, onChange: event =>
|
|
87
|
+
react_1.default.createElement(material_1.FormControlLabel, { control: react_1.default.createElement(material_1.Checkbox, { checked: checked, onChange: event => {
|
|
88
|
+
setChecked(event.target.checked);
|
|
89
|
+
} }), label: react_1.default.createElement(material_1.Typography, { variant: "body2" }, "Show options") }),
|
|
86
90
|
checked ? (react_1.default.createElement(SampleFilters, { setFilter: setFilter, columns: columns, filter: filter })) : null,
|
|
87
91
|
react_1.default.createElement(x_data_grid_1.DataGrid, { autoHeight: true, rows: rows, hideFooter: rows.length < 100, columns: columns, disableRowSelectionOnClick: true, rowHeight: 25, columnHeaderHeight: 35, disableColumnMenu: true, slots: { toolbar: checked ? x_data_grid_1.GridToolbar : null }, slotProps: {
|
|
88
92
|
toolbar: {
|
|
@@ -1,24 +1,28 @@
|
|
|
1
1
|
import { BaseFeatureDataAdapter, BaseOptions } from '@jbrowse/core/data_adapters/BaseAdapter';
|
|
2
2
|
import { Region, Feature } from '@jbrowse/core/util';
|
|
3
3
|
import IntervalTree from '@flatten-js/interval-tree';
|
|
4
|
-
|
|
4
|
+
type StatusCallback = (arg: string) => void;
|
|
5
5
|
export default class VcfAdapter extends BaseFeatureDataAdapter {
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
calculatedIntervalTreeMap: Record<string, IntervalTree>;
|
|
7
|
+
vcfFeatures?: Promise<{
|
|
8
8
|
header: string;
|
|
9
|
-
|
|
9
|
+
intervalTreeMap: Record<string, (sc?: StatusCallback) => IntervalTree>;
|
|
10
10
|
}>;
|
|
11
|
+
static capabilities: string[];
|
|
11
12
|
getHeader(): Promise<string>;
|
|
12
13
|
getMetadata(): Promise<any>;
|
|
13
|
-
setupP(): Promise<{
|
|
14
|
+
setupP(opts?: BaseOptions): Promise<{
|
|
14
15
|
header: string;
|
|
15
|
-
|
|
16
|
+
intervalTreeMap: {
|
|
17
|
+
[k: string]: (sc?: (arg: string) => void) => IntervalTree<any>;
|
|
18
|
+
};
|
|
16
19
|
}>;
|
|
17
20
|
setup(): Promise<{
|
|
18
21
|
header: string;
|
|
19
|
-
|
|
22
|
+
intervalTreeMap: Record<string, (sc?: StatusCallback) => IntervalTree>;
|
|
20
23
|
}>;
|
|
21
24
|
getRefNames(_?: BaseOptions): Promise<string[]>;
|
|
22
25
|
getFeatures(region: Region, opts?: BaseOptions): import("rxjs").Observable<Feature>;
|
|
23
26
|
freeResources(): void;
|
|
24
27
|
}
|
|
28
|
+
export {};
|
|
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const BaseAdapter_1 = require("@jbrowse/core/data_adapters/BaseAdapter");
|
|
7
|
+
const util_1 = require("@jbrowse/core/util");
|
|
7
8
|
const io_1 = require("@jbrowse/core/util/io");
|
|
8
9
|
const rxjs_1 = require("@jbrowse/core/util/rxjs");
|
|
9
10
|
const interval_tree_1 = __importDefault(require("@flatten-js/interval-tree"));
|
|
@@ -11,66 +12,84 @@ const bgzf_filehandle_1 = require("@gmod/bgzf-filehandle");
|
|
|
11
12
|
const vcf_1 = __importDefault(require("@gmod/vcf"));
|
|
12
13
|
// local
|
|
13
14
|
const VcfFeature_1 = __importDefault(require("../VcfFeature"));
|
|
14
|
-
const readVcf = (f) => {
|
|
15
|
-
const header = [];
|
|
16
|
-
const rest = [];
|
|
17
|
-
f.split(/\n|\r\n|\r/)
|
|
18
|
-
.map(f => f.trim())
|
|
19
|
-
.filter(f => !!f)
|
|
20
|
-
.forEach(line => {
|
|
21
|
-
if (line.startsWith('#')) {
|
|
22
|
-
header.push(line);
|
|
23
|
-
}
|
|
24
|
-
else if (line) {
|
|
25
|
-
rest.push(line);
|
|
26
|
-
}
|
|
27
|
-
});
|
|
28
|
-
return { header: header.join('\n'), lines: rest };
|
|
29
|
-
};
|
|
30
|
-
function isGzip(buf) {
|
|
31
|
-
return buf[0] === 31 && buf[1] === 139 && buf[2] === 8;
|
|
32
|
-
}
|
|
33
15
|
class VcfAdapter extends BaseAdapter_1.BaseFeatureDataAdapter {
|
|
16
|
+
constructor() {
|
|
17
|
+
super(...arguments);
|
|
18
|
+
this.calculatedIntervalTreeMap = {};
|
|
19
|
+
}
|
|
34
20
|
async getHeader() {
|
|
35
21
|
const { header } = await this.setup();
|
|
36
22
|
return header;
|
|
37
23
|
}
|
|
38
24
|
async getMetadata() {
|
|
39
25
|
const { header } = await this.setup();
|
|
40
|
-
const parser = new vcf_1.default({ header
|
|
26
|
+
const parser = new vcf_1.default({ header });
|
|
41
27
|
return parser.getMetadata();
|
|
42
28
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
29
|
+
async setupP(opts) {
|
|
30
|
+
const { statusCallback = () => { } } = opts || {};
|
|
31
|
+
const buf = (await (0, io_1.openLocation)(this.getConf('vcfLocation'), this.pluginManager).readFile(opts));
|
|
32
|
+
const buffer = (0, util_1.isGzip)(buf)
|
|
33
|
+
? await (0, util_1.updateStatus)('Unzipping', statusCallback, () => (0, bgzf_filehandle_1.unzip)(buf))
|
|
34
|
+
: buf;
|
|
35
|
+
const headerLines = [];
|
|
36
|
+
const featureMap = {};
|
|
37
|
+
let blockStart = 0;
|
|
38
|
+
const decoder = typeof TextDecoder !== 'undefined' ? new TextDecoder('utf8') : undefined;
|
|
39
|
+
let i = 0;
|
|
40
|
+
while (blockStart < buffer.length) {
|
|
41
|
+
const n = buffer.indexOf('\n', blockStart);
|
|
42
|
+
// could be a non-newline ended file, so slice to end of file if n===-1
|
|
43
|
+
const b = n === -1 ? buffer.slice(blockStart) : buffer.slice(blockStart, n);
|
|
44
|
+
const line = ((decoder === null || decoder === void 0 ? void 0 : decoder.decode(b)) || b.toString()).trim();
|
|
45
|
+
if (line) {
|
|
46
|
+
if (line.startsWith('#')) {
|
|
47
|
+
headerLines.push(line);
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
const ret = line.indexOf('\t');
|
|
51
|
+
const refName = line.slice(0, ret);
|
|
52
|
+
if (!featureMap[refName]) {
|
|
53
|
+
featureMap[refName] = [];
|
|
54
|
+
}
|
|
55
|
+
featureMap[refName].push(line);
|
|
56
|
+
}
|
|
66
57
|
}
|
|
67
|
-
|
|
58
|
+
if (i++ % 10000 === 0) {
|
|
59
|
+
statusCallback(`Loading ${Math.floor(blockStart / 1000000).toLocaleString('en-US')}/${Math.floor(buffer.length / 1000000).toLocaleString('en-US')} MB`);
|
|
60
|
+
}
|
|
61
|
+
blockStart = n + 1;
|
|
68
62
|
}
|
|
69
|
-
|
|
63
|
+
const header = headerLines.join('\n');
|
|
64
|
+
const parser = new vcf_1.default({ header });
|
|
65
|
+
const intervalTreeMap = Object.fromEntries(Object.entries(featureMap).map(([refName, lines]) => [
|
|
66
|
+
refName,
|
|
67
|
+
(sc) => {
|
|
68
|
+
if (!this.calculatedIntervalTreeMap[refName]) {
|
|
69
|
+
sc === null || sc === void 0 ? void 0 : sc('Parsing VCF data');
|
|
70
|
+
let idx = 0;
|
|
71
|
+
const intervalTree = new interval_tree_1.default();
|
|
72
|
+
for (const line of lines) {
|
|
73
|
+
const f = new VcfFeature_1.default({
|
|
74
|
+
variant: parser.parseLine(line),
|
|
75
|
+
parser,
|
|
76
|
+
id: `${this.id}-${refName}-${idx++}`,
|
|
77
|
+
});
|
|
78
|
+
intervalTree.insert([f.get('start'), f.get('end')], f);
|
|
79
|
+
}
|
|
80
|
+
this.calculatedIntervalTreeMap[refName] = intervalTree;
|
|
81
|
+
}
|
|
82
|
+
return this.calculatedIntervalTreeMap[refName];
|
|
83
|
+
},
|
|
84
|
+
]));
|
|
85
|
+
return {
|
|
86
|
+
header,
|
|
87
|
+
intervalTreeMap,
|
|
88
|
+
};
|
|
70
89
|
}
|
|
71
90
|
async setup() {
|
|
72
91
|
if (!this.vcfFeatures) {
|
|
73
|
-
this.vcfFeatures = this.setupP().catch(e => {
|
|
92
|
+
this.vcfFeatures = this.setupP().catch((e) => {
|
|
74
93
|
this.vcfFeatures = undefined;
|
|
75
94
|
throw e;
|
|
76
95
|
});
|
|
@@ -78,16 +97,16 @@ class VcfAdapter extends BaseAdapter_1.BaseFeatureDataAdapter {
|
|
|
78
97
|
return this.vcfFeatures;
|
|
79
98
|
}
|
|
80
99
|
async getRefNames(_ = {}) {
|
|
81
|
-
const {
|
|
82
|
-
return Object.keys(
|
|
100
|
+
const { intervalTreeMap } = await this.setup();
|
|
101
|
+
return Object.keys(intervalTreeMap);
|
|
83
102
|
}
|
|
84
103
|
getFeatures(region, opts = {}) {
|
|
85
104
|
return (0, rxjs_1.ObservableCreate)(async (observer) => {
|
|
86
105
|
var _a;
|
|
87
106
|
try {
|
|
88
107
|
const { start, end, refName } = region;
|
|
89
|
-
const {
|
|
90
|
-
(_a =
|
|
108
|
+
const { intervalTreeMap } = await this.setup();
|
|
109
|
+
(_a = intervalTreeMap[refName]) === null || _a === void 0 ? void 0 : _a.call(intervalTreeMap, opts.statusCallback).search([start, end]).forEach(f => {
|
|
91
110
|
observer.next(f);
|
|
92
111
|
});
|
|
93
112
|
observer.complete();
|
package/dist/VcfFeature/index.js
CHANGED
|
@@ -3,14 +3,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
// locals
|
|
4
4
|
const util_1 = require("./util");
|
|
5
5
|
class VCFFeature {
|
|
6
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
7
6
|
constructor(args) {
|
|
8
7
|
this.variant = args.variant;
|
|
9
8
|
this.parser = args.parser;
|
|
10
9
|
this.data = this.dataFromVariant(this.variant);
|
|
11
10
|
this._id = args.id;
|
|
12
11
|
}
|
|
13
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
14
12
|
get(field) {
|
|
15
13
|
var _a;
|
|
16
14
|
return field === 'samples'
|
|
@@ -34,8 +32,8 @@ class VCFFeature {
|
|
|
34
32
|
const { REF, ALT, POS, CHROM, INFO, ID } = variant;
|
|
35
33
|
const start = POS - 1;
|
|
36
34
|
const [type, description] = (0, util_1.getSOTermAndDescription)(REF, ALT, this.parser);
|
|
37
|
-
const isTRA = ALT
|
|
38
|
-
const isSymbolic = ALT
|
|
35
|
+
const isTRA = ALT.includes('<TRA>');
|
|
36
|
+
const isSymbolic = ALT.some(f => f.includes('<'));
|
|
39
37
|
return {
|
|
40
38
|
refName: CHROM,
|
|
41
39
|
start,
|
|
@@ -43,10 +41,9 @@ class VCFFeature {
|
|
|
43
41
|
description,
|
|
44
42
|
type,
|
|
45
43
|
name: ID === null || ID === void 0 ? void 0 : ID.join(','),
|
|
46
|
-
aliases: ID && ID.length > 1 ?
|
|
44
|
+
aliases: ID && ID.length > 1 ? ID.slice(1) : undefined,
|
|
47
45
|
};
|
|
48
46
|
}
|
|
49
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
50
47
|
toJSON() {
|
|
51
48
|
return {
|
|
52
49
|
uniqueId: this._id,
|
|
@@ -2,6 +2,6 @@ import VCF from '@gmod/vcf';
|
|
|
2
2
|
/**
|
|
3
3
|
* Get a sequence ontology (SO) term that describes the variant type
|
|
4
4
|
*/
|
|
5
|
-
export declare function getSOTermAndDescription(ref: string, alt: string[], parser: VCF): string[];
|
|
5
|
+
export declare function getSOTermAndDescription(ref: string, alt: string[] | undefined, parser: VCF): string[];
|
|
6
6
|
export declare function getSOAndDescFromAltDefs(alt: string, parser: VCF): string[];
|
|
7
7
|
export declare function getSOAndDescByExamination(ref: string, alt: string): string[];
|
package/dist/VcfFeature/util.js
CHANGED
|
@@ -40,10 +40,12 @@ function getSOTermAndDescription(ref, alt, parser) {
|
|
|
40
40
|
// Combine descriptions like ["SNV G -> A", "SNV G -> T"] to ["SNV G -> A,T"]
|
|
41
41
|
if (descriptions.size > 1) {
|
|
42
42
|
const descs = [...descriptions];
|
|
43
|
-
const prefixes = new Set(descs
|
|
43
|
+
const prefixes = new Set(descs
|
|
44
|
+
.map(desc => {
|
|
44
45
|
const prefix = desc.split('->');
|
|
45
46
|
return prefix[1] ? prefix[0] : desc;
|
|
46
|
-
})
|
|
47
|
+
})
|
|
48
|
+
.filter((f) => !!f));
|
|
47
49
|
descriptions = new Set([...prefixes]
|
|
48
50
|
.map(r => r.trim())
|
|
49
51
|
.map(prefix => {
|
|
@@ -88,43 +90,43 @@ function getSOAndDescByExamination(ref, alt) {
|
|
|
88
90
|
if (bnd) {
|
|
89
91
|
return ['breakend', alt];
|
|
90
92
|
}
|
|
91
|
-
|
|
93
|
+
if (ref.length === 1 && alt.length === 1) {
|
|
92
94
|
return ['SNV', makeDescriptionString('SNV', ref, alt)];
|
|
93
95
|
}
|
|
94
|
-
|
|
96
|
+
if (alt === '<INS>') {
|
|
95
97
|
return ['insertion', alt];
|
|
96
98
|
}
|
|
97
|
-
|
|
99
|
+
if (alt === '<DEL>') {
|
|
98
100
|
return ['deletion', alt];
|
|
99
101
|
}
|
|
100
|
-
|
|
102
|
+
if (alt === '<INV>') {
|
|
101
103
|
return ['inversion', alt];
|
|
102
104
|
}
|
|
103
|
-
|
|
105
|
+
if (alt === '<TRA>') {
|
|
104
106
|
return ['translocation', alt];
|
|
105
107
|
}
|
|
106
|
-
|
|
108
|
+
if (alt.includes('<')) {
|
|
107
109
|
return ['sv', alt];
|
|
108
110
|
}
|
|
109
|
-
|
|
111
|
+
if (ref.length === alt.length) {
|
|
110
112
|
return ref.split('').reverse().join('') === alt
|
|
111
113
|
? ['inversion', makeDescriptionString('inversion', ref, alt)]
|
|
112
114
|
: ['substitution', makeDescriptionString('substitution', ref, alt)];
|
|
113
115
|
}
|
|
114
|
-
|
|
116
|
+
if (ref.length <= alt.length) {
|
|
115
117
|
const len = alt.length - ref.length;
|
|
116
118
|
const lena = len.toLocaleString('en-US');
|
|
117
119
|
return [
|
|
118
120
|
'insertion',
|
|
119
|
-
len > 5 ? lena
|
|
121
|
+
len > 5 ? `${lena}bp INS` : makeDescriptionString('insertion', ref, alt),
|
|
120
122
|
];
|
|
121
123
|
}
|
|
122
|
-
|
|
124
|
+
if (ref.length > alt.length) {
|
|
123
125
|
const len = ref.length - alt.length;
|
|
124
126
|
const lena = len.toLocaleString('en-US');
|
|
125
127
|
return [
|
|
126
128
|
'deletion',
|
|
127
|
-
len > 5 ? lena
|
|
129
|
+
len > 5 ? `${lena}bp DEL` : makeDescriptionString('deletion', ref, alt),
|
|
128
130
|
];
|
|
129
131
|
}
|
|
130
132
|
return ['indel', makeDescriptionString('indel', ref, alt)];
|
|
@@ -33,7 +33,7 @@ class VcfTabixAdapter extends BaseAdapter_1.BaseFeatureDataAdapter {
|
|
|
33
33
|
}
|
|
34
34
|
async configure() {
|
|
35
35
|
if (!this.configured) {
|
|
36
|
-
this.configured = this.configurePre().catch(e => {
|
|
36
|
+
this.configured = this.configurePre().catch((e) => {
|
|
37
37
|
this.configured = undefined;
|
|
38
38
|
throw e;
|
|
39
39
|
});
|
package/dist/extensionPoints.js
CHANGED
|
@@ -20,7 +20,7 @@ function ExtensionPointsF(pluginManager) {
|
|
|
20
20
|
if (regexGuess.test(fileName) && !adapterHint) {
|
|
21
21
|
return obj;
|
|
22
22
|
}
|
|
23
|
-
|
|
23
|
+
if (adapterHint === adapterName) {
|
|
24
24
|
return obj;
|
|
25
25
|
}
|
|
26
26
|
return adapterGuesser(file, index, adapterHint);
|
|
@@ -52,7 +52,7 @@ declare const stateModelFactory: (configSchema: AnyConfigurationSchemaType) => i
|
|
|
52
52
|
error: unknown;
|
|
53
53
|
message: string | undefined;
|
|
54
54
|
}, import("mobx-state-tree")._NotCustomized, import("mobx-state-tree")._NotCustomized>>;
|
|
55
|
-
onHorizontalScroll?:
|
|
55
|
+
onHorizontalScroll?: () => void;
|
|
56
56
|
blockState?: Record<string, any>;
|
|
57
57
|
}>;
|
|
58
58
|
readonly DisplayBlurb: import("react").FC<{
|
|
@@ -100,7 +100,7 @@ declare const stateModelFactory: (configSchema: AnyConfigurationSchemaType) => i
|
|
|
100
100
|
} & {
|
|
101
101
|
readonly blockDefinitions: import("@jbrowse/plugin-circular-view/src/CircularView/models/slices").Slice[];
|
|
102
102
|
renderProps(): any;
|
|
103
|
-
readonly rendererType: import("@jbrowse/core/pluggableElementTypes").RendererType;
|
|
103
|
+
readonly rendererType: import("@jbrowse/core/pluggableElementTypes").RendererType | undefined;
|
|
104
104
|
isCompatibleWithRenderer(renderer: import("@jbrowse/core/pluggableElementTypes").RendererType): renderer is import("@jbrowse/core/pluggableElementTypes").CircularChordRendererType;
|
|
105
105
|
readonly selectedFeatureId: string | undefined;
|
|
106
106
|
} & {
|
|
@@ -118,7 +118,7 @@ declare const stateModelFactory: (configSchema: AnyConfigurationSchemaType) => i
|
|
|
118
118
|
afterAttach(): void;
|
|
119
119
|
} & {
|
|
120
120
|
renderSvg(opts: import("@jbrowse/plugin-circular-view/src/CircularView/models/model").ExportSvgOptions & {
|
|
121
|
-
theme
|
|
121
|
+
theme?: import("@mui/material").ThemeOptions;
|
|
122
122
|
}): Promise<import("react").JSX.Element>;
|
|
123
123
|
} & {
|
|
124
124
|
/**
|