@jbrowse/plugin-alignments 2.2.0 → 2.2.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/AlignmentsFeatureDetail/AlignmentsFeatureDetail.js +12 -13
- package/dist/AlignmentsFeatureDetail/AlignmentsFeatureDetail.js.map +1 -1
- package/dist/BamAdapter/BamAdapter.d.ts +1 -1
- package/dist/BamAdapter/BamAdapter.js +1 -0
- package/dist/BamAdapter/BamAdapter.js.map +1 -1
- package/dist/BamAdapter/BamSlightlyLazyFeature.js +1 -0
- package/dist/BamAdapter/BamSlightlyLazyFeature.js.map +1 -1
- package/dist/BamAdapter/MismatchParser.d.ts +2 -2
- package/dist/BamAdapter/MismatchParser.js +4 -7
- package/dist/BamAdapter/MismatchParser.js.map +1 -1
- package/dist/BamAdapter/configSchema.js +1 -1
- package/dist/BamAdapter/configSchema.js.map +1 -1
- package/dist/BamAdapter/index.js +7 -5
- package/dist/BamAdapter/index.js.map +1 -1
- package/dist/CramAdapter/CramSlightlyLazyFeature.d.ts +1 -10
- package/dist/CramAdapter/CramSlightlyLazyFeature.js +5 -218
- package/dist/CramAdapter/CramSlightlyLazyFeature.js.map +1 -1
- package/dist/CramAdapter/CramTestAdapters.d.ts +1 -1
- package/dist/CramAdapter/CramTestAdapters.js +3 -2
- package/dist/CramAdapter/CramTestAdapters.js.map +1 -1
- package/dist/CramAdapter/configSchema.js +2 -2
- package/dist/CramAdapter/configSchema.js.map +1 -1
- package/dist/CramAdapter/index.js +7 -5
- package/dist/CramAdapter/index.js.map +1 -1
- package/dist/CramAdapter/util.d.ts +18 -0
- package/dist/CramAdapter/util.js +241 -0
- package/dist/CramAdapter/util.js.map +1 -0
- package/dist/LinearAlignmentsDisplay/components/AlignmentsDisplay.js +1 -1
- package/dist/LinearAlignmentsDisplay/components/AlignmentsDisplay.js.map +1 -1
- package/dist/LinearAlignmentsDisplay/models/configSchema.d.ts +1 -1
- package/dist/LinearAlignmentsDisplay/models/model.d.ts +5 -5
- package/dist/LinearAlignmentsDisplay/models/model.js +7 -7
- package/dist/LinearAlignmentsDisplay/models/model.js.map +1 -1
- package/dist/LinearPileupDisplay/components/ColorByModifications.d.ts +3 -1
- package/dist/LinearPileupDisplay/components/ColorByModifications.js +7 -22
- package/dist/LinearPileupDisplay/components/ColorByModifications.js.map +1 -1
- package/dist/LinearPileupDisplay/components/ColorByTag.js +2 -22
- package/dist/LinearPileupDisplay/components/ColorByTag.js.map +1 -1
- package/dist/LinearPileupDisplay/components/FilterByTag.js +2 -15
- package/dist/LinearPileupDisplay/components/FilterByTag.js.map +1 -1
- package/dist/LinearPileupDisplay/components/SetFeatureHeight.js +2 -19
- package/dist/LinearPileupDisplay/components/SetFeatureHeight.js.map +1 -1
- package/dist/LinearPileupDisplay/components/SetMaxHeight.js +2 -18
- package/dist/LinearPileupDisplay/components/SetMaxHeight.js.map +1 -1
- package/dist/LinearPileupDisplay/components/SortByTag.js +2 -23
- package/dist/LinearPileupDisplay/components/SortByTag.js.map +1 -1
- package/dist/LinearPileupDisplay/configSchema.d.ts +4 -4
- package/dist/LinearPileupDisplay/configSchema.js +2 -2
- package/dist/LinearPileupDisplay/configSchema.js.map +1 -1
- package/dist/LinearPileupDisplay/index.d.ts +3 -0
- package/dist/LinearPileupDisplay/index.js +3 -0
- package/dist/LinearPileupDisplay/index.js.map +1 -1
- package/dist/LinearPileupDisplay/model.d.ts +19 -9
- package/dist/LinearPileupDisplay/model.js +25 -30
- package/dist/LinearPileupDisplay/model.js.map +1 -1
- package/dist/LinearSNPCoverageDisplay/components/Tooltip.d.ts +1 -1
- package/dist/LinearSNPCoverageDisplay/models/model.d.ts +14 -10
- package/dist/LinearSNPCoverageDisplay/models/model.js +8 -6
- package/dist/LinearSNPCoverageDisplay/models/model.js.map +1 -1
- package/dist/PileupRPC/rpcMethods.d.ts +1 -1
- package/dist/PileupRPC/rpcMethods.js +12 -7
- package/dist/PileupRPC/rpcMethods.js.map +1 -1
- package/dist/PileupRenderer/PileupLayoutSession.d.ts +1 -1
- package/dist/PileupRenderer/PileupRenderer.js +32 -28
- package/dist/PileupRenderer/PileupRenderer.js.map +1 -1
- package/dist/PileupRenderer/configSchema.js +1 -1
- package/dist/PileupRenderer/configSchema.js.map +1 -1
- package/dist/PileupRenderer/index.js +8 -6
- package/dist/PileupRenderer/index.js.map +1 -1
- package/dist/SNPCoverageAdapter/SNPCoverageAdapter.d.ts +0 -51
- package/dist/SNPCoverageAdapter/SNPCoverageAdapter.js +3 -182
- package/dist/SNPCoverageAdapter/SNPCoverageAdapter.js.map +1 -1
- package/dist/SNPCoverageAdapter/configSchema.d.ts +2 -3
- package/dist/SNPCoverageAdapter/configSchema.js +6 -3
- package/dist/SNPCoverageAdapter/configSchema.js.map +1 -1
- package/dist/SNPCoverageAdapter/generateCoverageBins.d.ts +53 -0
- package/dist/SNPCoverageAdapter/generateCoverageBins.js +185 -0
- package/dist/SNPCoverageAdapter/generateCoverageBins.js.map +1 -0
- package/dist/SNPCoverageAdapter/index.d.ts +1 -2
- package/dist/SNPCoverageAdapter/index.js +17 -14
- package/dist/SNPCoverageAdapter/index.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/esm/AlignmentsFeatureDetail/AlignmentsFeatureDetail.js +12 -13
- package/esm/AlignmentsFeatureDetail/AlignmentsFeatureDetail.js.map +1 -1
- package/esm/BamAdapter/BamAdapter.d.ts +1 -1
- package/esm/BamAdapter/BamAdapter.js +1 -0
- package/esm/BamAdapter/BamAdapter.js.map +1 -1
- package/esm/BamAdapter/BamSlightlyLazyFeature.js +1 -0
- package/esm/BamAdapter/BamSlightlyLazyFeature.js.map +1 -1
- package/esm/BamAdapter/MismatchParser.d.ts +2 -2
- package/esm/BamAdapter/MismatchParser.js +4 -7
- package/esm/BamAdapter/MismatchParser.js.map +1 -1
- package/esm/BamAdapter/configSchema.js +1 -1
- package/esm/BamAdapter/configSchema.js.map +1 -1
- package/esm/BamAdapter/index.js +7 -5
- package/esm/BamAdapter/index.js.map +1 -1
- package/esm/CramAdapter/CramSlightlyLazyFeature.d.ts +1 -10
- package/esm/CramAdapter/CramSlightlyLazyFeature.js +5 -218
- package/esm/CramAdapter/CramSlightlyLazyFeature.js.map +1 -1
- package/esm/CramAdapter/CramTestAdapters.d.ts +1 -1
- package/esm/CramAdapter/CramTestAdapters.js +3 -2
- package/esm/CramAdapter/CramTestAdapters.js.map +1 -1
- package/esm/CramAdapter/configSchema.js +2 -2
- package/esm/CramAdapter/configSchema.js.map +1 -1
- package/esm/CramAdapter/index.js +7 -5
- package/esm/CramAdapter/index.js.map +1 -1
- package/esm/CramAdapter/util.d.ts +18 -0
- package/esm/CramAdapter/util.js +236 -0
- package/esm/CramAdapter/util.js.map +1 -0
- package/esm/LinearAlignmentsDisplay/components/AlignmentsDisplay.js +1 -1
- package/esm/LinearAlignmentsDisplay/components/AlignmentsDisplay.js.map +1 -1
- package/esm/LinearAlignmentsDisplay/models/configSchema.d.ts +1 -1
- package/esm/LinearAlignmentsDisplay/models/model.d.ts +5 -5
- package/esm/LinearAlignmentsDisplay/models/model.js +7 -7
- package/esm/LinearAlignmentsDisplay/models/model.js.map +1 -1
- package/esm/LinearPileupDisplay/components/ColorByModifications.d.ts +3 -1
- package/esm/LinearPileupDisplay/components/ColorByModifications.js +8 -23
- package/esm/LinearPileupDisplay/components/ColorByModifications.js.map +1 -1
- package/esm/LinearPileupDisplay/components/ColorByTag.js +3 -20
- package/esm/LinearPileupDisplay/components/ColorByTag.js.map +1 -1
- package/esm/LinearPileupDisplay/components/FilterByTag.js +3 -13
- package/esm/LinearPileupDisplay/components/FilterByTag.js.map +1 -1
- package/esm/LinearPileupDisplay/components/SetFeatureHeight.js +3 -17
- package/esm/LinearPileupDisplay/components/SetFeatureHeight.js.map +1 -1
- package/esm/LinearPileupDisplay/components/SetMaxHeight.js +3 -16
- package/esm/LinearPileupDisplay/components/SetMaxHeight.js.map +1 -1
- package/esm/LinearPileupDisplay/components/SortByTag.js +3 -21
- package/esm/LinearPileupDisplay/components/SortByTag.js.map +1 -1
- package/esm/LinearPileupDisplay/configSchema.d.ts +4 -4
- package/esm/LinearPileupDisplay/configSchema.js +2 -2
- package/esm/LinearPileupDisplay/configSchema.js.map +1 -1
- package/esm/LinearPileupDisplay/index.d.ts +3 -0
- package/esm/LinearPileupDisplay/index.js +1 -0
- package/esm/LinearPileupDisplay/index.js.map +1 -1
- package/esm/LinearPileupDisplay/model.d.ts +19 -9
- package/esm/LinearPileupDisplay/model.js +25 -30
- package/esm/LinearPileupDisplay/model.js.map +1 -1
- package/esm/LinearSNPCoverageDisplay/components/Tooltip.d.ts +1 -1
- package/esm/LinearSNPCoverageDisplay/models/model.d.ts +14 -10
- package/esm/LinearSNPCoverageDisplay/models/model.js +9 -7
- package/esm/LinearSNPCoverageDisplay/models/model.js.map +1 -1
- package/esm/PileupRPC/rpcMethods.d.ts +1 -1
- package/esm/PileupRPC/rpcMethods.js +12 -7
- package/esm/PileupRPC/rpcMethods.js.map +1 -1
- package/esm/PileupRenderer/PileupLayoutSession.d.ts +1 -1
- package/esm/PileupRenderer/PileupRenderer.js +32 -28
- package/esm/PileupRenderer/PileupRenderer.js.map +1 -1
- package/esm/PileupRenderer/configSchema.js +1 -1
- package/esm/PileupRenderer/configSchema.js.map +1 -1
- package/esm/PileupRenderer/index.js +8 -6
- package/esm/PileupRenderer/index.js.map +1 -1
- package/esm/SNPCoverageAdapter/SNPCoverageAdapter.d.ts +0 -51
- package/esm/SNPCoverageAdapter/SNPCoverageAdapter.js +4 -183
- package/esm/SNPCoverageAdapter/SNPCoverageAdapter.js.map +1 -1
- package/esm/SNPCoverageAdapter/configSchema.d.ts +2 -3
- package/esm/SNPCoverageAdapter/configSchema.js +6 -3
- package/esm/SNPCoverageAdapter/configSchema.js.map +1 -1
- package/esm/SNPCoverageAdapter/generateCoverageBins.d.ts +53 -0
- package/esm/SNPCoverageAdapter/generateCoverageBins.js +182 -0
- package/esm/SNPCoverageAdapter/generateCoverageBins.js.map +1 -0
- package/esm/SNPCoverageAdapter/index.d.ts +1 -2
- package/esm/SNPCoverageAdapter/index.js +17 -15
- package/esm/SNPCoverageAdapter/index.js.map +1 -1
- package/esm/index.d.ts +3 -2
- package/esm/index.js +2 -2
- package/esm/index.js.map +1 -1
- package/package.json +4 -3
- package/src/AlignmentsFeatureDetail/AlignmentsFeatureDetail.tsx +17 -16
- package/src/AlignmentsFeatureDetail/__snapshots__/index.test.js.snap +1 -473
- package/src/AlignmentsFeatureDetail/index.test.js +6 -4
- package/src/BamAdapter/BamAdapter.ts +3 -2
- package/src/BamAdapter/BamSlightlyLazyFeature.ts +2 -1
- package/src/BamAdapter/MismatchParser.test.ts +21 -12
- package/src/BamAdapter/MismatchParser.ts +7 -10
- package/src/BamAdapter/__snapshots__/BamAdapter.test.ts.snap +135 -135
- package/src/BamAdapter/configSchema.ts +1 -1
- package/src/BamAdapter/index.ts +7 -8
- package/src/CombinationTest.test.ts +107 -0
- package/src/CramAdapter/CramSlightlyLazyFeature.ts +10 -219
- package/src/CramAdapter/CramTestAdapters.ts +2 -1
- package/src/CramAdapter/__snapshots__/CramAdapter.test.ts.snap +31 -31
- package/src/CramAdapter/__snapshots__/util.test.ts.snap +14 -0
- package/src/CramAdapter/configSchema.ts +2 -3
- package/src/CramAdapter/index.ts +7 -8
- package/src/CramAdapter/util.test.ts +26 -0
- package/src/CramAdapter/util.ts +251 -0
- package/src/LinearAlignmentsDisplay/components/AlignmentsDisplay.tsx +3 -1
- package/src/LinearAlignmentsDisplay/models/model.tsx +8 -7
- package/src/LinearPileupDisplay/components/ColorByModifications.tsx +5 -34
- package/src/LinearPileupDisplay/components/ColorByTag.tsx +2 -29
- package/src/LinearPileupDisplay/components/FilterByTag.tsx +2 -22
- package/src/LinearPileupDisplay/components/SetFeatureHeight.tsx +2 -22
- package/src/LinearPileupDisplay/components/SetMaxHeight.tsx +2 -24
- package/src/LinearPileupDisplay/components/SortByTag.tsx +2 -31
- package/src/LinearPileupDisplay/configSchema.ts +3 -5
- package/src/LinearPileupDisplay/index.ts +5 -0
- package/src/LinearPileupDisplay/model.ts +31 -30
- package/src/LinearSNPCoverageDisplay/models/model.ts +12 -8
- package/src/PileupRPC/rpcMethods.ts +15 -20
- package/src/PileupRenderer/{PileupRenderer.tsx → PileupRenderer.ts} +48 -54
- package/src/PileupRenderer/configSchema.ts +1 -1
- package/src/PileupRenderer/index.ts +8 -9
- package/src/SNPCoverageAdapter/SNPCoverageAdapter.ts +5 -249
- package/src/SNPCoverageAdapter/configSchema.ts +14 -13
- package/src/SNPCoverageAdapter/generateCoverageBins.ts +245 -0
- package/src/SNPCoverageAdapter/index.ts +17 -18
- package/src/__snapshots__/index.test.ts.snap +1 -1
- package/src/index.ts +11 -4
|
@@ -6,46 +6,13 @@ import { AugmentedRegion as Region } from '@jbrowse/core/util/types'
|
|
|
6
6
|
import SimpleFeature, { Feature } from '@jbrowse/core/util/simpleFeature'
|
|
7
7
|
import { ObservableCreate } from '@jbrowse/core/util/rxjs'
|
|
8
8
|
import { toArray } from 'rxjs/operators'
|
|
9
|
-
import
|
|
10
|
-
|
|
11
|
-
getTagAlt,
|
|
12
|
-
fetchSequence,
|
|
13
|
-
shouldFetchReferenceSequence,
|
|
14
|
-
} from '../util'
|
|
15
|
-
import {
|
|
16
|
-
parseCigar,
|
|
17
|
-
getNextRefPos,
|
|
18
|
-
getModificationPositions,
|
|
19
|
-
Mismatch,
|
|
20
|
-
} from '../BamAdapter/MismatchParser'
|
|
21
|
-
|
|
22
|
-
function mismatchLen(mismatch: Mismatch) {
|
|
23
|
-
return !isInterbase(mismatch.type) ? mismatch.length : 1
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function isInterbase(type: string) {
|
|
27
|
-
return type === 'softclip' || type === 'hardclip' || type === 'insertion'
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
31
|
-
function inc(bin: any, strand: number, type: string, field: string) {
|
|
32
|
-
let thisBin = bin[type][field]
|
|
33
|
-
if (thisBin === undefined) {
|
|
34
|
-
thisBin = bin[type][field] = {
|
|
35
|
-
total: 0,
|
|
36
|
-
'-1': 0,
|
|
37
|
-
'0': 0,
|
|
38
|
-
'1': 0,
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
thisBin.total++
|
|
42
|
-
thisBin[strand]++
|
|
43
|
-
}
|
|
9
|
+
import generateCoverageBins from './generateCoverageBins'
|
|
10
|
+
import { fetchSequence } from '../util'
|
|
44
11
|
|
|
45
12
|
export default class SNPCoverageAdapter extends BaseFeatureDataAdapter {
|
|
46
13
|
protected async configure() {
|
|
47
14
|
const subadapterConfig = this.getConf('subadapter')
|
|
48
|
-
const sequenceConf =
|
|
15
|
+
const sequenceConf = subadapterConfig.sequenceAdapter
|
|
49
16
|
const dataAdapter = await this.getSubAdapter?.(subadapterConfig)
|
|
50
17
|
|
|
51
18
|
const sequenceAdapter = sequenceConf
|
|
@@ -81,10 +48,11 @@ export default class SNPCoverageAdapter extends BaseFeatureDataAdapter {
|
|
|
81
48
|
.pipe(toArray())
|
|
82
49
|
.toPromise()
|
|
83
50
|
|
|
84
|
-
const { bins, skipmap } = await
|
|
51
|
+
const { bins, skipmap } = await generateCoverageBins(
|
|
85
52
|
feats,
|
|
86
53
|
region,
|
|
87
54
|
opts,
|
|
55
|
+
arg => this.fetchSequence(arg),
|
|
88
56
|
)
|
|
89
57
|
|
|
90
58
|
bins.forEach((bin, index) => {
|
|
@@ -135,218 +103,6 @@ export default class SNPCoverageAdapter extends BaseFeatureDataAdapter {
|
|
|
135
103
|
}
|
|
136
104
|
|
|
137
105
|
freeResources(/* { region } */): void {}
|
|
138
|
-
|
|
139
|
-
async generateCoverageBins(
|
|
140
|
-
features: Feature[],
|
|
141
|
-
region: Region,
|
|
142
|
-
opts: { bpPerPx?: number; colorBy?: { type: string; tag?: string } },
|
|
143
|
-
) {
|
|
144
|
-
const { colorBy } = opts
|
|
145
|
-
const binMax = Math.ceil(region.end - region.start)
|
|
146
|
-
|
|
147
|
-
const skipmap = {} as {
|
|
148
|
-
[key: string]: {
|
|
149
|
-
score: number
|
|
150
|
-
feature: unknown
|
|
151
|
-
start: number
|
|
152
|
-
end: number
|
|
153
|
-
strand: number
|
|
154
|
-
xs: string
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
// bins contain:
|
|
159
|
-
// - cov feature if they contribute to coverage
|
|
160
|
-
// - noncov are insertions/clip features that don't contribute to coverage
|
|
161
|
-
// - delskips deletions or introns that don't contribute to coverage
|
|
162
|
-
type BinType = { total: number; strands: { [key: string]: number } }
|
|
163
|
-
|
|
164
|
-
const regionSeq =
|
|
165
|
-
features.length && shouldFetchReferenceSequence(opts.colorBy?.type)
|
|
166
|
-
? await this.fetchSequence(region)
|
|
167
|
-
: undefined
|
|
168
|
-
|
|
169
|
-
const bins = [] as {
|
|
170
|
-
refbase?: string
|
|
171
|
-
total: number
|
|
172
|
-
all: number
|
|
173
|
-
ref: number
|
|
174
|
-
'-1': 0
|
|
175
|
-
'0': 0
|
|
176
|
-
'1': 0
|
|
177
|
-
lowqual: BinType
|
|
178
|
-
cov: BinType
|
|
179
|
-
delskips: BinType
|
|
180
|
-
noncov: BinType
|
|
181
|
-
}[]
|
|
182
|
-
|
|
183
|
-
for (let i = 0; i < features.length; i++) {
|
|
184
|
-
const feature = features[i]
|
|
185
|
-
const fstart = feature.get('start')
|
|
186
|
-
const fend = feature.get('end')
|
|
187
|
-
const fstrand = feature.get('strand') as -1 | 0 | 1
|
|
188
|
-
|
|
189
|
-
for (let j = fstart; j < fend + 1; j++) {
|
|
190
|
-
const i = j - region.start
|
|
191
|
-
if (i >= 0 && i < binMax) {
|
|
192
|
-
if (bins[i] === undefined) {
|
|
193
|
-
bins[i] = {
|
|
194
|
-
total: 0,
|
|
195
|
-
all: 0,
|
|
196
|
-
ref: 0,
|
|
197
|
-
'-1': 0,
|
|
198
|
-
'0': 0,
|
|
199
|
-
'1': 0,
|
|
200
|
-
lowqual: {} as BinType,
|
|
201
|
-
cov: {} as BinType,
|
|
202
|
-
delskips: {} as BinType,
|
|
203
|
-
noncov: {} as BinType,
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
if (j !== fend) {
|
|
207
|
-
bins[i].total++
|
|
208
|
-
bins[i].all++
|
|
209
|
-
bins[i].ref++
|
|
210
|
-
bins[i][fstrand]++
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
if (colorBy?.type === 'modifications') {
|
|
216
|
-
const seq = feature.get('seq') as string
|
|
217
|
-
const mm = (getTagAlt(feature, 'MM', 'Mm') as string) || ''
|
|
218
|
-
const ops = parseCigar(feature.get('CIGAR'))
|
|
219
|
-
const fend = feature.get('end')
|
|
220
|
-
|
|
221
|
-
getModificationPositions(mm, seq, fstrand).forEach(
|
|
222
|
-
({ type, positions }) => {
|
|
223
|
-
const mod = `mod_${type}`
|
|
224
|
-
for (const pos of getNextRefPos(ops, positions)) {
|
|
225
|
-
const epos = pos + fstart - region.start
|
|
226
|
-
if (epos >= 0 && epos < bins.length && pos + fstart < fend) {
|
|
227
|
-
const bin = bins[epos]
|
|
228
|
-
if (bin) {
|
|
229
|
-
inc(bin, fstrand, 'cov', mod)
|
|
230
|
-
} else {
|
|
231
|
-
console.warn(
|
|
232
|
-
'Undefined position in modifications snpcoverage encountered',
|
|
233
|
-
)
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
},
|
|
238
|
-
)
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
// methylation based coloring takes into account both reference
|
|
242
|
-
// sequence CpG detection and reads
|
|
243
|
-
else if (colorBy?.type === 'methylation') {
|
|
244
|
-
if (!regionSeq) {
|
|
245
|
-
throw new Error(
|
|
246
|
-
'no region sequence detected, need sequenceAdapter configuration',
|
|
247
|
-
)
|
|
248
|
-
}
|
|
249
|
-
const seq = feature.get('seq')
|
|
250
|
-
const mm = getTagAlt(feature, 'MM', 'Mm') || ''
|
|
251
|
-
const methBins = new Array(region.end - region.start).fill(0)
|
|
252
|
-
const ops = parseCigar(feature.get('CIGAR'))
|
|
253
|
-
|
|
254
|
-
getModificationPositions(mm, seq, fstrand).forEach(
|
|
255
|
-
({ type, positions }) => {
|
|
256
|
-
// we are processing methylation
|
|
257
|
-
if (type === 'm') {
|
|
258
|
-
for (const pos of getNextRefPos(ops, positions)) {
|
|
259
|
-
const epos = pos + fstart - region.start
|
|
260
|
-
if (epos >= 0 && epos < methBins.length) {
|
|
261
|
-
methBins[epos] = 1
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
},
|
|
266
|
-
)
|
|
267
|
-
|
|
268
|
-
for (let j = fstart; j < fend; j++) {
|
|
269
|
-
const i = j - region.start
|
|
270
|
-
if (i >= 0 && i < bins.length - 1) {
|
|
271
|
-
const l1 = regionSeq[i].toLowerCase()
|
|
272
|
-
const l2 = regionSeq[i + 1].toLowerCase()
|
|
273
|
-
const bin = bins[i]
|
|
274
|
-
const bin1 = bins[i + 1]
|
|
275
|
-
|
|
276
|
-
// color
|
|
277
|
-
if (l1 === 'c' && l2 === 'g') {
|
|
278
|
-
if (methBins[i] || methBins[i + 1]) {
|
|
279
|
-
inc(bin, fstrand, 'cov', 'meth')
|
|
280
|
-
inc(bin1, fstrand, 'cov', 'meth')
|
|
281
|
-
bins[i].ref--
|
|
282
|
-
bins[i][fstrand]--
|
|
283
|
-
bins[i + 1].ref--
|
|
284
|
-
bins[i + 1][fstrand]--
|
|
285
|
-
} else {
|
|
286
|
-
inc(bin, fstrand, 'cov', 'unmeth')
|
|
287
|
-
inc(bin1, fstrand, 'cov', 'unmeth')
|
|
288
|
-
bins[i].ref--
|
|
289
|
-
bins[i][fstrand]--
|
|
290
|
-
bins[i + 1].ref--
|
|
291
|
-
bins[i + 1][fstrand]--
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
// normal SNP based coloring
|
|
299
|
-
const mismatches = (feature.get('mismatches') as Mismatch[]) || []
|
|
300
|
-
const colorSNPs =
|
|
301
|
-
colorBy?.type !== 'modifications' && colorBy?.type !== 'methylation'
|
|
302
|
-
|
|
303
|
-
for (let i = 0; i < mismatches.length; i++) {
|
|
304
|
-
const mismatch = mismatches[i]
|
|
305
|
-
const mstart = fstart + mismatch.start
|
|
306
|
-
const mlen = mismatchLen(mismatch)
|
|
307
|
-
const mend = mstart + mlen
|
|
308
|
-
for (let j = mstart; j < mstart + mlen; j++) {
|
|
309
|
-
const epos = j - region.start
|
|
310
|
-
if (epos >= 0 && epos < bins.length) {
|
|
311
|
-
const bin = bins[epos]
|
|
312
|
-
const { base, type } = mismatch
|
|
313
|
-
const interbase = isInterbase(type)
|
|
314
|
-
if (!interbase) {
|
|
315
|
-
bin.ref--
|
|
316
|
-
bin[fstrand]--
|
|
317
|
-
} else {
|
|
318
|
-
inc(bin, fstrand, 'noncov', type)
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
if (type === 'deletion' || type === 'skip') {
|
|
322
|
-
inc(bin, fstrand, 'delskips', type)
|
|
323
|
-
bin.total--
|
|
324
|
-
} else if (!interbase && colorSNPs) {
|
|
325
|
-
inc(bin, fstrand, 'cov', base)
|
|
326
|
-
bin.refbase = mismatch.altbase
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
if (mismatch.type === 'skip') {
|
|
332
|
-
const hash = `${mstart}_${mend}_${fstrand}`
|
|
333
|
-
if (skipmap[hash] === undefined) {
|
|
334
|
-
skipmap[hash] = {
|
|
335
|
-
feature: feature,
|
|
336
|
-
start: mstart,
|
|
337
|
-
end: mend,
|
|
338
|
-
strand: fstrand,
|
|
339
|
-
xs: getTag(feature, 'XS') || getTag(feature, 'TS'),
|
|
340
|
-
score: 0,
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
skipmap[hash].score++
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
return { bins, skipmap }
|
|
349
|
-
}
|
|
350
106
|
}
|
|
351
107
|
|
|
352
108
|
const { capabilities } = SNPCoverageAdapter
|
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
import { ConfigurationSchema } from '@jbrowse/core/configuration'
|
|
2
|
-
import PluginManager from '@jbrowse/core/PluginManager'
|
|
3
2
|
|
|
4
3
|
/**
|
|
5
4
|
* #config SNPCoverageAdapter
|
|
6
5
|
*/
|
|
7
6
|
function x() {} // eslint-disable-line @typescript-eslint/no-unused-vars
|
|
8
7
|
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
8
|
+
const configSchema = ConfigurationSchema(
|
|
9
|
+
'SNPCoverageAdapter',
|
|
10
|
+
{
|
|
11
|
+
/**
|
|
12
|
+
* #slot
|
|
13
|
+
* normally refers to a BAM or CRAM adapter
|
|
14
|
+
*/
|
|
15
|
+
subadapter: {
|
|
16
|
+
type: 'frozen',
|
|
17
|
+
defaultValue: null,
|
|
18
18
|
},
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
},
|
|
20
|
+
{ explicitlyTyped: true },
|
|
21
|
+
)
|
|
21
22
|
|
|
22
|
-
export default
|
|
23
|
+
export default configSchema
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import { AugmentedRegion as Region } from '@jbrowse/core/util/types'
|
|
2
|
+
import { Feature } from '@jbrowse/core/util/simpleFeature'
|
|
3
|
+
import { getTag, getTagAlt, shouldFetchReferenceSequence } from '../util'
|
|
4
|
+
import {
|
|
5
|
+
parseCigar,
|
|
6
|
+
getNextRefPos,
|
|
7
|
+
getModificationPositions,
|
|
8
|
+
Mismatch,
|
|
9
|
+
} from '../BamAdapter/MismatchParser'
|
|
10
|
+
|
|
11
|
+
function mismatchLen(mismatch: Mismatch) {
|
|
12
|
+
return !isInterbase(mismatch.type) ? mismatch.length : 1
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function isInterbase(type: string) {
|
|
16
|
+
return type === 'softclip' || type === 'hardclip' || type === 'insertion'
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
20
|
+
function inc(bin: any, strand: number, type: string, field: string) {
|
|
21
|
+
let thisBin = bin[type][field]
|
|
22
|
+
if (thisBin === undefined) {
|
|
23
|
+
thisBin = bin[type][field] = {
|
|
24
|
+
total: 0,
|
|
25
|
+
'-1': 0,
|
|
26
|
+
'0': 0,
|
|
27
|
+
'1': 0,
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
thisBin.total++
|
|
31
|
+
thisBin[strand]++
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export default async function generateCoverageBins(
|
|
35
|
+
features: Feature[],
|
|
36
|
+
region: Region,
|
|
37
|
+
opts: { bpPerPx?: number; colorBy?: { type: string; tag?: string } },
|
|
38
|
+
fetchSequence: (arg: Region) => Promise<string>,
|
|
39
|
+
) {
|
|
40
|
+
const { colorBy } = opts
|
|
41
|
+
const binMax = Math.ceil(region.end - region.start)
|
|
42
|
+
|
|
43
|
+
const skipmap = {} as {
|
|
44
|
+
[key: string]: {
|
|
45
|
+
score: number
|
|
46
|
+
feature: unknown
|
|
47
|
+
start: number
|
|
48
|
+
end: number
|
|
49
|
+
strand: number
|
|
50
|
+
xs: string
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// bins contain:
|
|
55
|
+
// - cov feature if they contribute to coverage
|
|
56
|
+
// - noncov are insertions/clip features that don't contribute to coverage
|
|
57
|
+
// - delskips deletions or introns that don't contribute to coverage
|
|
58
|
+
type BinType = { total: number; strands: { [key: string]: number } }
|
|
59
|
+
|
|
60
|
+
const regionSeq =
|
|
61
|
+
features.length && shouldFetchReferenceSequence(opts.colorBy?.type)
|
|
62
|
+
? await fetchSequence(region)
|
|
63
|
+
: undefined
|
|
64
|
+
|
|
65
|
+
const bins = [] as {
|
|
66
|
+
refbase?: string
|
|
67
|
+
total: number
|
|
68
|
+
all: number
|
|
69
|
+
ref: number
|
|
70
|
+
'-1': 0
|
|
71
|
+
'0': 0
|
|
72
|
+
'1': 0
|
|
73
|
+
lowqual: BinType
|
|
74
|
+
cov: BinType
|
|
75
|
+
delskips: BinType
|
|
76
|
+
noncov: BinType
|
|
77
|
+
}[]
|
|
78
|
+
|
|
79
|
+
for (let i = 0; i < features.length; i++) {
|
|
80
|
+
const feature = features[i]
|
|
81
|
+
const fstart = feature.get('start')
|
|
82
|
+
const fend = feature.get('end')
|
|
83
|
+
const fstrand = feature.get('strand') as -1 | 0 | 1
|
|
84
|
+
|
|
85
|
+
for (let j = fstart; j < fend + 1; j++) {
|
|
86
|
+
const i = j - region.start
|
|
87
|
+
if (i >= 0 && i < binMax) {
|
|
88
|
+
if (bins[i] === undefined) {
|
|
89
|
+
bins[i] = {
|
|
90
|
+
total: 0,
|
|
91
|
+
all: 0,
|
|
92
|
+
ref: 0,
|
|
93
|
+
'-1': 0,
|
|
94
|
+
'0': 0,
|
|
95
|
+
'1': 0,
|
|
96
|
+
lowqual: {} as BinType,
|
|
97
|
+
cov: {} as BinType,
|
|
98
|
+
delskips: {} as BinType,
|
|
99
|
+
noncov: {} as BinType,
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
if (j !== fend) {
|
|
103
|
+
bins[i].total++
|
|
104
|
+
bins[i].all++
|
|
105
|
+
bins[i].ref++
|
|
106
|
+
bins[i][fstrand]++
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (colorBy?.type === 'modifications') {
|
|
112
|
+
const seq = feature.get('seq') as string
|
|
113
|
+
const mm = (getTagAlt(feature, 'MM', 'Mm') as string) || ''
|
|
114
|
+
const ops = parseCigar(feature.get('CIGAR'))
|
|
115
|
+
const fend = feature.get('end')
|
|
116
|
+
|
|
117
|
+
getModificationPositions(mm, seq, fstrand).forEach(
|
|
118
|
+
({ type, positions }) => {
|
|
119
|
+
const mod = `mod_${type}`
|
|
120
|
+
for (const pos of getNextRefPos(ops, positions)) {
|
|
121
|
+
const epos = pos + fstart - region.start
|
|
122
|
+
if (epos >= 0 && epos < bins.length && pos + fstart < fend) {
|
|
123
|
+
const bin = bins[epos]
|
|
124
|
+
if (bin) {
|
|
125
|
+
inc(bin, fstrand, 'cov', mod)
|
|
126
|
+
} else {
|
|
127
|
+
console.warn(
|
|
128
|
+
'Undefined position in modifications snpcoverage encountered',
|
|
129
|
+
)
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// methylation based coloring takes into account both reference
|
|
138
|
+
// sequence CpG detection and reads
|
|
139
|
+
else if (colorBy?.type === 'methylation') {
|
|
140
|
+
if (!regionSeq) {
|
|
141
|
+
throw new Error(
|
|
142
|
+
'no region sequence detected, need sequenceAdapter configuration',
|
|
143
|
+
)
|
|
144
|
+
}
|
|
145
|
+
const seq = feature.get('seq')
|
|
146
|
+
const mm = getTagAlt(feature, 'MM', 'Mm') || ''
|
|
147
|
+
const methBins = new Array(region.end - region.start).fill(0)
|
|
148
|
+
const ops = parseCigar(feature.get('CIGAR'))
|
|
149
|
+
|
|
150
|
+
getModificationPositions(mm, seq, fstrand).forEach(
|
|
151
|
+
({ type, positions }) => {
|
|
152
|
+
// we are processing methylation
|
|
153
|
+
if (type === 'm') {
|
|
154
|
+
for (const pos of getNextRefPos(ops, positions)) {
|
|
155
|
+
const epos = pos + fstart - region.start
|
|
156
|
+
if (epos >= 0 && epos < methBins.length) {
|
|
157
|
+
methBins[epos] = 1
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
},
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
for (let j = fstart; j < fend; j++) {
|
|
165
|
+
const i = j - region.start
|
|
166
|
+
if (i >= 0 && i < bins.length - 1) {
|
|
167
|
+
const l1 = regionSeq[i].toLowerCase()
|
|
168
|
+
const l2 = regionSeq[i + 1].toLowerCase()
|
|
169
|
+
const bin = bins[i]
|
|
170
|
+
const bin1 = bins[i + 1]
|
|
171
|
+
|
|
172
|
+
// color
|
|
173
|
+
if (l1 === 'c' && l2 === 'g') {
|
|
174
|
+
if (methBins[i] || methBins[i + 1]) {
|
|
175
|
+
inc(bin, fstrand, 'cov', 'meth')
|
|
176
|
+
inc(bin1, fstrand, 'cov', 'meth')
|
|
177
|
+
bins[i].ref--
|
|
178
|
+
bins[i][fstrand]--
|
|
179
|
+
bins[i + 1].ref--
|
|
180
|
+
bins[i + 1][fstrand]--
|
|
181
|
+
} else {
|
|
182
|
+
inc(bin, fstrand, 'cov', 'unmeth')
|
|
183
|
+
inc(bin1, fstrand, 'cov', 'unmeth')
|
|
184
|
+
bins[i].ref--
|
|
185
|
+
bins[i][fstrand]--
|
|
186
|
+
bins[i + 1].ref--
|
|
187
|
+
bins[i + 1][fstrand]--
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// normal SNP based coloring
|
|
195
|
+
const mismatches = (feature.get('mismatches') as Mismatch[]) || []
|
|
196
|
+
const colorSNPs =
|
|
197
|
+
colorBy?.type !== 'modifications' && colorBy?.type !== 'methylation'
|
|
198
|
+
|
|
199
|
+
for (let i = 0; i < mismatches.length; i++) {
|
|
200
|
+
const mismatch = mismatches[i]
|
|
201
|
+
const mstart = fstart + mismatch.start
|
|
202
|
+
const mlen = mismatchLen(mismatch)
|
|
203
|
+
const mend = mstart + mlen
|
|
204
|
+
for (let j = mstart; j < mstart + mlen; j++) {
|
|
205
|
+
const epos = j - region.start
|
|
206
|
+
if (epos >= 0 && epos < bins.length) {
|
|
207
|
+
const bin = bins[epos]
|
|
208
|
+
const { base, type } = mismatch
|
|
209
|
+
const interbase = isInterbase(type)
|
|
210
|
+
if (!interbase) {
|
|
211
|
+
bin.ref--
|
|
212
|
+
bin[fstrand]--
|
|
213
|
+
} else {
|
|
214
|
+
inc(bin, fstrand, 'noncov', type)
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (type === 'deletion' || type === 'skip') {
|
|
218
|
+
inc(bin, fstrand, 'delskips', type)
|
|
219
|
+
bin.total--
|
|
220
|
+
} else if (!interbase && colorSNPs) {
|
|
221
|
+
inc(bin, fstrand, 'cov', base)
|
|
222
|
+
bin.refbase = mismatch.altbase
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
if (mismatch.type === 'skip') {
|
|
228
|
+
const hash = `${mstart}_${mend}_${fstrand}`
|
|
229
|
+
if (skipmap[hash] === undefined) {
|
|
230
|
+
skipmap[hash] = {
|
|
231
|
+
feature: feature,
|
|
232
|
+
start: mstart,
|
|
233
|
+
end: mend,
|
|
234
|
+
strand: fstrand,
|
|
235
|
+
xs: getTag(feature, 'XS') || getTag(feature, 'TS'),
|
|
236
|
+
score: 0,
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
skipmap[hash].score++
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
return { bins, skipmap }
|
|
245
|
+
}
|
|
@@ -1,23 +1,22 @@
|
|
|
1
1
|
import PluginManager from '@jbrowse/core/PluginManager'
|
|
2
2
|
import AdapterType from '@jbrowse/core/pluggableElementTypes/AdapterType'
|
|
3
|
-
import
|
|
3
|
+
import configSchema from './configSchema'
|
|
4
4
|
import { capabilities } from './SNPCoverageAdapter'
|
|
5
5
|
|
|
6
|
-
export default (pluginManager: PluginManager)
|
|
7
|
-
pluginManager.addAdapterType(
|
|
8
|
-
(
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
)
|
|
6
|
+
export default function (pluginManager: PluginManager) {
|
|
7
|
+
pluginManager.addAdapterType(() => {
|
|
8
|
+
return new AdapterType({
|
|
9
|
+
name: 'SNPCoverageAdapter',
|
|
10
|
+
adapterMetadata: {
|
|
11
|
+
category: null,
|
|
12
|
+
displayName: null,
|
|
13
|
+
hiddenFromGUI: true,
|
|
14
|
+
description: null,
|
|
15
|
+
},
|
|
16
|
+
getAdapterClass: () =>
|
|
17
|
+
import('./SNPCoverageAdapter').then(r => r.default),
|
|
18
|
+
configSchema,
|
|
19
|
+
adapterCapabilities: capabilities,
|
|
20
|
+
})
|
|
21
|
+
})
|
|
23
22
|
}
|
package/src/index.ts
CHANGED
|
@@ -12,7 +12,10 @@ import SNPCoverageRendererF from './SNPCoverageRenderer'
|
|
|
12
12
|
import PileupRendererF from './PileupRenderer'
|
|
13
13
|
import LinearAlignmentsDisplayF from './LinearAlignmentsDisplay'
|
|
14
14
|
import LinearSNPCoverageDisplayF from './LinearSNPCoverageDisplay'
|
|
15
|
-
import LinearPileupDisplayF
|
|
15
|
+
import LinearPileupDisplayF, {
|
|
16
|
+
linearPileupDisplayStateModelFactory,
|
|
17
|
+
linearPileupDisplayConfigSchemaFactory,
|
|
18
|
+
} from './LinearPileupDisplay'
|
|
16
19
|
import AlignmentsTrackF from './AlignmentsTrack'
|
|
17
20
|
import AlignmentsFeatureWidgetF from './AlignmentsFeatureDetail'
|
|
18
21
|
|
|
@@ -28,9 +31,6 @@ import {
|
|
|
28
31
|
TrackTypeGuesser,
|
|
29
32
|
} from '@jbrowse/core/util/tracks'
|
|
30
33
|
|
|
31
|
-
export { MismatchParser }
|
|
32
|
-
export type { LinearPileupDisplayModel }
|
|
33
|
-
|
|
34
34
|
export default class AlignmentsPlugin extends Plugin {
|
|
35
35
|
name = 'AlignmentsPlugin'
|
|
36
36
|
|
|
@@ -125,3 +125,10 @@ export default class AlignmentsPlugin extends Plugin {
|
|
|
125
125
|
)
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
|
+
|
|
129
|
+
export {
|
|
130
|
+
linearPileupDisplayConfigSchemaFactory,
|
|
131
|
+
linearPileupDisplayStateModelFactory,
|
|
132
|
+
MismatchParser,
|
|
133
|
+
}
|
|
134
|
+
export type { LinearPileupDisplayModel }
|