@jbrowse/plugin-gtf 1.7.4 → 1.7.7
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.
|
@@ -4,11 +4,18 @@ import IntervalTree from '@flatten-js/interval-tree';
|
|
|
4
4
|
import { Feature } from '@jbrowse/core/util/simpleFeature';
|
|
5
5
|
export default class extends BaseFeatureDataAdapter {
|
|
6
6
|
protected gtfFeatures?: Promise<{
|
|
7
|
-
|
|
7
|
+
feats: {
|
|
8
|
+
[key: string]: string[];
|
|
9
|
+
};
|
|
8
10
|
}>;
|
|
11
|
+
protected intervalTrees: {
|
|
12
|
+
[key: string]: Promise<IntervalTree | undefined> | undefined;
|
|
13
|
+
};
|
|
9
14
|
private loadDataP;
|
|
10
15
|
private loadData;
|
|
11
16
|
getRefNames(opts?: BaseOptions): Promise<string[]>;
|
|
17
|
+
private loadFeatureIntervalTreeHelper;
|
|
18
|
+
private loadFeatureIntervalTree;
|
|
12
19
|
getFeatures(query: NoAssemblyRegion, opts?: BaseOptions): import("rxjs").Observable<Feature>;
|
|
13
20
|
freeResources(): void;
|
|
14
21
|
}
|
|
@@ -27,8 +27,6 @@ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/de
|
|
|
27
27
|
|
|
28
28
|
var _BaseAdapter = require("@jbrowse/core/data_adapters/BaseAdapter");
|
|
29
29
|
|
|
30
|
-
var _configuration = require("@jbrowse/core/configuration");
|
|
31
|
-
|
|
32
30
|
var _io = require("@jbrowse/core/util/io");
|
|
33
31
|
|
|
34
32
|
var _rxjs = require("@jbrowse/core/util/rxjs");
|
|
@@ -67,6 +65,7 @@ var _default = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
|
|
|
67
65
|
|
|
68
66
|
_this = _super.call.apply(_super, [this].concat(args));
|
|
69
67
|
(0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "gtfFeatures", void 0);
|
|
68
|
+
(0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "intervalTrees", {});
|
|
70
69
|
return _this;
|
|
71
70
|
}
|
|
72
71
|
|
|
@@ -74,15 +73,13 @@ var _default = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
|
|
|
74
73
|
key: "loadDataP",
|
|
75
74
|
value: function () {
|
|
76
75
|
var _loadDataP = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee() {
|
|
77
|
-
var
|
|
78
|
-
|
|
79
|
-
var buffer, buf, data, feats, intervalTree;
|
|
76
|
+
var buffer, buf, data, lines, feats, i, refName;
|
|
80
77
|
return _regenerator.default.wrap(function _callee$(_context) {
|
|
81
78
|
while (1) {
|
|
82
79
|
switch (_context.prev = _context.next) {
|
|
83
80
|
case 0:
|
|
84
81
|
_context.next = 2;
|
|
85
|
-
return (0, _io.openLocation)(
|
|
82
|
+
return (0, _io.openLocation)(this.getConf('gtfLocation'), this.pluginManager).readFile();
|
|
86
83
|
|
|
87
84
|
case 2:
|
|
88
85
|
buffer = _context.sent;
|
|
@@ -117,32 +114,26 @@ var _default = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
|
|
|
117
114
|
data = new TextDecoder('utf8', {
|
|
118
115
|
fatal: true
|
|
119
116
|
}).decode(buf);
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
parseComments: false,
|
|
123
|
-
parseDirectives: false,
|
|
124
|
-
parseSequences: false
|
|
117
|
+
lines = data.split('\n').filter(function (f) {
|
|
118
|
+
return !!f && !f.startsWith('#');
|
|
125
119
|
});
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
});
|
|
131
|
-
}).reduce(function (acc, obj) {
|
|
132
|
-
var key = obj.get('refName');
|
|
120
|
+
feats = {};
|
|
121
|
+
|
|
122
|
+
for (i = 0; i < lines.length; i++) {
|
|
123
|
+
refName = lines[i].split('\t')[0];
|
|
133
124
|
|
|
134
|
-
if (!
|
|
135
|
-
|
|
125
|
+
if (!feats[refName]) {
|
|
126
|
+
feats[refName] = [];
|
|
136
127
|
}
|
|
137
128
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
129
|
+
feats[refName].push(lines[i]);
|
|
130
|
+
}
|
|
131
|
+
|
|
141
132
|
return _context.abrupt("return", {
|
|
142
|
-
|
|
133
|
+
feats: feats
|
|
143
134
|
});
|
|
144
135
|
|
|
145
|
-
case
|
|
136
|
+
case 18:
|
|
146
137
|
case "end":
|
|
147
138
|
return _context.stop();
|
|
148
139
|
}
|
|
@@ -160,7 +151,7 @@ var _default = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
|
|
|
160
151
|
key: "loadData",
|
|
161
152
|
value: function () {
|
|
162
153
|
var _loadData = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2() {
|
|
163
|
-
var
|
|
154
|
+
var _this2 = this;
|
|
164
155
|
|
|
165
156
|
return _regenerator.default.wrap(function _callee2$(_context2) {
|
|
166
157
|
while (1) {
|
|
@@ -168,7 +159,7 @@ var _default = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
|
|
|
168
159
|
case 0:
|
|
169
160
|
if (!this.gtfFeatures) {
|
|
170
161
|
this.gtfFeatures = this.loadDataP().catch(function (e) {
|
|
171
|
-
|
|
162
|
+
_this2.gtfFeatures = undefined;
|
|
172
163
|
throw e;
|
|
173
164
|
});
|
|
174
165
|
}
|
|
@@ -195,7 +186,7 @@ var _default = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
|
|
|
195
186
|
var _getRefNames = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee3() {
|
|
196
187
|
var opts,
|
|
197
188
|
_yield$this$loadData,
|
|
198
|
-
|
|
189
|
+
feats,
|
|
199
190
|
_args3 = arguments;
|
|
200
191
|
|
|
201
192
|
return _regenerator.default.wrap(function _callee3$(_context3) {
|
|
@@ -208,8 +199,8 @@ var _default = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
|
|
|
208
199
|
|
|
209
200
|
case 3:
|
|
210
201
|
_yield$this$loadData = _context3.sent;
|
|
211
|
-
|
|
212
|
-
return _context3.abrupt("return", Object.keys(
|
|
202
|
+
feats = _yield$this$loadData.feats;
|
|
203
|
+
return _context3.abrupt("return", Object.keys(feats));
|
|
213
204
|
|
|
214
205
|
case 6:
|
|
215
206
|
case "end":
|
|
@@ -225,49 +216,143 @@ var _default = /*#__PURE__*/function (_BaseFeatureDataAdapt) {
|
|
|
225
216
|
|
|
226
217
|
return getRefNames;
|
|
227
218
|
}()
|
|
219
|
+
}, {
|
|
220
|
+
key: "loadFeatureIntervalTreeHelper",
|
|
221
|
+
value: function () {
|
|
222
|
+
var _loadFeatureIntervalTreeHelper = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee4(refName) {
|
|
223
|
+
var _this3 = this;
|
|
224
|
+
|
|
225
|
+
var _yield$this$loadData2, feats, lines, data, intervalTree, ret, i, obj;
|
|
226
|
+
|
|
227
|
+
return _regenerator.default.wrap(function _callee4$(_context4) {
|
|
228
|
+
while (1) {
|
|
229
|
+
switch (_context4.prev = _context4.next) {
|
|
230
|
+
case 0:
|
|
231
|
+
_context4.next = 2;
|
|
232
|
+
return this.loadData();
|
|
233
|
+
|
|
234
|
+
case 2:
|
|
235
|
+
_yield$this$loadData2 = _context4.sent;
|
|
236
|
+
feats = _yield$this$loadData2.feats;
|
|
237
|
+
lines = feats[refName];
|
|
238
|
+
|
|
239
|
+
if (lines) {
|
|
240
|
+
_context4.next = 7;
|
|
241
|
+
break;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
return _context4.abrupt("return", undefined);
|
|
245
|
+
|
|
246
|
+
case 7:
|
|
247
|
+
data = _gtf.default.parseStringSync(lines.join('\n'), {
|
|
248
|
+
parseFeatures: true,
|
|
249
|
+
parseComments: false,
|
|
250
|
+
parseDirectives: false,
|
|
251
|
+
parseSequences: false
|
|
252
|
+
});
|
|
253
|
+
intervalTree = new _intervalTree.default();
|
|
254
|
+
ret = data.flat().map(function (f, i) {
|
|
255
|
+
return new _simpleFeature.default({
|
|
256
|
+
data: (0, _util.featureData)(f),
|
|
257
|
+
id: "".concat(_this3.id, "-offset-").concat(i)
|
|
258
|
+
});
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
for (i = 0; i < ret.length; i++) {
|
|
262
|
+
obj = ret[i];
|
|
263
|
+
intervalTree.insert([obj.get('start'), obj.get('end')], obj);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
return _context4.abrupt("return", intervalTree);
|
|
267
|
+
|
|
268
|
+
case 12:
|
|
269
|
+
case "end":
|
|
270
|
+
return _context4.stop();
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}, _callee4, this);
|
|
274
|
+
}));
|
|
275
|
+
|
|
276
|
+
function loadFeatureIntervalTreeHelper(_x) {
|
|
277
|
+
return _loadFeatureIntervalTreeHelper.apply(this, arguments);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
return loadFeatureIntervalTreeHelper;
|
|
281
|
+
}()
|
|
282
|
+
}, {
|
|
283
|
+
key: "loadFeatureIntervalTree",
|
|
284
|
+
value: function () {
|
|
285
|
+
var _loadFeatureIntervalTree = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee5(refName) {
|
|
286
|
+
var _this4 = this;
|
|
287
|
+
|
|
288
|
+
return _regenerator.default.wrap(function _callee5$(_context5) {
|
|
289
|
+
while (1) {
|
|
290
|
+
switch (_context5.prev = _context5.next) {
|
|
291
|
+
case 0:
|
|
292
|
+
if (!this.intervalTrees[refName]) {
|
|
293
|
+
this.intervalTrees[refName] = this.loadFeatureIntervalTreeHelper(refName).catch(function (e) {
|
|
294
|
+
_this4.intervalTrees[refName] = undefined;
|
|
295
|
+
throw e;
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
return _context5.abrupt("return", this.intervalTrees[refName]);
|
|
300
|
+
|
|
301
|
+
case 2:
|
|
302
|
+
case "end":
|
|
303
|
+
return _context5.stop();
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}, _callee5, this);
|
|
307
|
+
}));
|
|
308
|
+
|
|
309
|
+
function loadFeatureIntervalTree(_x2) {
|
|
310
|
+
return _loadFeatureIntervalTree.apply(this, arguments);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
return loadFeatureIntervalTree;
|
|
314
|
+
}()
|
|
228
315
|
}, {
|
|
229
316
|
key: "getFeatures",
|
|
230
317
|
value: function getFeatures(query) {
|
|
231
|
-
var
|
|
318
|
+
var _this5 = this;
|
|
232
319
|
|
|
233
320
|
var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
234
321
|
return (0, _rxjs.ObservableCreate)( /*#__PURE__*/function () {
|
|
235
|
-
var _ref = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function
|
|
236
|
-
var
|
|
237
|
-
|
|
238
|
-
return _regenerator.default.wrap(function _callee4$(_context4) {
|
|
322
|
+
var _ref = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee6(observer) {
|
|
323
|
+
var start, end, refName, intervalTree;
|
|
324
|
+
return _regenerator.default.wrap(function _callee6$(_context6) {
|
|
239
325
|
while (1) {
|
|
240
|
-
switch (
|
|
326
|
+
switch (_context6.prev = _context6.next) {
|
|
241
327
|
case 0:
|
|
242
|
-
|
|
328
|
+
_context6.prev = 0;
|
|
243
329
|
start = query.start, end = query.end, refName = query.refName;
|
|
244
|
-
|
|
245
|
-
return
|
|
330
|
+
_context6.next = 4;
|
|
331
|
+
return _this5.loadFeatureIntervalTree(refName);
|
|
246
332
|
|
|
247
333
|
case 4:
|
|
248
|
-
|
|
249
|
-
intervalTree
|
|
250
|
-
(_intervalTree$refName = intervalTree[refName]) === null || _intervalTree$refName === void 0 ? void 0 : _intervalTree$refName.search([start, end]).forEach(function (f) {
|
|
334
|
+
intervalTree = _context6.sent;
|
|
335
|
+
intervalTree === null || intervalTree === void 0 ? void 0 : intervalTree.search([start, end]).forEach(function (f) {
|
|
251
336
|
return observer.next(f);
|
|
252
337
|
});
|
|
253
338
|
observer.complete();
|
|
254
|
-
|
|
339
|
+
_context6.next = 12;
|
|
255
340
|
break;
|
|
256
341
|
|
|
257
|
-
case
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
observer.error(
|
|
342
|
+
case 9:
|
|
343
|
+
_context6.prev = 9;
|
|
344
|
+
_context6.t0 = _context6["catch"](0);
|
|
345
|
+
observer.error(_context6.t0);
|
|
261
346
|
|
|
262
|
-
case
|
|
347
|
+
case 12:
|
|
263
348
|
case "end":
|
|
264
|
-
return
|
|
349
|
+
return _context6.stop();
|
|
265
350
|
}
|
|
266
351
|
}
|
|
267
|
-
},
|
|
352
|
+
}, _callee6, null, [[0, 9]]);
|
|
268
353
|
}));
|
|
269
354
|
|
|
270
|
-
return function (
|
|
355
|
+
return function (_x3) {
|
|
271
356
|
return _ref.apply(this, arguments);
|
|
272
357
|
};
|
|
273
358
|
}(), opts.signal);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jbrowse/plugin-gtf",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.7",
|
|
4
4
|
"description": "JBrowse 2 gtf feature adapter",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jbrowse",
|
|
@@ -51,5 +51,5 @@
|
|
|
51
51
|
"publishConfig": {
|
|
52
52
|
"access": "public"
|
|
53
53
|
},
|
|
54
|
-
"gitHead": "
|
|
54
|
+
"gitHead": "2c26e04ae942c380bf2f5b79ef7a49cc32b7bfed"
|
|
55
55
|
}
|
|
@@ -3,13 +3,11 @@ import {
|
|
|
3
3
|
BaseOptions,
|
|
4
4
|
} from '@jbrowse/core/data_adapters/BaseAdapter'
|
|
5
5
|
import { NoAssemblyRegion } from '@jbrowse/core/util/types'
|
|
6
|
-
import { readConfObject } from '@jbrowse/core/configuration'
|
|
7
6
|
import { openLocation } from '@jbrowse/core/util/io'
|
|
8
7
|
import { ObservableCreate } from '@jbrowse/core/util/rxjs'
|
|
9
8
|
import IntervalTree from '@flatten-js/interval-tree'
|
|
10
9
|
import SimpleFeature, { Feature } from '@jbrowse/core/util/simpleFeature'
|
|
11
10
|
import { unzip } from '@gmod/bgzf-filehandle'
|
|
12
|
-
|
|
13
11
|
import gtf from '@gmod/gtf'
|
|
14
12
|
import { FeatureLoc, featureData } from '../util'
|
|
15
13
|
function isGzip(buf: Buffer) {
|
|
@@ -18,12 +16,16 @@ function isGzip(buf: Buffer) {
|
|
|
18
16
|
|
|
19
17
|
export default class extends BaseFeatureDataAdapter {
|
|
20
18
|
protected gtfFeatures?: Promise<{
|
|
21
|
-
|
|
19
|
+
feats: { [key: string]: string[] }
|
|
22
20
|
}>
|
|
23
21
|
|
|
22
|
+
protected intervalTrees: {
|
|
23
|
+
[key: string]: Promise<IntervalTree | undefined> | undefined
|
|
24
|
+
} = {}
|
|
25
|
+
|
|
24
26
|
private async loadDataP() {
|
|
25
27
|
const buffer = await openLocation(
|
|
26
|
-
|
|
28
|
+
this.getConf('gtfLocation'),
|
|
27
29
|
this.pluginManager,
|
|
28
30
|
).readFile()
|
|
29
31
|
|
|
@@ -33,31 +35,18 @@ export default class extends BaseFeatureDataAdapter {
|
|
|
33
35
|
throw new Error('Data exceeds maximum string length (512MB)')
|
|
34
36
|
}
|
|
35
37
|
const data = new TextDecoder('utf8', { fatal: true }).decode(buf)
|
|
36
|
-
const feats = gtf.parseStringSync(data, {
|
|
37
|
-
parseFeatures: true,
|
|
38
|
-
parseComments: false,
|
|
39
|
-
parseDirectives: false,
|
|
40
|
-
parseSequences: false,
|
|
41
|
-
}) as FeatureLoc[][]
|
|
42
38
|
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
if (!acc[key]) {
|
|
55
|
-
acc[key] = new IntervalTree()
|
|
56
|
-
}
|
|
57
|
-
acc[key].insert([obj.get('start'), obj.get('end')], obj)
|
|
58
|
-
return acc
|
|
59
|
-
}, {} as Record<string, IntervalTree>)
|
|
60
|
-
return { intervalTree }
|
|
39
|
+
const lines = data.split('\n').filter(f => !!f && !f.startsWith('#'))
|
|
40
|
+
const feats = {} as { [key: string]: string[] }
|
|
41
|
+
for (let i = 0; i < lines.length; i++) {
|
|
42
|
+
const refName = lines[i].split('\t')[0]
|
|
43
|
+
if (!feats[refName]) {
|
|
44
|
+
feats[refName] = []
|
|
45
|
+
}
|
|
46
|
+
feats[refName].push(lines[i])
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return { feats }
|
|
61
50
|
}
|
|
62
51
|
|
|
63
52
|
private async loadData() {
|
|
@@ -72,18 +61,57 @@ export default class extends BaseFeatureDataAdapter {
|
|
|
72
61
|
}
|
|
73
62
|
|
|
74
63
|
public async getRefNames(opts: BaseOptions = {}) {
|
|
75
|
-
const {
|
|
76
|
-
return Object.keys(
|
|
64
|
+
const { feats } = await this.loadData()
|
|
65
|
+
return Object.keys(feats)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
private async loadFeatureIntervalTreeHelper(refName: string) {
|
|
69
|
+
const { feats } = await this.loadData()
|
|
70
|
+
const lines = feats[refName]
|
|
71
|
+
if (!lines) {
|
|
72
|
+
return undefined
|
|
73
|
+
}
|
|
74
|
+
const data = gtf.parseStringSync(lines.join('\n'), {
|
|
75
|
+
parseFeatures: true,
|
|
76
|
+
parseComments: false,
|
|
77
|
+
parseDirectives: false,
|
|
78
|
+
parseSequences: false,
|
|
79
|
+
}) as FeatureLoc[][]
|
|
80
|
+
|
|
81
|
+
const intervalTree = new IntervalTree()
|
|
82
|
+
const ret = data.flat().map(
|
|
83
|
+
(f, i) =>
|
|
84
|
+
new SimpleFeature({
|
|
85
|
+
data: featureData(f),
|
|
86
|
+
id: `${this.id}-offset-${i}`,
|
|
87
|
+
}),
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
for (let i = 0; i < ret.length; i++) {
|
|
91
|
+
const obj = ret[i]
|
|
92
|
+
intervalTree.insert([obj.get('start'), obj.get('end')], obj)
|
|
93
|
+
}
|
|
94
|
+
return intervalTree
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
private async loadFeatureIntervalTree(refName: string) {
|
|
98
|
+
if (!this.intervalTrees[refName]) {
|
|
99
|
+
this.intervalTrees[refName] = this.loadFeatureIntervalTreeHelper(
|
|
100
|
+
refName,
|
|
101
|
+
).catch(e => {
|
|
102
|
+
this.intervalTrees[refName] = undefined
|
|
103
|
+
throw e
|
|
104
|
+
})
|
|
105
|
+
}
|
|
106
|
+
return this.intervalTrees[refName]
|
|
77
107
|
}
|
|
78
108
|
|
|
79
109
|
public getFeatures(query: NoAssemblyRegion, opts: BaseOptions = {}) {
|
|
80
110
|
return ObservableCreate<Feature>(async observer => {
|
|
81
111
|
try {
|
|
82
112
|
const { start, end, refName } = query
|
|
83
|
-
const
|
|
84
|
-
intervalTree[
|
|
85
|
-
?.search([start, end])
|
|
86
|
-
.forEach(f => observer.next(f))
|
|
113
|
+
const intervalTree = await this.loadFeatureIntervalTree(refName)
|
|
114
|
+
intervalTree?.search([start, end]).forEach(f => observer.next(f))
|
|
87
115
|
observer.complete()
|
|
88
116
|
} catch (e) {
|
|
89
117
|
observer.error(e)
|