@jbrowse/plugin-alignments 1.6.1 → 1.6.5

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jbrowse/plugin-alignments",
3
- "version": "1.6.1",
3
+ "version": "1.6.5",
4
4
  "description": "JBrowse 2 alignments adapters, tracks, etc.",
5
5
  "keywords": [
6
6
  "jbrowse",
@@ -35,10 +35,10 @@
35
35
  "useSrc": "node ../../scripts/useSrc.js"
36
36
  },
37
37
  "dependencies": {
38
- "@gmod/bam": "^1.1.11",
39
- "@gmod/cram": "^1.5.9",
38
+ "@gmod/bam": "^1.1.12",
39
+ "@gmod/cram": "^1.6.1",
40
40
  "@material-ui/icons": "^4.9.1",
41
- "abortable-promise-cache": "^1.1.3",
41
+ "abortable-promise-cache": "^1.5.0",
42
42
  "color": "^3.1.2",
43
43
  "copy-to-clipboard": "^3.3.1",
44
44
  "fast-deep-equal": "^3.1.3",
@@ -61,5 +61,5 @@
61
61
  "publishConfig": {
62
62
  "access": "public"
63
63
  },
64
- "gitHead": "d6ad1b8e7fbb00000f2ac87f463c82e9db12ea01"
64
+ "gitHead": "ab41f017840ffef09f5d60b008281cedaa5abe26"
65
65
  }
@@ -197,11 +197,10 @@ export default class BamAdapter extends BaseFeatureDataAdapter {
197
197
 
198
198
  async estimateRegionsStats(regions: Region[], opts?: BaseOptions) {
199
199
  const { bam } = await this.configure()
200
- // @ts-ignore
201
- const index = bam.index
202
200
  // this is a method to avoid calling on htsget adapters
203
- if (index.filehandle !== '?') {
204
- const bytes = await bytesForRegions(regions, index)
201
+ // @ts-ignore
202
+ if (bam.index.filehandle !== '?') {
203
+ const bytes = await bytesForRegions(regions, bam)
205
204
  const fetchSizeLimit = readConfObject(this.config, 'fetchSizeLimit')
206
205
  return { bytes, fetchSizeLimit }
207
206
  } else {
@@ -716,20 +716,21 @@ export default class PileupRenderer extends BoxRendererType {
716
716
  ctx.fillText(`(${mismatch.base})`, leftPx + 2, topPx + heightPx)
717
717
  }
718
718
  } else if (mismatch.type === 'skip') {
719
- // fix to avoid bad rendering
720
- // note that this was also related to chrome bug https://bugs.chromium.org/p/chro>
721
- // ref #1236
719
+ // fix to avoid bad rendering note that this was also related to chrome
720
+ // bug https://bugs.chromium.org/p/chromium/issues/detail?id=1131528
721
+ // also affected firefox ref #1236 #2750
722
722
  if (leftPx + widthPx > 0) {
723
723
  // make small exons more visible when zoomed far out
724
- ctx.clearRect(
725
- leftPx,
726
- topPx,
727
- widthPx - (bpPerPx > 10 ? 1.5 : 0),
728
- heightPx,
724
+ const adjustPx = widthPx - (bpPerPx > 10 ? 1.5 : 0)
725
+ ctx.clearRect(leftPx, topPx, adjustPx, heightPx)
726
+ ctx.fillStyle = '#333'
727
+ ctx.fillRect(
728
+ Math.max(0, leftPx),
729
+ topPx + heightPx / 2 - 1,
730
+ adjustPx + (leftPx < 0 ? leftPx : 0),
731
+ 2,
729
732
  )
730
733
  }
731
- ctx.fillStyle = '#333'
732
- ctx.fillRect(leftPx, topPx + heightPx / 2, widthPx, 2)
733
734
  }
734
735
  }
735
736
 
@@ -9,7 +9,7 @@ import SerializableFilterChain from '@jbrowse/core/pluggableElementTypes/rendere
9
9
  import { ObservableCreate } from '@jbrowse/core/util/rxjs'
10
10
  import { reduce, filter, toArray } from 'rxjs/operators'
11
11
  import { Observable } from 'rxjs'
12
- import { getTagAlt } from '../util'
12
+ import { getTag, getTagAlt } from '../util'
13
13
  import {
14
14
  parseCigar,
15
15
  getNextRefPos,
@@ -171,14 +171,6 @@ export default class SNPCoverageAdapter extends BaseFeatureDataAdapter {
171
171
  // delskips are elements that don't contribute to coverage, but should be
172
172
  // reported also (and are not interbase)
173
173
  type BinType = { total: number; strands: { [key: string]: number } }
174
- const initBins = Array.from({ length: binMax }, () => ({
175
- total: 0,
176
- lowqual: {} as BinType,
177
- cov: {} as BinType,
178
- delskips: {} as BinType,
179
- noncov: {} as BinType,
180
- ref: {} as BinType,
181
- }))
182
174
 
183
175
  // request an extra +1 on the end to get CpG crossing region boundary
184
176
  let regionSeq: string | undefined
@@ -189,7 +181,7 @@ export default class SNPCoverageAdapter extends BaseFeatureDataAdapter {
189
181
  refName: originalRefName || refName,
190
182
  start,
191
183
  end: end + 1,
192
- assemblyName: 'na',
184
+ assemblyName: region.assemblyName,
193
185
  })
194
186
  .pipe(toArray())
195
187
  .toPromise()
@@ -198,172 +190,195 @@ export default class SNPCoverageAdapter extends BaseFeatureDataAdapter {
198
190
 
199
191
  const bins = await features
200
192
  .pipe(
201
- reduce((bins, feature) => {
202
- const cigar = feature.get('CIGAR')
203
- const fstart = feature.get('start')
204
- const fend = feature.get('end')
205
- const fstrand = feature.get('strand')
206
- const cigarOps = parseCigar(cigar)
207
-
208
- for (let j = fstart; j < fend; j++) {
209
- const i = j - region.start
210
- if (i >= 0 && i < bins.length) {
211
- const bin = bins[i]
212
- bin.total++
213
- inc(bin, fstrand, 'ref', 'ref')
214
- }
215
- }
216
-
217
- if (colorBy?.type === 'modifications') {
218
- const seq = feature.get('seq')
219
- const mm = getTagAlt(feature, 'MM', 'Mm') || ''
193
+ reduce(
194
+ (bins, feature) => {
195
+ const cigar = feature.get('CIGAR')
196
+ const fstart = feature.get('start')
197
+ const fend = feature.get('end')
198
+ const fstrand = feature.get('strand')
199
+ const cigarOps = parseCigar(cigar)
220
200
 
221
- const ml =
222
- (getTagAlt(feature, 'ML', 'Ml') as number[] | string) || []
201
+ for (let j = fstart; j < fend; j++) {
202
+ const i = j - region.start
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
+ }
216
+ }
223
217
 
224
- const probabilities = ml
225
- ? (typeof ml === 'string' ? ml.split(',').map(e => +e) : ml).map(
226
- e => e / 255,
227
- )
228
- : (getTagAlt(feature, 'MP', 'Mp') as string)
229
- .split('')
230
- .map(s => s.charCodeAt(0) - 33)
231
- .map(elt => Math.min(1, elt / 50))
232
-
233
- let probIndex = 0
234
- getModificationPositions(mm, seq, fstrand).forEach(
235
- ({ type, positions }) => {
236
- const mod = `mod_${type}`
237
- for (const pos of getNextRefPos(cigarOps, positions)) {
238
- const epos = pos + fstart - region.start
239
- if (epos >= 0 && epos < bins.length && pos + fstart < fend) {
240
- const bin = bins[epos]
241
- if (probabilities[probIndex] > 0.5) {
242
- inc(bin, fstrand, 'cov', mod)
243
- } else {
244
- inc(bin, fstrand, 'lowqual', mod)
218
+ if (colorBy?.type === 'modifications') {
219
+ const seq = feature.get('seq')
220
+ const mm = getTagAlt(feature, 'MM', 'Mm') || ''
221
+
222
+ const ml =
223
+ (getTagAlt(feature, 'ML', 'Ml') as number[] | string) || []
224
+
225
+ const probabilities = ml
226
+ ? (typeof ml === 'string'
227
+ ? ml.split(',').map(e => +e)
228
+ : ml
229
+ ).map(e => e / 255)
230
+ : (getTagAlt(feature, 'MP', 'Mp') as string)
231
+ .split('')
232
+ .map(s => s.charCodeAt(0) - 33)
233
+ .map(elt => Math.min(1, elt / 50))
234
+
235
+ let probIndex = 0
236
+ getModificationPositions(mm, seq, fstrand).forEach(
237
+ ({ type, positions }) => {
238
+ const mod = `mod_${type}`
239
+ for (const pos of getNextRefPos(cigarOps, positions)) {
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
+ }
245
252
  }
253
+ probIndex++
246
254
  }
247
- probIndex++
248
- }
249
- },
250
- )
251
- }
252
-
253
- // methylation based coloring takes into account both reference
254
- // sequence CpG detection and reads
255
- else if (colorBy?.type === 'methylation') {
256
- if (!regionSeq) {
257
- throw new Error(
258
- 'no region sequence detected, need sequenceAdapter configuration',
255
+ },
259
256
  )
260
257
  }
261
- const seq = feature.get('seq')
262
- const mm = getTagAlt(feature, 'MM', 'Mm') || ''
263
- const methBins = new Array(region.end - region.start).fill(0)
264
-
265
- getModificationPositions(mm, seq, fstrand).forEach(
266
- ({ type, positions }) => {
267
- // we are processing methylation
268
- if (type === 'm') {
269
- for (const pos of getNextRefPos(cigarOps, positions)) {
270
- const epos = pos + fstart - region.start
271
- if (epos >= 0 && epos < methBins.length) {
272
- methBins[epos] = 1
258
+
259
+ // methylation based coloring takes into account both reference
260
+ // sequence CpG detection and reads
261
+ else if (colorBy?.type === 'methylation') {
262
+ if (!regionSeq) {
263
+ throw new Error(
264
+ 'no region sequence detected, need sequenceAdapter configuration',
265
+ )
266
+ }
267
+ const seq = feature.get('seq')
268
+ const mm = getTagAlt(feature, 'MM', 'Mm') || ''
269
+ const methBins = new Array(region.end - region.start).fill(0)
270
+
271
+ getModificationPositions(mm, seq, fstrand).forEach(
272
+ ({ type, positions }) => {
273
+ // we are processing methylation
274
+ if (type === 'm') {
275
+ for (const pos of getNextRefPos(cigarOps, positions)) {
276
+ const epos = pos + fstart - region.start
277
+ if (epos >= 0 && epos < methBins.length) {
278
+ methBins[epos] = 1
279
+ }
273
280
  }
274
281
  }
275
- }
276
- },
277
- )
282
+ },
283
+ )
278
284
 
279
- for (let j = fstart; j < fend; j++) {
280
- const i = j - region.start
281
- if (i >= 0 && i < bins.length - 1) {
282
- const l1 = regionSeq[i].toLowerCase()
283
- const l2 = regionSeq[i + 1].toLowerCase()
284
- const bin = bins[i]
285
- const bin1 = bins[i + 1]
286
-
287
- // color
288
- if (l1 === 'c' && l2 === 'g') {
289
- if (methBins[i] || methBins[i + 1]) {
290
- inc(bin, fstrand, 'cov', 'meth')
291
- inc(bin1, fstrand, 'cov', 'meth')
292
- dec(bin, fstrand, 'ref', 'ref')
293
- dec(bin1, fstrand, 'ref', 'ref')
294
- } else {
295
- inc(bin, fstrand, 'cov', 'unmeth')
296
- inc(bin1, fstrand, 'cov', 'unmeth')
297
- dec(bin, fstrand, 'ref', 'ref')
298
- dec(bin1, fstrand, 'ref', 'ref')
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
+ }
299
306
  }
300
307
  }
301
308
  }
302
309
  }
303
- }
304
-
305
- // normal SNP based coloring
306
- else {
307
- const mismatches = feature.get('mismatches') as
308
- | Mismatch[]
309
- | undefined
310
-
311
- if (mismatches) {
312
- for (let i = 0; i < mismatches.length; i++) {
313
- const mismatch = mismatches[i]
314
- const mstart = fstart + mismatch.start
315
- for (let j = mstart; j < mstart + mismatchLen(mismatch); j++) {
316
- const epos = j - region.start
317
- if (epos >= 0 && epos < bins.length) {
318
- const bin = bins[epos]
319
- const { base, type } = mismatch
320
- const interbase = isInterbase(type)
321
- if (!interbase) {
322
- dec(bin, fstrand, 'ref', 'ref')
323
- } else {
324
- inc(bin, fstrand, 'noncov', type)
325
- }
326
310
 
327
- if (type === 'deletion' || type === 'skip') {
328
- inc(bin, fstrand, 'delskips', type)
329
- bin.total--
330
- } else if (!interbase) {
331
- inc(bin, fstrand, 'cov', base)
311
+ // normal SNP based coloring
312
+ else {
313
+ const mismatches = feature.get('mismatches') as
314
+ | Mismatch[]
315
+ | undefined
316
+
317
+ if (mismatches) {
318
+ for (let i = 0; i < mismatches.length; i++) {
319
+ const mismatch = mismatches[i]
320
+ const mstart = fstart + mismatch.start
321
+ for (
322
+ let j = mstart;
323
+ j < mstart + mismatchLen(mismatch);
324
+ j++
325
+ ) {
326
+ const epos = j - region.start
327
+ if (epos >= 0 && epos < bins.length) {
328
+ const bin = bins[epos]
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
+ }
332
343
  }
333
344
  }
334
345
  }
335
- }
336
346
 
337
- mismatches
338
- .filter(mismatch => mismatch.type === 'skip')
339
- .forEach(mismatch => {
340
- const mstart = feature.get('start') + mismatch.start
341
- const start = mstart
342
- const end = mstart + mismatch.length
343
- const strand = feature.get('strand')
344
- const hash = `${start}_${end}_${strand}`
345
- if (!skipmap[hash]) {
346
- skipmap[hash] = {
347
- feature: feature,
348
- start,
349
- end,
350
- strand,
351
- xs:
352
- feature.get('xs') ||
353
- feature.get('ts') ||
354
- feature.get('tags').XS ||
355
- feature.get('tags').TS,
356
- score: 1,
347
+ mismatches
348
+ .filter(mismatch => mismatch.type === 'skip')
349
+ .forEach(mismatch => {
350
+ const mstart = feature.get('start') + mismatch.start
351
+ const start = mstart
352
+ const end = mstart + mismatch.length
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++
357
366
  }
358
- } else {
359
- skipmap[hash].score++
360
- }
361
- })
367
+ })
368
+ }
362
369
  }
363
- }
364
370
 
365
- return bins
366
- }, initBins),
371
+ return bins
372
+ },
373
+ [] as {
374
+ total: number
375
+ lowqual: BinType
376
+ cov: BinType
377
+ delskips: BinType
378
+ noncov: BinType
379
+ ref: BinType
380
+ }[],
381
+ ),
367
382
  )
368
383
  .toPromise()
369
384