@jbrowse/plugin-alignments 1.6.5 → 1.6.8
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/index.d.ts +1 -1
- package/dist/BamAdapter/BamSlightlyLazyFeature.d.ts +2 -10
- package/dist/BamAdapter/MismatchParser.d.ts +3 -5
- package/dist/BamAdapter/configSchema.d.ts +1 -1
- package/dist/CramAdapter/CramSlightlyLazyFeature.d.ts +1 -2
- package/dist/CramAdapter/configSchema.d.ts +1 -1
- package/dist/HtsgetBamAdapter/configSchema.d.ts +1 -1
- package/dist/LinearAlignmentsDisplay/models/configSchema.d.ts +1 -1
- package/dist/LinearAlignmentsDisplay/models/model.d.ts +1 -1
- package/dist/LinearPileupDisplay/configSchema.d.ts +1 -1
- package/dist/LinearSNPCoverageDisplay/components/Tooltip.d.ts +1 -1
- package/dist/LinearSNPCoverageDisplay/models/configSchema.d.ts +1 -1
- package/dist/LinearSNPCoverageDisplay/models/model.d.ts +2 -2
- package/dist/PileupRenderer/PileupRenderer.d.ts +20 -6
- package/dist/PileupRenderer/configSchema.d.ts +1 -1
- package/dist/SNPCoverageAdapter/SNPCoverageAdapter.d.ts +3 -11
- package/dist/SNPCoverageAdapter/configSchema.d.ts +1 -1
- package/dist/SNPCoverageRenderer/SNPCoverageRenderer.d.ts +1 -1
- package/dist/SNPCoverageRenderer/configSchema.d.ts +1 -1
- package/dist/SNPCoverageRenderer/index.d.ts +1 -1
- package/dist/plugin-alignments.cjs.development.js +795 -682
- package/dist/plugin-alignments.cjs.development.js.map +1 -1
- package/dist/plugin-alignments.cjs.production.min.js +1 -1
- package/dist/plugin-alignments.cjs.production.min.js.map +1 -1
- package/dist/plugin-alignments.esm.js +797 -684
- package/dist/plugin-alignments.esm.js.map +1 -1
- package/dist/util.d.ts +4 -0
- package/package.json +4 -4
- package/src/AlignmentsFeatureDetail/AlignmentsFeatureDetail.tsx +23 -14
- package/src/BamAdapter/BamAdapter.ts +10 -7
- package/src/BamAdapter/BamSlightlyLazyFeature.ts +11 -75
- package/src/BamAdapter/MismatchParser.test.ts +53 -297
- package/src/BamAdapter/MismatchParser.ts +54 -116
- package/src/BamAdapter/configSchema.ts +0 -4
- package/src/CramAdapter/CramSlightlyLazyFeature.ts +3 -10
- package/src/LinearAlignmentsDisplay/components/AlignmentsDisplay.tsx +38 -30
- package/src/LinearAlignmentsDisplay/models/model.tsx +10 -9
- package/src/LinearPileupDisplay/components/ColorByModifications.tsx +76 -80
- package/src/LinearPileupDisplay/components/ColorByTag.tsx +24 -23
- package/src/LinearPileupDisplay/components/FilterByTag.tsx +73 -68
- package/src/LinearPileupDisplay/components/SetFeatureHeight.tsx +28 -26
- package/src/LinearPileupDisplay/components/SetMaxHeight.tsx +24 -13
- package/src/LinearPileupDisplay/components/SortByTag.tsx +29 -21
- package/src/LinearPileupDisplay/model.ts +12 -6
- package/src/LinearSNPCoverageDisplay/components/Tooltip.tsx +5 -3
- package/src/LinearSNPCoverageDisplay/models/configSchema.ts +4 -5
- package/src/PileupRenderer/PileupRenderer.tsx +202 -70
- package/src/PileupRenderer/components/PileupRendering.tsx +5 -3
- package/src/SNPCoverageAdapter/SNPCoverageAdapter.ts +192 -237
- package/src/SNPCoverageRenderer/SNPCoverageRenderer.ts +91 -60
- package/src/SNPCoverageRenderer/configSchema.js +1 -1
- package/src/util.ts +25 -0
|
@@ -4,12 +4,15 @@ import {
|
|
|
4
4
|
} from '@jbrowse/core/data_adapters/BaseAdapter'
|
|
5
5
|
import { AugmentedRegion as Region } from '@jbrowse/core/util/types'
|
|
6
6
|
import SimpleFeature, { Feature } from '@jbrowse/core/util/simpleFeature'
|
|
7
|
-
import { readConfObject } from '@jbrowse/core/configuration'
|
|
8
7
|
import SerializableFilterChain from '@jbrowse/core/pluggableElementTypes/renderers/util/serializableFilterChain'
|
|
9
8
|
import { ObservableCreate } from '@jbrowse/core/util/rxjs'
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
|
|
9
|
+
import { toArray } from 'rxjs/operators'
|
|
10
|
+
import {
|
|
11
|
+
getTag,
|
|
12
|
+
getTagAlt,
|
|
13
|
+
fetchSequence,
|
|
14
|
+
shouldFetchReferenceSequence,
|
|
15
|
+
} from '../util'
|
|
13
16
|
import {
|
|
14
17
|
parseCigar,
|
|
15
18
|
getNextRefPos,
|
|
@@ -48,11 +51,8 @@ function dec(bin: any, strand: number, type: string, field: string) {
|
|
|
48
51
|
|
|
49
52
|
export default class SNPCoverageAdapter extends BaseFeatureDataAdapter {
|
|
50
53
|
protected async configure() {
|
|
51
|
-
const subadapterConfig =
|
|
52
|
-
const sequenceConf =
|
|
53
|
-
'subadapter',
|
|
54
|
-
'sequenceAdapter',
|
|
55
|
-
])
|
|
54
|
+
const subadapterConfig = this.getConf('subadapter')
|
|
55
|
+
const sequenceConf = this.getConf(['subadapter', 'sequenceAdapter'])
|
|
56
56
|
const dataAdapter = await this.getSubAdapter?.(subadapterConfig)
|
|
57
57
|
|
|
58
58
|
const sequenceAdapter = sequenceConf
|
|
@@ -71,37 +71,47 @@ export default class SNPCoverageAdapter extends BaseFeatureDataAdapter {
|
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
+
async fetchSequence(region: Region) {
|
|
75
|
+
const { sequenceAdapter } = await this.configure()
|
|
76
|
+
if (!sequenceAdapter) {
|
|
77
|
+
return undefined
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return fetchSequence(region, sequenceAdapter)
|
|
81
|
+
}
|
|
82
|
+
|
|
74
83
|
getFeatures(region: Region, opts: SNPCoverageOptions = {}) {
|
|
75
84
|
return ObservableCreate<Feature>(async observer => {
|
|
76
85
|
const { subadapter } = await this.configure()
|
|
77
|
-
let
|
|
86
|
+
let feats = await subadapter
|
|
87
|
+
.getFeatures(region, opts)
|
|
88
|
+
.pipe(toArray())
|
|
89
|
+
.toPromise()
|
|
78
90
|
|
|
79
91
|
if (opts.filters) {
|
|
80
92
|
const { filters } = opts
|
|
81
|
-
|
|
93
|
+
feats = feats.filter(f => filters.passes(f, opts))
|
|
82
94
|
}
|
|
83
95
|
|
|
84
96
|
const { bins, skipmap } = await this.generateCoverageBins(
|
|
85
|
-
|
|
97
|
+
feats,
|
|
86
98
|
region,
|
|
87
99
|
opts,
|
|
88
100
|
)
|
|
89
101
|
|
|
90
102
|
bins.forEach((bin, index) => {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
)
|
|
104
|
-
}
|
|
103
|
+
observer.next(
|
|
104
|
+
new SimpleFeature({
|
|
105
|
+
id: `${this.id}-${region.start}-${index}`,
|
|
106
|
+
data: {
|
|
107
|
+
score: bin.total,
|
|
108
|
+
snpinfo: bin,
|
|
109
|
+
start: region.start + index,
|
|
110
|
+
end: region.start + index + 1,
|
|
111
|
+
refName: region.refName,
|
|
112
|
+
},
|
|
113
|
+
}),
|
|
114
|
+
)
|
|
105
115
|
})
|
|
106
116
|
|
|
107
117
|
// make fake features from the coverage
|
|
@@ -137,22 +147,12 @@ export default class SNPCoverageAdapter extends BaseFeatureDataAdapter {
|
|
|
137
147
|
|
|
138
148
|
freeResources(/* { region } */): void {}
|
|
139
149
|
|
|
140
|
-
/**
|
|
141
|
-
* Generates coverage bins from features which details
|
|
142
|
-
* the reference, mismatches, strands, and coverage info
|
|
143
|
-
* @param features - Features of region to be passed in
|
|
144
|
-
* @param region - Region
|
|
145
|
-
* @param bpPerPx - base pairs per pixel
|
|
146
|
-
* @returns Array of nested frequency tables
|
|
147
|
-
*/
|
|
148
150
|
async generateCoverageBins(
|
|
149
|
-
features:
|
|
151
|
+
features: Feature[],
|
|
150
152
|
region: Region,
|
|
151
153
|
opts: { bpPerPx?: number; colorBy?: { type: string; tag?: string } },
|
|
152
154
|
) {
|
|
153
155
|
const { colorBy } = opts
|
|
154
|
-
const { sequenceAdapter } = await this.configure()
|
|
155
|
-
const { originalRefName, refName, start, end } = region
|
|
156
156
|
const binMax = Math.ceil(region.end - region.start)
|
|
157
157
|
|
|
158
158
|
const skipmap = {} as {
|
|
@@ -166,221 +166,176 @@ export default class SNPCoverageAdapter extends BaseFeatureDataAdapter {
|
|
|
166
166
|
}
|
|
167
167
|
}
|
|
168
168
|
|
|
169
|
-
// bins contain
|
|
170
|
-
//
|
|
171
|
-
//
|
|
172
|
-
//
|
|
169
|
+
// bins contain:
|
|
170
|
+
// - cov feature if they contribute to coverage
|
|
171
|
+
// - noncov are insertions/clip features that don't contribute to coverage
|
|
172
|
+
// - delskips deletions or introns that don't contribute to coverage
|
|
173
173
|
type BinType = { total: number; strands: { [key: string]: number } }
|
|
174
174
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
175
|
+
const regionSeq =
|
|
176
|
+
features.length && shouldFetchReferenceSequence(opts.colorBy?.type)
|
|
177
|
+
? await this.fetchSequence(region)
|
|
178
|
+
: undefined
|
|
179
|
+
|
|
180
|
+
const bins = [] as {
|
|
181
|
+
total: number
|
|
182
|
+
lowqual: BinType
|
|
183
|
+
cov: BinType
|
|
184
|
+
delskips: BinType
|
|
185
|
+
noncov: BinType
|
|
186
|
+
ref: BinType
|
|
187
|
+
}[]
|
|
188
|
+
|
|
189
|
+
for (let i = 0; i < features.length; i++) {
|
|
190
|
+
const feature = features[i]
|
|
191
|
+
const ops = parseCigar(feature.get('CIGAR'))
|
|
192
|
+
const fstart = feature.get('start')
|
|
193
|
+
const fend = feature.get('end')
|
|
194
|
+
const fstrand = feature.get('strand')
|
|
195
|
+
|
|
196
|
+
for (let j = fstart; j < fend; j++) {
|
|
197
|
+
const i = j - region.start
|
|
198
|
+
if (i >= 0 && i < binMax) {
|
|
199
|
+
const bin = bins[i] || {
|
|
200
|
+
total: 0,
|
|
201
|
+
lowqual: {} as BinType,
|
|
202
|
+
cov: {} as BinType,
|
|
203
|
+
delskips: {} as BinType,
|
|
204
|
+
noncov: {} as BinType,
|
|
205
|
+
ref: {} as BinType,
|
|
206
|
+
}
|
|
207
|
+
if (j !== fend) {
|
|
208
|
+
bin.total++
|
|
209
|
+
inc(bin, fstrand, 'ref', 'ref')
|
|
210
|
+
}
|
|
211
|
+
bins[i] = bin
|
|
212
|
+
}
|
|
213
|
+
}
|
|
190
214
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
const
|
|
198
|
-
const
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
if (i >= 0 && i < binMax) {
|
|
204
|
-
const bin = bins[i] || {
|
|
205
|
-
total: 0,
|
|
206
|
-
lowqual: {} as BinType,
|
|
207
|
-
cov: {} as BinType,
|
|
208
|
-
delskips: {} as BinType,
|
|
209
|
-
noncov: {} as BinType,
|
|
210
|
-
ref: {} as BinType,
|
|
211
|
-
}
|
|
212
|
-
bin.total++
|
|
213
|
-
inc(bin, fstrand, 'ref', 'ref')
|
|
214
|
-
bins[i] = bin
|
|
215
|
+
if (colorBy?.type === 'modifications') {
|
|
216
|
+
const seq = feature.get('seq') as string
|
|
217
|
+
const mm = (getTagAlt(feature, 'MM', 'Mm') as string) || ''
|
|
218
|
+
|
|
219
|
+
getModificationPositions(mm, seq, fstrand).forEach(
|
|
220
|
+
({ type, positions }) => {
|
|
221
|
+
const mod = `mod_${type}`
|
|
222
|
+
for (const pos of getNextRefPos(ops, positions)) {
|
|
223
|
+
const epos = pos + fstart - region.start
|
|
224
|
+
if (epos >= 0 && epos < bins.length && pos + fstart < fend) {
|
|
225
|
+
const bin = bins[epos]
|
|
226
|
+
inc(bin, fstrand, 'cov', mod)
|
|
215
227
|
}
|
|
216
228
|
}
|
|
229
|
+
},
|
|
230
|
+
)
|
|
231
|
+
}
|
|
217
232
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
const epos = pos + fstart - region.start
|
|
241
|
-
if (
|
|
242
|
-
epos >= 0 &&
|
|
243
|
-
epos < bins.length &&
|
|
244
|
-
pos + fstart < fend
|
|
245
|
-
) {
|
|
246
|
-
const bin = bins[epos]
|
|
247
|
-
if (probabilities[probIndex] > 0.5) {
|
|
248
|
-
inc(bin, fstrand, 'cov', mod)
|
|
249
|
-
} else {
|
|
250
|
-
inc(bin, fstrand, 'lowqual', mod)
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
probIndex++
|
|
254
|
-
}
|
|
255
|
-
},
|
|
256
|
-
)
|
|
233
|
+
// methylation based coloring takes into account both reference
|
|
234
|
+
// sequence CpG detection and reads
|
|
235
|
+
else if (colorBy?.type === 'methylation') {
|
|
236
|
+
if (!regionSeq) {
|
|
237
|
+
throw new Error(
|
|
238
|
+
'no region sequence detected, need sequenceAdapter configuration',
|
|
239
|
+
)
|
|
240
|
+
}
|
|
241
|
+
const seq = feature.get('seq')
|
|
242
|
+
const mm = getTagAlt(feature, 'MM', 'Mm') || ''
|
|
243
|
+
const methBins = new Array(region.end - region.start).fill(0)
|
|
244
|
+
|
|
245
|
+
getModificationPositions(mm, seq, fstrand).forEach(
|
|
246
|
+
({ type, positions }) => {
|
|
247
|
+
// we are processing methylation
|
|
248
|
+
if (type === 'm') {
|
|
249
|
+
for (const pos of getNextRefPos(ops, positions)) {
|
|
250
|
+
const epos = pos + fstart - region.start
|
|
251
|
+
if (epos >= 0 && epos < methBins.length) {
|
|
252
|
+
methBins[epos] = 1
|
|
253
|
+
}
|
|
254
|
+
}
|
|
257
255
|
}
|
|
256
|
+
},
|
|
257
|
+
)
|
|
258
258
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
(
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
},
|
|
283
|
-
)
|
|
284
|
-
|
|
285
|
-
for (let j = fstart; j < fend; j++) {
|
|
286
|
-
const i = j - region.start
|
|
287
|
-
if (i >= 0 && i < bins.length - 1) {
|
|
288
|
-
const l1 = regionSeq[i].toLowerCase()
|
|
289
|
-
const l2 = regionSeq[i + 1].toLowerCase()
|
|
290
|
-
const bin = bins[i]
|
|
291
|
-
const bin1 = bins[i + 1]
|
|
292
|
-
|
|
293
|
-
// color
|
|
294
|
-
if (l1 === 'c' && l2 === 'g') {
|
|
295
|
-
if (methBins[i] || methBins[i + 1]) {
|
|
296
|
-
inc(bin, fstrand, 'cov', 'meth')
|
|
297
|
-
inc(bin1, fstrand, 'cov', 'meth')
|
|
298
|
-
dec(bin, fstrand, 'ref', 'ref')
|
|
299
|
-
dec(bin1, fstrand, 'ref', 'ref')
|
|
300
|
-
} else {
|
|
301
|
-
inc(bin, fstrand, 'cov', 'unmeth')
|
|
302
|
-
inc(bin1, fstrand, 'cov', 'unmeth')
|
|
303
|
-
dec(bin, fstrand, 'ref', 'ref')
|
|
304
|
-
dec(bin1, fstrand, 'ref', 'ref')
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
}
|
|
259
|
+
for (let j = fstart; j < fend; j++) {
|
|
260
|
+
const i = j - region.start
|
|
261
|
+
if (i >= 0 && i < bins.length - 1) {
|
|
262
|
+
const l1 = regionSeq[i].toLowerCase()
|
|
263
|
+
const l2 = regionSeq[i + 1].toLowerCase()
|
|
264
|
+
const bin = bins[i]
|
|
265
|
+
const bin1 = bins[i + 1]
|
|
266
|
+
|
|
267
|
+
// color
|
|
268
|
+
if (l1 === 'c' && l2 === 'g') {
|
|
269
|
+
if (methBins[i] || methBins[i + 1]) {
|
|
270
|
+
inc(bin, fstrand, 'cov', 'meth')
|
|
271
|
+
inc(bin1, fstrand, 'cov', 'meth')
|
|
272
|
+
dec(bin, fstrand, 'ref', 'ref')
|
|
273
|
+
dec(bin1, fstrand, 'ref', 'ref')
|
|
274
|
+
} else {
|
|
275
|
+
inc(bin, fstrand, 'cov', 'unmeth')
|
|
276
|
+
inc(bin1, fstrand, 'cov', 'unmeth')
|
|
277
|
+
dec(bin, fstrand, 'ref', 'ref')
|
|
278
|
+
dec(bin1, fstrand, 'ref', 'ref')
|
|
308
279
|
}
|
|
309
280
|
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
310
284
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
const { base, type } = mismatch
|
|
330
|
-
const interbase = isInterbase(type)
|
|
331
|
-
if (!interbase) {
|
|
332
|
-
dec(bin, fstrand, 'ref', 'ref')
|
|
333
|
-
} else {
|
|
334
|
-
inc(bin, fstrand, 'noncov', type)
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
if (type === 'deletion' || type === 'skip') {
|
|
338
|
-
inc(bin, fstrand, 'delskips', type)
|
|
339
|
-
bin.total--
|
|
340
|
-
} else if (!interbase) {
|
|
341
|
-
inc(bin, fstrand, 'cov', base)
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
}
|
|
285
|
+
// normal SNP based coloring
|
|
286
|
+
else {
|
|
287
|
+
const mismatches = feature.get('mismatches') as Mismatch[] | undefined
|
|
288
|
+
|
|
289
|
+
if (mismatches) {
|
|
290
|
+
for (let i = 0; i < mismatches.length; i++) {
|
|
291
|
+
const mismatch = mismatches[i]
|
|
292
|
+
const mstart = fstart + mismatch.start
|
|
293
|
+
for (let j = mstart; j < mstart + mismatchLen(mismatch); j++) {
|
|
294
|
+
const epos = j - region.start
|
|
295
|
+
if (epos >= 0 && epos < bins.length) {
|
|
296
|
+
const bin = bins[epos]
|
|
297
|
+
const { base, type } = mismatch
|
|
298
|
+
const interbase = isInterbase(type)
|
|
299
|
+
if (!interbase) {
|
|
300
|
+
dec(bin, fstrand, 'ref', 'ref')
|
|
301
|
+
} else {
|
|
302
|
+
inc(bin, fstrand, 'noncov', type)
|
|
345
303
|
}
|
|
346
304
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
.
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
const strand = feature.get('strand')
|
|
354
|
-
const hash = `${start}_${end}_${strand}`
|
|
355
|
-
if (!skipmap[hash]) {
|
|
356
|
-
skipmap[hash] = {
|
|
357
|
-
feature: feature,
|
|
358
|
-
start,
|
|
359
|
-
end,
|
|
360
|
-
strand,
|
|
361
|
-
xs: getTag(feature, 'XS') || getTag(feature, 'TS'),
|
|
362
|
-
score: 1,
|
|
363
|
-
}
|
|
364
|
-
} else {
|
|
365
|
-
skipmap[hash].score++
|
|
366
|
-
}
|
|
367
|
-
})
|
|
305
|
+
if (type === 'deletion' || type === 'skip') {
|
|
306
|
+
inc(bin, fstrand, 'delskips', type)
|
|
307
|
+
bin.total--
|
|
308
|
+
} else if (!interbase) {
|
|
309
|
+
inc(bin, fstrand, 'cov', base)
|
|
310
|
+
}
|
|
368
311
|
}
|
|
369
312
|
}
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
mismatches
|
|
316
|
+
.filter(mismatch => mismatch.type === 'skip')
|
|
317
|
+
.forEach(mismatch => {
|
|
318
|
+
const mstart = feature.get('start') + mismatch.start
|
|
319
|
+
const start = mstart
|
|
320
|
+
const end = mstart + mismatch.length
|
|
321
|
+
const strand = feature.get('strand')
|
|
322
|
+
const hash = `${start}_${end}_${strand}`
|
|
323
|
+
if (!skipmap[hash]) {
|
|
324
|
+
skipmap[hash] = {
|
|
325
|
+
feature: feature,
|
|
326
|
+
start,
|
|
327
|
+
end,
|
|
328
|
+
strand,
|
|
329
|
+
xs: getTag(feature, 'XS') || getTag(feature, 'TS'),
|
|
330
|
+
score: 1,
|
|
331
|
+
}
|
|
332
|
+
} else {
|
|
333
|
+
skipmap[hash].score++
|
|
334
|
+
}
|
|
335
|
+
})
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
384
339
|
|
|
385
340
|
return { bins, skipmap }
|
|
386
341
|
}
|