@jbrowse/plugin-bed 1.5.9 → 1.6.3
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/BedTabixAdapter/BedTabixAdapter.d.ts +2 -3
- package/dist/BigBedAdapter/BigBedAdapter.d.ts +33 -11
- package/dist/plugin-bed.cjs.development.js +136 -110
- package/dist/plugin-bed.cjs.development.js.map +1 -1
- package/dist/plugin-bed.cjs.production.min.js +1 -1
- package/dist/plugin-bed.cjs.production.min.js.map +1 -1
- package/dist/plugin-bed.esm.js +136 -110
- package/dist/plugin-bed.esm.js.map +1 -1
- package/package.json +2 -2
- package/src/BedTabixAdapter/BedTabixAdapter.ts +2 -3
- package/src/BigBedAdapter/BigBedAdapter.test.ts +0 -2
- package/src/BigBedAdapter/BigBedAdapter.ts +82 -92
- package/src/index.ts +9 -5
|
@@ -5,17 +5,17 @@ import {
|
|
|
5
5
|
BaseFeatureDataAdapter,
|
|
6
6
|
BaseOptions,
|
|
7
7
|
} from '@jbrowse/core/data_adapters/BaseAdapter'
|
|
8
|
-
import { Region
|
|
8
|
+
import { Region } from '@jbrowse/core/util/types'
|
|
9
9
|
import { openLocation } from '@jbrowse/core/util/io'
|
|
10
10
|
import { ObservableCreate } from '@jbrowse/core/util/rxjs'
|
|
11
11
|
import SimpleFeature, { Feature } from '@jbrowse/core/util/simpleFeature'
|
|
12
12
|
import { map, mergeAll } from 'rxjs/operators'
|
|
13
13
|
import { readConfObject } from '@jbrowse/core/configuration'
|
|
14
|
-
import { Instance } from 'mobx-state-tree'
|
|
15
|
-
import configSchema from './configSchema'
|
|
16
14
|
import { ucscProcessedTranscript } from '../util'
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
|
|
16
|
+
function isUCSC(f: Feature) {
|
|
17
|
+
return f.get('thickStart') && f.get('blockCount') && f.get('strand') !== 0
|
|
18
|
+
}
|
|
19
19
|
|
|
20
20
|
interface BEDFeature {
|
|
21
21
|
chrom: string
|
|
@@ -26,50 +26,51 @@ interface BEDFeature {
|
|
|
26
26
|
|
|
27
27
|
interface Parser {
|
|
28
28
|
parseLine: (line: string, opts: { uniqueId: string | number }) => BEDFeature
|
|
29
|
+
autoSql: { fields: { name: string; comment: string }[] }
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
export default class BigBedAdapter extends BaseFeatureDataAdapter {
|
|
32
|
-
private bigbed: BigBed
|
|
33
|
+
private cached?: Promise<{ bigbed: BigBed; header: any; parser: Parser }>
|
|
33
34
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
) {
|
|
41
|
-
super(config, getSubAdapter, pluginManager)
|
|
42
|
-
const bigBedLocation = readConfObject(
|
|
43
|
-
config,
|
|
44
|
-
'bigBedLocation',
|
|
45
|
-
) as FileLocation
|
|
46
|
-
this.bigbed = new BigBed({
|
|
47
|
-
filehandle: openLocation(bigBedLocation, this.pluginManager),
|
|
35
|
+
public async configurePre(opts?: BaseOptions) {
|
|
36
|
+
const bigbed = new BigBed({
|
|
37
|
+
filehandle: openLocation(
|
|
38
|
+
readConfObject(this.config, 'bigBedLocation'),
|
|
39
|
+
this.pluginManager,
|
|
40
|
+
),
|
|
48
41
|
})
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
.then(({ autoSql }: { autoSql: string }) => new BED({ autoSql }))
|
|
42
|
+
const header = await bigbed.getHeader(opts)
|
|
43
|
+
const parser = new BED({ autoSql: header.autoSql }) as Parser
|
|
44
|
+
return { bigbed, header, parser }
|
|
53
45
|
}
|
|
54
46
|
|
|
55
|
-
public async
|
|
56
|
-
|
|
47
|
+
public async configure(opts?: BaseOptions) {
|
|
48
|
+
if (!this.cached) {
|
|
49
|
+
this.cached = this.configurePre(opts).catch(e => {
|
|
50
|
+
this.cached = undefined
|
|
51
|
+
throw e
|
|
52
|
+
})
|
|
53
|
+
}
|
|
54
|
+
return this.cached
|
|
57
55
|
}
|
|
58
56
|
|
|
59
|
-
async
|
|
60
|
-
const {
|
|
61
|
-
|
|
62
|
-
const { autoSql } = await this.parser
|
|
63
|
-
const { fields, ...rest } = autoSql
|
|
64
|
-
const f = Object.fromEntries(
|
|
65
|
-
// @ts-ignore
|
|
66
|
-
fields.map(({ name, comment }) => [name, comment]),
|
|
67
|
-
)
|
|
68
|
-
return { version, fileType, autoSql: { ...rest }, fields: f }
|
|
57
|
+
public async getRefNames(opts?: BaseOptions) {
|
|
58
|
+
const { header } = await this.configure(opts)
|
|
59
|
+
return Object.keys(header.refsByName)
|
|
69
60
|
}
|
|
70
61
|
|
|
71
|
-
|
|
72
|
-
|
|
62
|
+
async getHeader(opts?: BaseOptions) {
|
|
63
|
+
const { parser, header } = await this.configure(opts)
|
|
64
|
+
const { version, fileType } = header
|
|
65
|
+
const { fields, ...rest } = parser.autoSql
|
|
66
|
+
return {
|
|
67
|
+
version,
|
|
68
|
+
fileType,
|
|
69
|
+
autoSql: { ...rest },
|
|
70
|
+
fields: Object.fromEntries(
|
|
71
|
+
fields.map(({ name, comment }) => [name, comment]),
|
|
72
|
+
),
|
|
73
|
+
}
|
|
73
74
|
}
|
|
74
75
|
|
|
75
76
|
public getFeatures(region: Region, opts: BaseOptions = {}) {
|
|
@@ -77,70 +78,59 @@ export default class BigBedAdapter extends BaseFeatureDataAdapter {
|
|
|
77
78
|
const { signal } = opts
|
|
78
79
|
return ObservableCreate<Feature>(async observer => {
|
|
79
80
|
try {
|
|
80
|
-
const parser = await this.
|
|
81
|
-
const ob = await
|
|
81
|
+
const { parser, bigbed } = await this.configure(opts)
|
|
82
|
+
const ob = await bigbed.getFeatureStream(refName, start, end, {
|
|
82
83
|
signal,
|
|
83
84
|
basesPerSpan: end - start,
|
|
84
85
|
})
|
|
85
86
|
ob.pipe(
|
|
86
87
|
mergeAll(),
|
|
87
|
-
map(
|
|
88
|
-
(
|
|
89
|
-
start
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
const data = parser.parseLine(
|
|
95
|
-
`${refName}\t${r.start}\t${r.end}\t${r.rest}`,
|
|
96
|
-
{
|
|
97
|
-
uniqueId: r.uniqueId as string,
|
|
98
|
-
},
|
|
99
|
-
)
|
|
88
|
+
map(r => {
|
|
89
|
+
const data = parser.parseLine(
|
|
90
|
+
`${refName}\t${r.start}\t${r.end}\t${r.rest}`,
|
|
91
|
+
{
|
|
92
|
+
uniqueId: r.uniqueId as string,
|
|
93
|
+
},
|
|
94
|
+
)
|
|
100
95
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
96
|
+
const { blockCount, blockSizes, blockStarts, chromStarts } = data
|
|
97
|
+
if (blockCount) {
|
|
98
|
+
const starts = chromStarts || blockStarts || []
|
|
99
|
+
const sizes = blockSizes
|
|
100
|
+
const blocksOffset = r.start
|
|
101
|
+
data.subfeatures = []
|
|
107
102
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
if (r.uniqueId === undefined) {
|
|
120
|
-
throw new Error('invalid bbi feature')
|
|
103
|
+
for (let b = 0; b < blockCount; b += 1) {
|
|
104
|
+
const bmin = (starts[b] || 0) + blocksOffset
|
|
105
|
+
const bmax = bmin + (sizes[b] || 0)
|
|
106
|
+
data.subfeatures.push({
|
|
107
|
+
uniqueId: `${r.uniqueId}-${b}`,
|
|
108
|
+
start: bmin,
|
|
109
|
+
end: bmax,
|
|
110
|
+
type: 'block',
|
|
111
|
+
})
|
|
121
112
|
}
|
|
122
|
-
|
|
113
|
+
}
|
|
114
|
+
if (r.uniqueId === undefined) {
|
|
115
|
+
throw new Error('invalid bbi feature')
|
|
116
|
+
}
|
|
117
|
+
const { chromStart, chromEnd, chrom, ...rest } = data
|
|
123
118
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
119
|
+
const f = new SimpleFeature({
|
|
120
|
+
id: `${this.id}-${r.uniqueId}`,
|
|
121
|
+
data: {
|
|
122
|
+
...rest,
|
|
123
|
+
start: r.start,
|
|
124
|
+
end: r.end,
|
|
125
|
+
refName,
|
|
126
|
+
},
|
|
127
|
+
})
|
|
133
128
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
f.get('strand') !== 0
|
|
140
|
-
? ucscProcessedTranscript(f)
|
|
141
|
-
: f
|
|
142
|
-
},
|
|
143
|
-
),
|
|
129
|
+
// collection of heuristics for suggesting that this feature
|
|
130
|
+
// should be converted to a gene, CNV bigbed has many gene like
|
|
131
|
+
// features including thickStart and blockCount but no strand
|
|
132
|
+
return isUCSC(f) ? ucscProcessedTranscript(f) : f
|
|
133
|
+
}),
|
|
144
134
|
).subscribe(observer)
|
|
145
135
|
} catch (e) {
|
|
146
136
|
observer.error(e)
|
package/src/index.ts
CHANGED
|
@@ -35,11 +35,15 @@ export default class BedPlugin extends Plugin {
|
|
|
35
35
|
const regexGuess = /\.(bb|bigbed)$/i
|
|
36
36
|
const adapterName = 'BigBedAdapter'
|
|
37
37
|
const fileName = getFileName(file)
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
38
|
+
const obj = {
|
|
39
|
+
type: adapterName,
|
|
40
|
+
bigBedLocation: file,
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (regexGuess.test(fileName) && !adapterHint) {
|
|
44
|
+
return obj
|
|
45
|
+
} else if (adapterHint === adapterName) {
|
|
46
|
+
return obj
|
|
43
47
|
}
|
|
44
48
|
return adapterGuesser(file, index, adapterHint)
|
|
45
49
|
}
|