@gmod/bbi 5.0.1 → 6.0.0
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/CHANGELOG.md +8 -0
- package/README.md +5 -5
- package/dist/bbi.d.ts +15 -16
- package/dist/bbi.js +195 -220
- package/dist/bbi.js.map +1 -1
- package/dist/bigbed.js +138 -159
- package/dist/bigbed.js.map +1 -1
- package/dist/bigwig.js +11 -21
- package/dist/bigwig.js.map +1 -1
- package/dist/block-view.d.ts +2 -3
- package/dist/block-view.js +190 -205
- package/dist/block-view.js.map +1 -1
- package/dist/unzip-pako.d.ts +1 -2
- package/dist/unzip-pako.js.map +1 -1
- package/dist/util.js +3 -14
- package/dist/util.js.map +1 -1
- package/esm/bbi.d.ts +15 -16
- package/esm/bbi.js +66 -70
- package/esm/bbi.js.map +1 -1
- package/esm/bigbed.js +47 -40
- package/esm/bigbed.js.map +1 -1
- package/esm/bigwig.js +3 -2
- package/esm/bigwig.js.map +1 -1
- package/esm/block-view.d.ts +2 -3
- package/esm/block-view.js +36 -41
- package/esm/block-view.js.map +1 -1
- package/esm/unzip-pako.d.ts +1 -2
- package/esm/unzip-pako.js.map +1 -1
- package/package.json +14 -18
- package/src/bbi.ts +78 -99
- package/src/bigbed.ts +47 -62
- package/src/bigwig.ts +2 -2
- package/src/block-view.ts +46 -57
- package/src/unzip-pako.ts +1 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
# [6.0.0](https://github.com/GMOD/bbi-js/compare/v5.0.2...v6.0.0) (2024-12-12)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
## [5.0.2](https://github.com/GMOD/bbi-js/compare/v5.0.1...v5.0.2) (2024-09-03)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
1
9
|
## [5.0.1](https://github.com/GMOD/bbi-js/compare/v5.0.0...v5.0.1) (2024-08-09)
|
|
2
10
|
|
|
3
11
|
|
package/README.md
CHANGED
|
@@ -21,13 +21,13 @@ const file = new BigWig({
|
|
|
21
21
|
})()
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
If using remotely, you can use it in combination with generic-
|
|
25
|
-
own implementation of something like generic-
|
|
26
|
-
https://github.com/GMOD/generic-
|
|
24
|
+
If using remotely, you can use it in combination with generic-filehandle2 or
|
|
25
|
+
your own implementation of something like generic-filehandle2
|
|
26
|
+
https://github.com/GMOD/generic-filehandle2/
|
|
27
27
|
|
|
28
28
|
```typescript
|
|
29
29
|
const { BigWig } = require('@gmod/bbi')
|
|
30
|
-
const { RemoteFile } = require('generic-
|
|
30
|
+
const { RemoteFile } = require('generic-filehandle2')
|
|
31
31
|
|
|
32
32
|
// if running in the browser or newer versions of node.js, RemoteFile will use
|
|
33
33
|
// the the global fetch
|
|
@@ -57,7 +57,7 @@ Accepts an object containing either
|
|
|
57
57
|
- url - path to a url
|
|
58
58
|
- filehandle - a filehandle instance that you can implement as a custom class
|
|
59
59
|
yourself. path and url are based on
|
|
60
|
-
https://www.npmjs.com/package/generic-
|
|
60
|
+
https://www.npmjs.com/package/generic-filehandle2 but by implementing a class
|
|
61
61
|
containing the Filehandle interface specified therein, you can pass it to this
|
|
62
62
|
module
|
|
63
63
|
|
package/dist/bbi.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { GenericFilehandle } from 'generic-
|
|
1
|
+
import { GenericFilehandle } from 'generic-filehandle2';
|
|
2
2
|
import { Observable } from 'rxjs';
|
|
3
3
|
import { BlockView } from './block-view';
|
|
4
|
-
interface ZoomLevel {
|
|
4
|
+
export interface ZoomLevel {
|
|
5
5
|
reductionLevel: number;
|
|
6
6
|
reserved: number;
|
|
7
7
|
dataOffset: number;
|
|
@@ -20,14 +20,14 @@ export interface Feature {
|
|
|
20
20
|
uniqueId?: string;
|
|
21
21
|
field?: number;
|
|
22
22
|
}
|
|
23
|
-
interface Statistics {
|
|
23
|
+
export interface Statistics {
|
|
24
24
|
scoreSum: number;
|
|
25
25
|
basesCovered: number;
|
|
26
26
|
scoreSumSquares: number;
|
|
27
27
|
scoreMin: number;
|
|
28
28
|
scoreMax: number;
|
|
29
29
|
}
|
|
30
|
-
interface RefInfo {
|
|
30
|
+
export interface RefInfo {
|
|
31
31
|
name: string;
|
|
32
32
|
id: number;
|
|
33
33
|
length: number;
|
|
@@ -48,7 +48,6 @@ export interface MainHeader {
|
|
|
48
48
|
uncompressBufSize: number;
|
|
49
49
|
chromTreeOffset: number;
|
|
50
50
|
extHeaderOffset: number;
|
|
51
|
-
isBigEndian: boolean;
|
|
52
51
|
fileType: string;
|
|
53
52
|
}
|
|
54
53
|
export interface Header extends MainHeader {
|
|
@@ -60,6 +59,10 @@ export interface RequestOptions {
|
|
|
60
59
|
headers?: Record<string, string>;
|
|
61
60
|
[key: string]: unknown;
|
|
62
61
|
}
|
|
62
|
+
export interface RequestOptions2 extends RequestOptions {
|
|
63
|
+
scale?: number;
|
|
64
|
+
basesPerSpan?: number;
|
|
65
|
+
}
|
|
63
66
|
export declare abstract class BBI {
|
|
64
67
|
protected bbi: GenericFilehandle;
|
|
65
68
|
private headerP?;
|
|
@@ -73,7 +76,6 @@ export declare abstract class BBI {
|
|
|
73
76
|
});
|
|
74
77
|
private _getHeader;
|
|
75
78
|
private _getMainHeader;
|
|
76
|
-
private _isBigEndian;
|
|
77
79
|
private _readChromTree;
|
|
78
80
|
protected getUnzoomedView(opts?: RequestOptions): Promise<BlockView>;
|
|
79
81
|
protected abstract getView(scale: number, opts?: RequestOptions): Promise<BlockView>;
|
|
@@ -81,17 +83,14 @@ export declare abstract class BBI {
|
|
|
81
83
|
* Gets features from a BigWig file
|
|
82
84
|
*
|
|
83
85
|
* @param refName - The chromosome name
|
|
86
|
+
*
|
|
84
87
|
* @param start - The start of a region
|
|
88
|
+
*
|
|
85
89
|
* @param end - The end of a region
|
|
86
|
-
*
|
|
90
|
+
*
|
|
91
|
+
* @param opts - An object containing basesPerSpan (e.g. pixels per basepair)
|
|
92
|
+
* or scale used to infer the zoomLevel to use
|
|
87
93
|
*/
|
|
88
|
-
getFeatureStream(refName: string, start: number, end: number, opts?:
|
|
89
|
-
|
|
90
|
-
basesPerSpan?: number;
|
|
91
|
-
}): Promise<Observable<Feature[]>>;
|
|
92
|
-
getFeatures(refName: string, start: number, end: number, opts?: RequestOptions & {
|
|
93
|
-
scale?: number;
|
|
94
|
-
basesPerSpan?: number;
|
|
95
|
-
}): Promise<Feature[]>;
|
|
94
|
+
getFeatureStream(refName: string, start: number, end: number, opts?: RequestOptions2): Promise<Observable<Feature[]>>;
|
|
95
|
+
getFeatures(refName: string, start: number, end: number, opts?: RequestOptions2): Promise<Feature[]>;
|
|
96
96
|
}
|
|
97
|
-
export {};
|
package/dist/bbi.js
CHANGED
|
@@ -1,17 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
3
|
exports.BBI = void 0;
|
|
13
|
-
const
|
|
14
|
-
const generic_filehandle_1 = require("generic-filehandle");
|
|
4
|
+
const generic_filehandle2_1 = require("generic-filehandle2");
|
|
15
5
|
const rxjs_1 = require("rxjs");
|
|
16
6
|
const operators_1 = require("rxjs/operators");
|
|
17
7
|
const block_view_1 = require("./block-view");
|
|
@@ -20,7 +10,7 @@ const BIG_BED_MAGIC = -2021002517;
|
|
|
20
10
|
class BBI {
|
|
21
11
|
getHeader(opts) {
|
|
22
12
|
if (!this.headerP) {
|
|
23
|
-
this.headerP = this._getHeader(opts).catch(e => {
|
|
13
|
+
this.headerP = this._getHeader(opts).catch((e) => {
|
|
24
14
|
this.headerP = undefined;
|
|
25
15
|
throw e;
|
|
26
16
|
});
|
|
@@ -28,8 +18,7 @@ class BBI {
|
|
|
28
18
|
return this.headerP;
|
|
29
19
|
}
|
|
30
20
|
/*
|
|
31
|
-
* @param filehandle - a filehandle from generic-
|
|
32
|
-
* something similar to the node10 fs.promises API
|
|
21
|
+
* @param filehandle - a filehandle from generic-filehandle2
|
|
33
22
|
*
|
|
34
23
|
* @param path - a Local file path as a string
|
|
35
24
|
*
|
|
@@ -45,250 +34,236 @@ class BBI {
|
|
|
45
34
|
this.bbi = filehandle;
|
|
46
35
|
}
|
|
47
36
|
else if (url) {
|
|
48
|
-
this.bbi = new
|
|
37
|
+
this.bbi = new generic_filehandle2_1.RemoteFile(url);
|
|
49
38
|
}
|
|
50
39
|
else if (path) {
|
|
51
|
-
this.bbi = new
|
|
40
|
+
this.bbi = new generic_filehandle2_1.LocalFile(path);
|
|
52
41
|
}
|
|
53
42
|
else {
|
|
54
43
|
throw new Error('no file given');
|
|
55
44
|
}
|
|
56
45
|
}
|
|
57
|
-
_getHeader(opts) {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
46
|
+
async _getHeader(opts) {
|
|
47
|
+
const header = await this._getMainHeader(opts);
|
|
48
|
+
const chroms = await this._readChromTree(header, opts);
|
|
49
|
+
return {
|
|
50
|
+
...header,
|
|
51
|
+
...chroms,
|
|
52
|
+
};
|
|
63
53
|
}
|
|
64
|
-
_getMainHeader(
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
54
|
+
async _getMainHeader(opts, requestSize = 2000) {
|
|
55
|
+
const b = await this.bbi.read(requestSize, 0, opts);
|
|
56
|
+
const dataView = new DataView(b.buffer, b.byteOffset, b.length);
|
|
57
|
+
const r1 = dataView.getInt32(0, true);
|
|
58
|
+
if (r1 !== BIG_WIG_MAGIC && r1 !== BIG_BED_MAGIC) {
|
|
59
|
+
throw new Error('not a BigWig/BigBed file');
|
|
60
|
+
}
|
|
61
|
+
let offset = 0;
|
|
62
|
+
const magic = dataView.getInt32(offset, true);
|
|
63
|
+
offset += 4;
|
|
64
|
+
const version = dataView.getUint16(offset, true);
|
|
65
|
+
offset += 2;
|
|
66
|
+
const numZoomLevels = dataView.getUint16(offset, true);
|
|
67
|
+
offset += 2;
|
|
68
|
+
const chromTreeOffset = Number(dataView.getBigUint64(offset, true));
|
|
69
|
+
offset += 8;
|
|
70
|
+
const unzoomedDataOffset = Number(dataView.getBigUint64(offset, true));
|
|
71
|
+
offset += 8;
|
|
72
|
+
const unzoomedIndexOffset = Number(dataView.getBigUint64(offset, true));
|
|
73
|
+
offset += 8;
|
|
74
|
+
const fieldCount = dataView.getUint16(offset, true);
|
|
75
|
+
offset += 2;
|
|
76
|
+
const definedFieldCount = dataView.getUint16(offset, true);
|
|
77
|
+
offset += 2;
|
|
78
|
+
const asOffset = Number(dataView.getBigUint64(offset, true));
|
|
79
|
+
offset += 8;
|
|
80
|
+
const totalSummaryOffset = Number(dataView.getBigUint64(offset, true));
|
|
81
|
+
offset += 8;
|
|
82
|
+
const uncompressBufSize = dataView.getUint32(offset, true);
|
|
83
|
+
offset += 4;
|
|
84
|
+
const extHeaderOffset = Number(dataView.getBigUint64(offset, true));
|
|
85
|
+
offset += 8;
|
|
86
|
+
const zoomLevels = [];
|
|
87
|
+
for (let i = 0; i < numZoomLevels; i++) {
|
|
88
|
+
const reductionLevel = dataView.getUint32(offset, true);
|
|
73
89
|
offset += 4;
|
|
74
|
-
const
|
|
75
|
-
offset +=
|
|
76
|
-
const
|
|
77
|
-
offset += 2;
|
|
78
|
-
const chromTreeOffset = Number(dataView.getBigUint64(offset, le));
|
|
90
|
+
const reserved = dataView.getUint32(offset, true);
|
|
91
|
+
offset += 4;
|
|
92
|
+
const dataOffset = Number(dataView.getBigUint64(offset, true));
|
|
79
93
|
offset += 8;
|
|
80
|
-
const
|
|
94
|
+
const indexOffset = Number(dataView.getBigUint64(offset, true));
|
|
81
95
|
offset += 8;
|
|
82
|
-
|
|
96
|
+
zoomLevels.push({ reductionLevel, reserved, dataOffset, indexOffset });
|
|
97
|
+
}
|
|
98
|
+
const fileType = magic === BIG_BED_MAGIC ? 'bigbed' : 'bigwig';
|
|
99
|
+
// refetch header if it is too large on first pass,
|
|
100
|
+
// 8*5 is the sizeof the totalSummary struct
|
|
101
|
+
if (asOffset > requestSize || totalSummaryOffset > requestSize - 8 * 5) {
|
|
102
|
+
return this._getMainHeader(opts, requestSize * 2);
|
|
103
|
+
}
|
|
104
|
+
let totalSummary;
|
|
105
|
+
if (totalSummaryOffset) {
|
|
106
|
+
const b2 = b.subarray(Number(totalSummaryOffset));
|
|
107
|
+
let offset = 0;
|
|
108
|
+
const dataView = new DataView(b2.buffer, b2.byteOffset, b2.length);
|
|
109
|
+
const basesCovered = Number(dataView.getBigUint64(offset, true));
|
|
83
110
|
offset += 8;
|
|
84
|
-
const
|
|
85
|
-
offset += 2;
|
|
86
|
-
const definedFieldCount = dataView.getUint16(offset, le);
|
|
87
|
-
offset += 2;
|
|
88
|
-
const asOffset = Number(dataView.getBigUint64(offset, le));
|
|
111
|
+
const scoreMin = dataView.getFloat64(offset, true);
|
|
89
112
|
offset += 8;
|
|
90
|
-
const
|
|
113
|
+
const scoreMax = dataView.getFloat64(offset, true);
|
|
91
114
|
offset += 8;
|
|
92
|
-
const
|
|
93
|
-
offset += 4;
|
|
94
|
-
const extHeaderOffset = Number(dataView.getBigUint64(offset, le));
|
|
115
|
+
const scoreSum = dataView.getFloat64(offset, true);
|
|
95
116
|
offset += 8;
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
const indexOffset = Number(dataView.getBigUint64(offset, le));
|
|
105
|
-
offset += 8;
|
|
106
|
-
zoomLevels.push({ reductionLevel, reserved, dataOffset, indexOffset });
|
|
107
|
-
}
|
|
108
|
-
const fileType = magic === BIG_BED_MAGIC ? 'bigbed' : 'bigwig';
|
|
109
|
-
// refetch header if it is too large on first pass,
|
|
110
|
-
// 8*5 is the sizeof the totalSummary struct
|
|
111
|
-
if (asOffset > requestSize || totalSummaryOffset > requestSize - 8 * 5) {
|
|
112
|
-
return this._getMainHeader(opts, requestSize * 2);
|
|
113
|
-
}
|
|
114
|
-
let totalSummary;
|
|
115
|
-
if (totalSummaryOffset) {
|
|
116
|
-
const b = buffer.subarray(Number(totalSummaryOffset));
|
|
117
|
-
let offset = 0;
|
|
118
|
-
const dataView = new DataView(b.buffer, b.byteOffset, b.length);
|
|
119
|
-
const basesCovered = Number(dataView.getBigUint64(offset, le));
|
|
120
|
-
offset += 8;
|
|
121
|
-
const scoreMin = dataView.getFloat64(offset, le);
|
|
122
|
-
offset += 8;
|
|
123
|
-
const scoreMax = dataView.getFloat64(offset, le);
|
|
124
|
-
offset += 8;
|
|
125
|
-
const scoreSum = dataView.getFloat64(offset, le);
|
|
126
|
-
offset += 8;
|
|
127
|
-
const scoreSumSquares = dataView.getFloat64(offset, le);
|
|
128
|
-
offset += 8;
|
|
129
|
-
totalSummary = {
|
|
130
|
-
scoreMin,
|
|
131
|
-
scoreMax,
|
|
132
|
-
scoreSum,
|
|
133
|
-
scoreSumSquares,
|
|
134
|
-
basesCovered,
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
else {
|
|
138
|
-
throw new Error('no stats');
|
|
139
|
-
}
|
|
140
|
-
return {
|
|
141
|
-
zoomLevels,
|
|
142
|
-
magic,
|
|
143
|
-
extHeaderOffset,
|
|
144
|
-
numZoomLevels,
|
|
145
|
-
fieldCount,
|
|
146
|
-
totalSummary,
|
|
147
|
-
definedFieldCount,
|
|
148
|
-
uncompressBufSize,
|
|
149
|
-
asOffset,
|
|
150
|
-
chromTreeOffset,
|
|
151
|
-
totalSummaryOffset,
|
|
152
|
-
unzoomedDataOffset,
|
|
153
|
-
unzoomedIndexOffset,
|
|
154
|
-
fileType,
|
|
155
|
-
version,
|
|
156
|
-
isBigEndian,
|
|
157
|
-
autoSql: asOffset
|
|
158
|
-
? buffer.subarray(asOffset, buffer.indexOf(0, asOffset)).toString()
|
|
159
|
-
: '',
|
|
117
|
+
const scoreSumSquares = dataView.getFloat64(offset, true);
|
|
118
|
+
offset += 8;
|
|
119
|
+
totalSummary = {
|
|
120
|
+
scoreMin,
|
|
121
|
+
scoreMax,
|
|
122
|
+
scoreSum,
|
|
123
|
+
scoreSumSquares,
|
|
124
|
+
basesCovered,
|
|
160
125
|
};
|
|
161
|
-
});
|
|
162
|
-
}
|
|
163
|
-
_isBigEndian(buffer) {
|
|
164
|
-
let ret = buffer.readInt32LE(0);
|
|
165
|
-
if (ret === BIG_WIG_MAGIC || ret === BIG_BED_MAGIC) {
|
|
166
|
-
return false;
|
|
167
126
|
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
return true;
|
|
127
|
+
else {
|
|
128
|
+
throw new Error('no stats');
|
|
171
129
|
}
|
|
172
|
-
|
|
130
|
+
const decoder = new TextDecoder('utf8');
|
|
131
|
+
return {
|
|
132
|
+
zoomLevels,
|
|
133
|
+
magic,
|
|
134
|
+
extHeaderOffset,
|
|
135
|
+
numZoomLevels,
|
|
136
|
+
fieldCount,
|
|
137
|
+
totalSummary,
|
|
138
|
+
definedFieldCount,
|
|
139
|
+
uncompressBufSize,
|
|
140
|
+
asOffset,
|
|
141
|
+
chromTreeOffset,
|
|
142
|
+
totalSummaryOffset,
|
|
143
|
+
unzoomedDataOffset,
|
|
144
|
+
unzoomedIndexOffset,
|
|
145
|
+
fileType,
|
|
146
|
+
version,
|
|
147
|
+
autoSql: asOffset
|
|
148
|
+
? decoder.decode(b.subarray(asOffset, b.indexOf(0, asOffset)))
|
|
149
|
+
: '',
|
|
150
|
+
};
|
|
173
151
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
152
|
+
async _readChromTree(header, opts) {
|
|
153
|
+
const refsByNumber = [];
|
|
154
|
+
const refsByName = {};
|
|
155
|
+
let unzoomedDataOffset = header.unzoomedDataOffset;
|
|
156
|
+
const chromTreeOffset = header.chromTreeOffset;
|
|
157
|
+
while (unzoomedDataOffset % 4 !== 0) {
|
|
158
|
+
unzoomedDataOffset += 1;
|
|
159
|
+
}
|
|
160
|
+
const off = unzoomedDataOffset - chromTreeOffset;
|
|
161
|
+
const b = await this.bbi.read(off, Number(chromTreeOffset), opts);
|
|
162
|
+
const dataView = new DataView(b.buffer, b.byteOffset, b.length);
|
|
163
|
+
let offset = 0;
|
|
164
|
+
// const magic = dataView.getUint32(offset, true)
|
|
165
|
+
offset += 4;
|
|
166
|
+
// const blockSize = dataView.getUint32(offset, true)
|
|
167
|
+
offset += 4;
|
|
168
|
+
const keySize = dataView.getUint32(offset, true);
|
|
169
|
+
offset += 4;
|
|
170
|
+
// const valSize = dataView.getUint32(offset, true)
|
|
171
|
+
offset += 4;
|
|
172
|
+
// const itemCount = dataView.getBigUint64(offset, true)
|
|
173
|
+
offset += 8;
|
|
174
|
+
const rootNodeOffset = 32;
|
|
175
|
+
const decoder = new TextDecoder('utf8');
|
|
176
|
+
const bptReadNode = async (currentOffset) => {
|
|
177
|
+
let offset = currentOffset;
|
|
178
|
+
if (offset >= b.length) {
|
|
179
|
+
throw new Error('reading beyond end of buffer');
|
|
185
180
|
}
|
|
186
|
-
const
|
|
187
|
-
|
|
188
|
-
const
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
}
|
|
207
|
-
const isLeafNode = dataView.getUint8(offset);
|
|
208
|
-
offset += 2; //skip 1
|
|
209
|
-
const cnt = dataView.getUint16(offset, le);
|
|
210
|
-
offset += 2;
|
|
211
|
-
if (isLeafNode) {
|
|
212
|
-
for (let n = 0; n < cnt; n++) {
|
|
213
|
-
const key = buffer
|
|
214
|
-
.subarray(offset, offset + keySize)
|
|
215
|
-
.toString()
|
|
216
|
-
.replaceAll('\0', '');
|
|
217
|
-
offset += keySize;
|
|
218
|
-
const refId = dataView.getUint32(offset, le);
|
|
219
|
-
offset += 4;
|
|
220
|
-
const refSize = dataView.getUint32(offset, le);
|
|
221
|
-
offset += 4;
|
|
222
|
-
const refRec = { name: key, id: refId, length: refSize };
|
|
223
|
-
refsByName[this.renameRefSeqs(key)] = refId;
|
|
224
|
-
refsByNumber[refId] = refRec;
|
|
225
|
-
}
|
|
181
|
+
const isLeafNode = dataView.getUint8(offset);
|
|
182
|
+
offset += 2; //skip 1
|
|
183
|
+
const cnt = dataView.getUint16(offset, true);
|
|
184
|
+
offset += 2;
|
|
185
|
+
if (isLeafNode) {
|
|
186
|
+
for (let n = 0; n < cnt; n++) {
|
|
187
|
+
const key = decoder
|
|
188
|
+
.decode(b.subarray(offset, offset + keySize))
|
|
189
|
+
.replaceAll('\0', '');
|
|
190
|
+
offset += keySize;
|
|
191
|
+
const refId = dataView.getUint32(offset, true);
|
|
192
|
+
offset += 4;
|
|
193
|
+
const refSize = dataView.getUint32(offset, true);
|
|
194
|
+
offset += 4;
|
|
195
|
+
refsByName[this.renameRefSeqs(key)] = refId;
|
|
196
|
+
refsByNumber[refId] = {
|
|
197
|
+
name: key,
|
|
198
|
+
id: refId,
|
|
199
|
+
length: refSize,
|
|
200
|
+
};
|
|
226
201
|
}
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
yield Promise.all(nextNodes);
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
// parse index node
|
|
205
|
+
const nextNodes = [];
|
|
206
|
+
for (let n = 0; n < cnt; n++) {
|
|
207
|
+
offset += keySize;
|
|
208
|
+
const childOffset = Number(dataView.getBigUint64(offset, true));
|
|
209
|
+
offset += 8;
|
|
210
|
+
nextNodes.push(bptReadNode(Number(childOffset) - Number(chromTreeOffset)));
|
|
237
211
|
}
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
212
|
+
await Promise.all(nextNodes);
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
await bptReadNode(rootNodeOffset);
|
|
216
|
+
return {
|
|
217
|
+
refsByName,
|
|
218
|
+
refsByNumber,
|
|
219
|
+
};
|
|
245
220
|
}
|
|
246
221
|
/*
|
|
247
222
|
* fetches the "unzoomed" view of the bigwig data. this is the default for bigbed
|
|
248
223
|
* @param abortSignal - a signal to optionally abort this operation
|
|
249
224
|
*/
|
|
250
|
-
getUnzoomedView(opts) {
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
return new block_view_1.BlockView(this.bbi, refsByName, unzoomedIndexOffset, isBigEndian, uncompressBufSize > 0, fileType);
|
|
254
|
-
});
|
|
225
|
+
async getUnzoomedView(opts) {
|
|
226
|
+
const { unzoomedIndexOffset, refsByName, uncompressBufSize, fileType } = await this.getHeader(opts);
|
|
227
|
+
return new block_view_1.BlockView(this.bbi, refsByName, unzoomedIndexOffset, uncompressBufSize > 0, fileType);
|
|
255
228
|
}
|
|
256
229
|
/**
|
|
257
230
|
* Gets features from a BigWig file
|
|
258
231
|
*
|
|
259
232
|
* @param refName - The chromosome name
|
|
233
|
+
*
|
|
260
234
|
* @param start - The start of a region
|
|
235
|
+
*
|
|
261
236
|
* @param end - The end of a region
|
|
262
|
-
*
|
|
237
|
+
*
|
|
238
|
+
* @param opts - An object containing basesPerSpan (e.g. pixels per basepair)
|
|
239
|
+
* or scale used to infer the zoomLevel to use
|
|
263
240
|
*/
|
|
264
|
-
getFeatureStream(refName, start, end, opts) {
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
241
|
+
async getFeatureStream(refName, start, end, opts) {
|
|
242
|
+
await this.getHeader(opts);
|
|
243
|
+
const chrName = this.renameRefSeqs(refName);
|
|
244
|
+
let view;
|
|
245
|
+
const { basesPerSpan, scale } = opts || {};
|
|
246
|
+
if (basesPerSpan) {
|
|
247
|
+
view = await this.getView(1 / basesPerSpan, opts);
|
|
248
|
+
}
|
|
249
|
+
else if (scale) {
|
|
250
|
+
view = await this.getView(scale, opts);
|
|
251
|
+
}
|
|
252
|
+
else {
|
|
253
|
+
view = await this.getView(1, opts);
|
|
254
|
+
}
|
|
255
|
+
return new rxjs_1.Observable(observer => {
|
|
256
|
+
view
|
|
257
|
+
.readWigData(chrName, start, end, observer, opts)
|
|
258
|
+
.catch((e) => {
|
|
259
|
+
observer.error(e);
|
|
283
260
|
});
|
|
284
261
|
});
|
|
285
262
|
}
|
|
286
|
-
getFeatures(refName, start, end, opts) {
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
return ret.flat();
|
|
291
|
-
});
|
|
263
|
+
async getFeatures(refName, start, end, opts) {
|
|
264
|
+
const ob = await this.getFeatureStream(refName, start, end, opts);
|
|
265
|
+
const ret = await (0, rxjs_1.firstValueFrom)(ob.pipe((0, operators_1.toArray)()));
|
|
266
|
+
return ret.flat();
|
|
292
267
|
}
|
|
293
268
|
}
|
|
294
269
|
exports.BBI = BBI;
|