@jbrowse/plugin-breakpoint-split-view 2.6.1 → 2.6.2
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/BreakpointAlignmentsFeatureDetail/BreakpointAlignmentsFeatureDetail.js +0 -1
- package/dist/BreakpointAlignmentsFeatureDetail/index.js +0 -1
- package/dist/BreakpointSplitView/BreakpointSplitView.js +0 -1
- package/dist/BreakpointSplitView/components/AlignmentConnections.js +0 -1
- package/dist/BreakpointSplitView/components/Breakends.js +0 -1
- package/dist/BreakpointSplitView/components/BreakpointSplitView.js +0 -1
- package/dist/BreakpointSplitView/components/ExportSvgDialog.js +0 -1
- package/dist/BreakpointSplitView/components/Overlay.js +0 -1
- package/dist/BreakpointSplitView/components/Translocations.js +0 -1
- package/dist/BreakpointSplitView/components/util.js +0 -1
- package/dist/BreakpointSplitView/index.js +0 -1
- package/dist/BreakpointSplitView/model.d.ts +1 -1
- package/dist/BreakpointSplitView/model.js +3 -3
- package/dist/BreakpointSplitView/svgcomponents/SVGBackground.js +0 -1
- package/dist/BreakpointSplitView/svgcomponents/SVGBreakpointSplitView.js +0 -1
- package/dist/BreakpointSplitView/util.js +0 -1
- package/dist/index.js +0 -1
- package/esm/BreakpointAlignmentsFeatureDetail/BreakpointAlignmentsFeatureDetail.js +0 -1
- package/esm/BreakpointAlignmentsFeatureDetail/index.js +0 -1
- package/esm/BreakpointSplitView/BreakpointSplitView.js +0 -1
- package/esm/BreakpointSplitView/components/AlignmentConnections.js +0 -1
- package/esm/BreakpointSplitView/components/Breakends.js +0 -1
- package/esm/BreakpointSplitView/components/BreakpointSplitView.js +0 -1
- package/esm/BreakpointSplitView/components/ExportSvgDialog.js +0 -1
- package/esm/BreakpointSplitView/components/Overlay.js +0 -1
- package/esm/BreakpointSplitView/components/Translocations.js +0 -1
- package/esm/BreakpointSplitView/components/util.js +0 -1
- package/esm/BreakpointSplitView/index.js +0 -1
- package/esm/BreakpointSplitView/model.d.ts +1 -1
- package/esm/BreakpointSplitView/model.js +3 -3
- package/esm/BreakpointSplitView/svgcomponents/SVGBackground.js +0 -1
- package/esm/BreakpointSplitView/svgcomponents/SVGBreakpointSplitView.js +0 -1
- package/esm/BreakpointSplitView/util.js +0 -1
- package/esm/index.js +0 -1
- package/package.json +3 -4
- package/dist/BreakpointAlignmentsFeatureDetail/BreakpointAlignmentsFeatureDetail.js.map +0 -1
- package/dist/BreakpointAlignmentsFeatureDetail/index.js.map +0 -1
- package/dist/BreakpointSplitView/BreakpointSplitView.js.map +0 -1
- package/dist/BreakpointSplitView/components/AlignmentConnections.js.map +0 -1
- package/dist/BreakpointSplitView/components/Breakends.js.map +0 -1
- package/dist/BreakpointSplitView/components/BreakpointSplitView.js.map +0 -1
- package/dist/BreakpointSplitView/components/ExportSvgDialog.js.map +0 -1
- package/dist/BreakpointSplitView/components/Overlay.js.map +0 -1
- package/dist/BreakpointSplitView/components/Translocations.js.map +0 -1
- package/dist/BreakpointSplitView/components/util.js.map +0 -1
- package/dist/BreakpointSplitView/index.js.map +0 -1
- package/dist/BreakpointSplitView/model.js.map +0 -1
- package/dist/BreakpointSplitView/svgcomponents/SVGBackground.js.map +0 -1
- package/dist/BreakpointSplitView/svgcomponents/SVGBreakpointSplitView.js.map +0 -1
- package/dist/BreakpointSplitView/util.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/esm/BreakpointAlignmentsFeatureDetail/BreakpointAlignmentsFeatureDetail.js.map +0 -1
- package/esm/BreakpointAlignmentsFeatureDetail/index.js.map +0 -1
- package/esm/BreakpointSplitView/BreakpointSplitView.js.map +0 -1
- package/esm/BreakpointSplitView/components/AlignmentConnections.js.map +0 -1
- package/esm/BreakpointSplitView/components/Breakends.js.map +0 -1
- package/esm/BreakpointSplitView/components/BreakpointSplitView.js.map +0 -1
- package/esm/BreakpointSplitView/components/ExportSvgDialog.js.map +0 -1
- package/esm/BreakpointSplitView/components/Overlay.js.map +0 -1
- package/esm/BreakpointSplitView/components/Translocations.js.map +0 -1
- package/esm/BreakpointSplitView/components/util.js.map +0 -1
- package/esm/BreakpointSplitView/index.js.map +0 -1
- package/esm/BreakpointSplitView/model.js.map +0 -1
- package/esm/BreakpointSplitView/svgcomponents/SVGBackground.js.map +0 -1
- package/esm/BreakpointSplitView/svgcomponents/SVGBreakpointSplitView.js.map +0 -1
- package/esm/BreakpointSplitView/util.js.map +0 -1
- package/esm/index.js.map +0 -1
- package/src/BreakpointAlignmentsFeatureDetail/BreakpointAlignmentsFeatureDetail.tsx +0 -24
- package/src/BreakpointAlignmentsFeatureDetail/index.ts +0 -35
- package/src/BreakpointSplitView/BreakpointSplitView.ts +0 -100
- package/src/BreakpointSplitView/components/AlignmentConnections.tsx +0 -166
- package/src/BreakpointSplitView/components/Breakends.tsx +0 -141
- package/src/BreakpointSplitView/components/BreakpointSplitView.tsx +0 -95
- package/src/BreakpointSplitView/components/ExportSvgDialog.tsx +0 -149
- package/src/BreakpointSplitView/components/Overlay.tsx +0 -29
- package/src/BreakpointSplitView/components/Translocations.tsx +0 -147
- package/src/BreakpointSplitView/components/util.ts +0 -127
- package/src/BreakpointSplitView/index.ts +0 -17
- package/src/BreakpointSplitView/model.ts +0 -333
- package/src/BreakpointSplitView/svgcomponents/SVGBackground.tsx +0 -21
- package/src/BreakpointSplitView/svgcomponents/SVGBreakpointSplitView.tsx +0 -179
- package/src/BreakpointSplitView/util.ts +0 -89
- package/src/index.test.ts +0 -3
- package/src/index.ts +0 -15
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
import React, { useState } from 'react'
|
|
2
|
-
import {
|
|
3
|
-
Button,
|
|
4
|
-
Checkbox,
|
|
5
|
-
CircularProgress,
|
|
6
|
-
DialogActions,
|
|
7
|
-
DialogContent,
|
|
8
|
-
FormControlLabel,
|
|
9
|
-
MenuItem,
|
|
10
|
-
TextField,
|
|
11
|
-
Typography,
|
|
12
|
-
} from '@mui/material'
|
|
13
|
-
import { Dialog, ErrorMessage } from '@jbrowse/core/ui'
|
|
14
|
-
import { getSession, useLocalStorage } from '@jbrowse/core/util'
|
|
15
|
-
|
|
16
|
-
// locals
|
|
17
|
-
import { ExportSvgOptions } from '../model'
|
|
18
|
-
|
|
19
|
-
function LoadingMessage() {
|
|
20
|
-
return (
|
|
21
|
-
<div>
|
|
22
|
-
<CircularProgress size={20} style={{ marginRight: 20 }} />
|
|
23
|
-
<Typography display="inline">Creating SVG</Typography>
|
|
24
|
-
</div>
|
|
25
|
-
)
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function useSvgLocal<T>(key: string, val: T) {
|
|
29
|
-
return useLocalStorage('svg-' + key, val)
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export default function ExportSvgDlg({
|
|
33
|
-
model,
|
|
34
|
-
handleClose,
|
|
35
|
-
}: {
|
|
36
|
-
model: { exportSvg(opts: ExportSvgOptions): Promise<void> }
|
|
37
|
-
handleClose: () => void
|
|
38
|
-
}) {
|
|
39
|
-
const session = getSession(model)
|
|
40
|
-
const offscreenCanvas = typeof OffscreenCanvas !== 'undefined'
|
|
41
|
-
const [rasterizeLayers, setRasterizeLayers] = useState(offscreenCanvas)
|
|
42
|
-
const [loading, setLoading] = useState(false)
|
|
43
|
-
const [error, setError] = useState<unknown>()
|
|
44
|
-
const [filename, setFilename] = useSvgLocal('file', 'jbrowse.svg')
|
|
45
|
-
const [trackLabels, setTrackLabels] = useSvgLocal('tracklabels', 'offset')
|
|
46
|
-
const [themeName, setThemeName] = useSvgLocal(
|
|
47
|
-
'theme',
|
|
48
|
-
session.themeName || 'default',
|
|
49
|
-
)
|
|
50
|
-
return (
|
|
51
|
-
<Dialog open onClose={handleClose} title="Export SVG">
|
|
52
|
-
<DialogContent>
|
|
53
|
-
{error ? (
|
|
54
|
-
<ErrorMessage error={error} />
|
|
55
|
-
) : loading ? (
|
|
56
|
-
<LoadingMessage />
|
|
57
|
-
) : null}
|
|
58
|
-
<TextField
|
|
59
|
-
helperText="filename"
|
|
60
|
-
value={filename}
|
|
61
|
-
onChange={event => setFilename(event.target.value)}
|
|
62
|
-
/>
|
|
63
|
-
<br />
|
|
64
|
-
<TextField
|
|
65
|
-
select
|
|
66
|
-
label="Track label positioning"
|
|
67
|
-
variant="outlined"
|
|
68
|
-
style={{ width: 150 }}
|
|
69
|
-
value={trackLabels}
|
|
70
|
-
onChange={event => setTrackLabels(event.target.value)}
|
|
71
|
-
>
|
|
72
|
-
<MenuItem value="offset">Offset</MenuItem>
|
|
73
|
-
<MenuItem value="overlay">Overlay</MenuItem>
|
|
74
|
-
<MenuItem value="left">Left</MenuItem>
|
|
75
|
-
<MenuItem value="none">None</MenuItem>
|
|
76
|
-
</TextField>
|
|
77
|
-
<br />
|
|
78
|
-
{session.allThemes ? (
|
|
79
|
-
<TextField
|
|
80
|
-
select
|
|
81
|
-
label="Theme"
|
|
82
|
-
variant="outlined"
|
|
83
|
-
value={themeName}
|
|
84
|
-
onChange={event => setThemeName(event.target.value)}
|
|
85
|
-
>
|
|
86
|
-
{Object.entries(session.allThemes()).map(([key, val]) => (
|
|
87
|
-
<MenuItem key={key} value={key}>
|
|
88
|
-
{
|
|
89
|
-
// @ts-expect-error
|
|
90
|
-
val.name || '(Unknown name)'
|
|
91
|
-
}
|
|
92
|
-
</MenuItem>
|
|
93
|
-
))}
|
|
94
|
-
</TextField>
|
|
95
|
-
) : null}
|
|
96
|
-
|
|
97
|
-
{offscreenCanvas ? (
|
|
98
|
-
<FormControlLabel
|
|
99
|
-
control={
|
|
100
|
-
<Checkbox
|
|
101
|
-
checked={rasterizeLayers}
|
|
102
|
-
onChange={() => setRasterizeLayers(val => !val)}
|
|
103
|
-
/>
|
|
104
|
-
}
|
|
105
|
-
label="Rasterize canvas based tracks? File may be much larger if this is turned off"
|
|
106
|
-
/>
|
|
107
|
-
) : (
|
|
108
|
-
<Typography>
|
|
109
|
-
Note: rasterizing layers not yet supported in this browser, so SVG
|
|
110
|
-
size may be large
|
|
111
|
-
</Typography>
|
|
112
|
-
)}
|
|
113
|
-
</DialogContent>
|
|
114
|
-
<DialogActions>
|
|
115
|
-
<Button
|
|
116
|
-
variant="contained"
|
|
117
|
-
color="secondary"
|
|
118
|
-
onClick={() => handleClose()}
|
|
119
|
-
>
|
|
120
|
-
Cancel
|
|
121
|
-
</Button>
|
|
122
|
-
<Button
|
|
123
|
-
variant="contained"
|
|
124
|
-
color="primary"
|
|
125
|
-
type="submit"
|
|
126
|
-
onClick={async () => {
|
|
127
|
-
setLoading(true)
|
|
128
|
-
setError(undefined)
|
|
129
|
-
try {
|
|
130
|
-
await model.exportSvg({
|
|
131
|
-
rasterizeLayers,
|
|
132
|
-
filename,
|
|
133
|
-
trackLabels,
|
|
134
|
-
themeName,
|
|
135
|
-
})
|
|
136
|
-
handleClose()
|
|
137
|
-
} catch (e) {
|
|
138
|
-
console.error(e)
|
|
139
|
-
setError(e)
|
|
140
|
-
setLoading(false)
|
|
141
|
-
}
|
|
142
|
-
}}
|
|
143
|
-
>
|
|
144
|
-
Submit
|
|
145
|
-
</Button>
|
|
146
|
-
</DialogActions>
|
|
147
|
-
</Dialog>
|
|
148
|
-
)
|
|
149
|
-
}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import React from 'react'
|
|
2
|
-
import { observer } from 'mobx-react'
|
|
3
|
-
|
|
4
|
-
// locals
|
|
5
|
-
import { BreakpointViewModel } from '../model'
|
|
6
|
-
import AlignmentConnections from './AlignmentConnections'
|
|
7
|
-
import Breakends from './Breakends'
|
|
8
|
-
import Translocations from './Translocations'
|
|
9
|
-
|
|
10
|
-
export default observer(function (props: {
|
|
11
|
-
parentRef: React.RefObject<SVGSVGElement>
|
|
12
|
-
model: BreakpointViewModel
|
|
13
|
-
trackId: string
|
|
14
|
-
getTrackYPosOverride?: (trackId: string, level: number) => number
|
|
15
|
-
}) {
|
|
16
|
-
const { model, trackId } = props
|
|
17
|
-
const tracks = model.getMatchedTracks(trackId)
|
|
18
|
-
if (tracks[0]?.type === 'AlignmentsTrack') {
|
|
19
|
-
return <AlignmentConnections {...props} />
|
|
20
|
-
}
|
|
21
|
-
if (tracks[0]?.type === 'VariantTrack') {
|
|
22
|
-
return model.hasTranslocations(trackId) ? (
|
|
23
|
-
<Translocations {...props} />
|
|
24
|
-
) : (
|
|
25
|
-
<Breakends {...props} />
|
|
26
|
-
)
|
|
27
|
-
}
|
|
28
|
-
return null
|
|
29
|
-
})
|
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
import React, { useState, useMemo } from 'react'
|
|
2
|
-
import { getSession } from '@jbrowse/core/util'
|
|
3
|
-
import { observer } from 'mobx-react'
|
|
4
|
-
import { getSnapshot } from 'mobx-state-tree'
|
|
5
|
-
|
|
6
|
-
// locals
|
|
7
|
-
import { getMatchedTranslocationFeatures } from './util'
|
|
8
|
-
import { yPos, getPxFromCoordinate, useNextFrame } from '../util'
|
|
9
|
-
import { BreakpointViewModel, LayoutRecord } from '../model'
|
|
10
|
-
|
|
11
|
-
const [LEFT] = [0, 1, 2, 3]
|
|
12
|
-
|
|
13
|
-
const Translocations = observer(function ({
|
|
14
|
-
model,
|
|
15
|
-
trackId,
|
|
16
|
-
parentRef: ref,
|
|
17
|
-
getTrackYPosOverride,
|
|
18
|
-
}: {
|
|
19
|
-
model: BreakpointViewModel
|
|
20
|
-
trackId: string
|
|
21
|
-
parentRef: React.RefObject<SVGSVGElement>
|
|
22
|
-
getTrackYPosOverride?: (trackId: string, level: number) => number
|
|
23
|
-
}) {
|
|
24
|
-
const { views } = model
|
|
25
|
-
const session = getSession(model)
|
|
26
|
-
const { assemblyManager } = session
|
|
27
|
-
const totalFeatures = model.getTrackFeatures(trackId)
|
|
28
|
-
const layoutMatches = useMemo(
|
|
29
|
-
() =>
|
|
30
|
-
model.getMatchedFeaturesInLayout(
|
|
31
|
-
trackId,
|
|
32
|
-
getMatchedTranslocationFeatures(totalFeatures),
|
|
33
|
-
),
|
|
34
|
-
|
|
35
|
-
[totalFeatures, trackId, model],
|
|
36
|
-
)
|
|
37
|
-
|
|
38
|
-
const [mouseoverElt, setMouseoverElt] = useState<string>()
|
|
39
|
-
const snap = getSnapshot(model)
|
|
40
|
-
useNextFrame(snap)
|
|
41
|
-
|
|
42
|
-
const assembly = assemblyManager.get(views[0].assemblyNames[0])
|
|
43
|
-
if (!assembly) {
|
|
44
|
-
return null
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
let yOffset = 0
|
|
48
|
-
if (ref.current) {
|
|
49
|
-
const rect = ref.current.getBoundingClientRect()
|
|
50
|
-
yOffset = rect.top
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// we hardcode the TRA to go to the "other view" and if there is none, we
|
|
54
|
-
// just return null here note: would need to do processing of the INFO
|
|
55
|
-
// CHR2/END and see which view could contain those coordinates to really do
|
|
56
|
-
// it properly
|
|
57
|
-
if (views.length < 2) {
|
|
58
|
-
return null
|
|
59
|
-
}
|
|
60
|
-
return (
|
|
61
|
-
<g
|
|
62
|
-
fill="none"
|
|
63
|
-
stroke="green"
|
|
64
|
-
strokeWidth={5}
|
|
65
|
-
data-testid={layoutMatches.length ? `${trackId}-loaded` : trackId}
|
|
66
|
-
>
|
|
67
|
-
{layoutMatches.map(chunk => {
|
|
68
|
-
// we follow a path in the list of chunks, not from top to bottom,
|
|
69
|
-
// just in series following x1,y1 -> x2,y2
|
|
70
|
-
const ret = []
|
|
71
|
-
for (let i = 0; i < chunk.length; i += 1) {
|
|
72
|
-
const { layout: c1, feature: f1, level: level1 } = chunk[i]
|
|
73
|
-
const level2 = level1 === 0 ? 1 : 0
|
|
74
|
-
const id = f1.id()
|
|
75
|
-
if (!c1) {
|
|
76
|
-
return null
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
const info = f1.get('INFO')
|
|
80
|
-
const chr2 = info.CHR2[0]
|
|
81
|
-
const end2 = info.END[0]
|
|
82
|
-
const [myDirection, mateDirection] = info.STRANDS[0].split('')
|
|
83
|
-
|
|
84
|
-
const r = getPxFromCoordinate(views[level2], chr2, end2)
|
|
85
|
-
if (r) {
|
|
86
|
-
const c2: LayoutRecord = [r, 0, r + 1, 0]
|
|
87
|
-
const x1 = getPxFromCoordinate(
|
|
88
|
-
views[level1],
|
|
89
|
-
f1.get('refName'),
|
|
90
|
-
c1[LEFT],
|
|
91
|
-
)
|
|
92
|
-
const x2 = r
|
|
93
|
-
const reversed1 = views[level1].pxToBp(x1).reversed
|
|
94
|
-
const reversed2 = views[level2].pxToBp(x2).reversed
|
|
95
|
-
|
|
96
|
-
const tracks = views.map(v => v.getTrack(trackId))
|
|
97
|
-
const y1 =
|
|
98
|
-
yPos(trackId, level1, views, tracks, c1, getTrackYPosOverride) -
|
|
99
|
-
yOffset
|
|
100
|
-
const y2 =
|
|
101
|
-
yPos(trackId, level2, views, tracks, c2, getTrackYPosOverride) -
|
|
102
|
-
yOffset
|
|
103
|
-
|
|
104
|
-
const path = [
|
|
105
|
-
'M', // move to
|
|
106
|
-
x1 - 20 * (myDirection === '+' ? 1 : -1) * (reversed1 ? -1 : 1),
|
|
107
|
-
y1,
|
|
108
|
-
'L', // line to
|
|
109
|
-
x1,
|
|
110
|
-
y1,
|
|
111
|
-
'L', // line to
|
|
112
|
-
x2,
|
|
113
|
-
y2,
|
|
114
|
-
'L', // line to
|
|
115
|
-
x2 - 20 * (mateDirection === '+' ? 1 : -1) * (reversed2 ? -1 : 1),
|
|
116
|
-
y2,
|
|
117
|
-
].join(' ')
|
|
118
|
-
ret.push(
|
|
119
|
-
<path
|
|
120
|
-
d={path}
|
|
121
|
-
key={JSON.stringify(path)}
|
|
122
|
-
strokeWidth={id === mouseoverElt ? 10 : 5}
|
|
123
|
-
onClick={() => {
|
|
124
|
-
const featureWidget = session.addWidget?.(
|
|
125
|
-
'VariantFeatureWidget',
|
|
126
|
-
'variantFeature',
|
|
127
|
-
{
|
|
128
|
-
featureData: (
|
|
129
|
-
totalFeatures.get(id) || { toJSON: () => {} }
|
|
130
|
-
).toJSON(),
|
|
131
|
-
},
|
|
132
|
-
)
|
|
133
|
-
session.showWidget?.(featureWidget)
|
|
134
|
-
}}
|
|
135
|
-
onMouseOver={() => setMouseoverElt(id)}
|
|
136
|
-
onMouseOut={() => setMouseoverElt(undefined)}
|
|
137
|
-
/>,
|
|
138
|
-
)
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
return ret
|
|
142
|
-
})}
|
|
143
|
-
</g>
|
|
144
|
-
)
|
|
145
|
-
})
|
|
146
|
-
|
|
147
|
-
export default Translocations
|
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
import { Feature, notEmpty } from '@jbrowse/core/util'
|
|
2
|
-
|
|
3
|
-
import { parseBreakend } from '@gmod/vcf'
|
|
4
|
-
|
|
5
|
-
// this finds candidate alignment features, aimed at plotting split reads from
|
|
6
|
-
// BAM/CRAM files
|
|
7
|
-
export function getBadlyPairedAlignments(features: Map<string, Feature>) {
|
|
8
|
-
const candidates = new Map<string, Feature[]>()
|
|
9
|
-
const alreadySeen = new Set<string>()
|
|
10
|
-
|
|
11
|
-
// this finds candidate features that share the same name
|
|
12
|
-
for (const feature of features.values()) {
|
|
13
|
-
const flags = feature.get('flags')
|
|
14
|
-
const id = feature.id()
|
|
15
|
-
const unmapped = flags & 4
|
|
16
|
-
const correctlyPaired = flags & 2
|
|
17
|
-
|
|
18
|
-
if (!alreadySeen.has(id) && !correctlyPaired && !unmapped) {
|
|
19
|
-
const n = feature.get('name')
|
|
20
|
-
let val = candidates.get(n)
|
|
21
|
-
if (!val) {
|
|
22
|
-
val = []
|
|
23
|
-
candidates.set(n, val)
|
|
24
|
-
}
|
|
25
|
-
val.push(feature)
|
|
26
|
-
}
|
|
27
|
-
alreadySeen.add(feature.id())
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
return [...candidates.values()].filter(v => v.length > 1)
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function getTag(f: Feature, tag: string) {
|
|
34
|
-
const tags = f.get('tags')
|
|
35
|
-
return tags ? tags[tag] : f.get(tag)
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// this finds candidate alignment features, aimed at plotting split reads from
|
|
39
|
-
// BAM/CRAM files
|
|
40
|
-
export function getMatchedAlignmentFeatures(features: Map<string, Feature>) {
|
|
41
|
-
const candidates = new Map<string, Feature[]>()
|
|
42
|
-
const alreadySeen = new Set<string>()
|
|
43
|
-
|
|
44
|
-
// this finds candidate features that share the same name
|
|
45
|
-
for (const feature of features.values()) {
|
|
46
|
-
const id = feature.id()
|
|
47
|
-
const unmapped = feature.get('flags') & 4
|
|
48
|
-
const hasSA = !!getTag(feature, 'SA')
|
|
49
|
-
if (!alreadySeen.has(id) && !unmapped && hasSA) {
|
|
50
|
-
const n = feature.get('name')
|
|
51
|
-
let val = candidates.get(n)
|
|
52
|
-
if (!val) {
|
|
53
|
-
val = []
|
|
54
|
-
candidates.set(n, val)
|
|
55
|
-
}
|
|
56
|
-
val.push(feature)
|
|
57
|
-
}
|
|
58
|
-
alreadySeen.add(feature.id())
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
return [...candidates.values()].filter(v => v.length > 1)
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export function hasPairedReads(features: Map<string, Feature>) {
|
|
65
|
-
for (const f of features.values()) {
|
|
66
|
-
if (f.get('flags') & 1) {
|
|
67
|
-
return true
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
return false
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
export function findMatchingAlt(feat1: Feature, feat2: Feature) {
|
|
74
|
-
const alts = feat1.get('ALT') as string[] | undefined
|
|
75
|
-
if (alts) {
|
|
76
|
-
return new Map(
|
|
77
|
-
alts
|
|
78
|
-
?.map(alt => parseBreakend(alt))
|
|
79
|
-
.filter(notEmpty)
|
|
80
|
-
.map(bnd => [bnd.MatePosition, bnd]),
|
|
81
|
-
).get(`${feat2.get('refName')}:${feat2.get('start') + 1}`)
|
|
82
|
-
}
|
|
83
|
-
return undefined
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// Returns paired BND features across multiple views by inspecting the ALT
|
|
87
|
-
// field to get exact coordinate matches
|
|
88
|
-
export function getMatchedBreakendFeatures(feats: Map<string, Feature>) {
|
|
89
|
-
const candidates = new Map<string, Feature[]>()
|
|
90
|
-
const alreadySeen = new Set<string>()
|
|
91
|
-
|
|
92
|
-
for (const f of feats.values()) {
|
|
93
|
-
if (!alreadySeen.has(f.id()) && f.get('type') === 'breakend') {
|
|
94
|
-
const alts = f.get('ALT') as string[] | undefined
|
|
95
|
-
alts?.forEach(a => {
|
|
96
|
-
const cur = `${f.get('refName')}:${f.get('start') + 1}`
|
|
97
|
-
const bnd = parseBreakend(a)
|
|
98
|
-
if (bnd) {
|
|
99
|
-
const val = candidates.get(cur)
|
|
100
|
-
if (!val) {
|
|
101
|
-
candidates.set(bnd.MatePosition || 'none', [f])
|
|
102
|
-
} else {
|
|
103
|
-
val.push(f)
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
})
|
|
107
|
-
}
|
|
108
|
-
alreadySeen.add(f.id())
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
return [...candidates.values()].filter(v => v.length > 1)
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// Getting "matched" TRA means just return all TRA
|
|
115
|
-
export function getMatchedTranslocationFeatures(feats: Map<string, Feature>) {
|
|
116
|
-
const ret: Feature[][] = []
|
|
117
|
-
const alreadySeen = new Set<string>()
|
|
118
|
-
|
|
119
|
-
for (const f of feats.values()) {
|
|
120
|
-
if (!alreadySeen.has(f.id()) && f.get('ALT')[0] === '<TRA>') {
|
|
121
|
-
ret.push([f])
|
|
122
|
-
}
|
|
123
|
-
alreadySeen.add(f.id())
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
return ret
|
|
127
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { lazy } from 'react'
|
|
2
|
-
import PluginManager from '@jbrowse/core/PluginManager'
|
|
3
|
-
|
|
4
|
-
// locals
|
|
5
|
-
import BreakpointSplitView from './BreakpointSplitView'
|
|
6
|
-
import stateModelFactory from './model'
|
|
7
|
-
|
|
8
|
-
export default (pluginManager: PluginManager) => {
|
|
9
|
-
pluginManager.addViewType(() => {
|
|
10
|
-
return new BreakpointSplitView({
|
|
11
|
-
name: 'BreakpointSplitView',
|
|
12
|
-
displayName: 'Breakpoint split view',
|
|
13
|
-
stateModel: stateModelFactory(pluginManager),
|
|
14
|
-
ReactComponent: lazy(() => import('./components/BreakpointSplitView')),
|
|
15
|
-
})
|
|
16
|
-
})
|
|
17
|
-
}
|