@jbrowse/plugin-bed 4.3.0 → 5.0.0-beta.10
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/esm/BedAdapter/BedAdapter.d.ts +5 -22
- package/esm/BedAdapter/BedAdapter.js +29 -93
- package/esm/BedAdapter/configSchema.d.ts +59 -32
- package/esm/BedAdapter/configSchema.js +64 -14
- package/esm/BedAdapter/index.js +4 -2
- package/esm/BedGraphAdapter/BedGraphAdapter.d.ts +5 -12
- package/esm/BedGraphAdapter/BedGraphAdapter.js +33 -89
- package/esm/BedGraphAdapter/configSchema.d.ts +35 -11
- package/esm/BedGraphAdapter/configSchema.js +43 -13
- package/esm/BedGraphAdapter/index.js +3 -2
- package/esm/BedGraphTabixAdapter/BedGraphTabixAdapter.d.ts +5 -5
- package/esm/BedGraphTabixAdapter/BedGraphTabixAdapter.js +65 -57
- package/esm/BedGraphTabixAdapter/configSchema.d.ts +46 -22
- package/esm/BedGraphTabixAdapter/configSchema.js +50 -34
- package/esm/BedGraphTabixAdapter/index.js +3 -2
- package/esm/BedTabixAdapter/BedTabixAdapter.d.ts +34 -38
- package/esm/BedTabixAdapter/BedTabixAdapter.js +82 -72
- package/esm/BedTabixAdapter/configSchema.d.ts +55 -31
- package/esm/BedTabixAdapter/configSchema.js +58 -35
- package/esm/BedTabixAdapter/index.js +4 -2
- package/esm/BedpeAdapter/BedpeAdapter.d.ts +6 -13
- package/esm/BedpeAdapter/BedpeAdapter.js +26 -74
- package/esm/BedpeAdapter/configSchema.d.ts +31 -12
- package/esm/BedpeAdapter/configSchema.js +37 -13
- package/esm/BedpeAdapter/index.js +4 -2
- package/esm/BedpeAdapter/util.js +25 -25
- package/esm/BigBedAdapter/BigBedAdapter.d.ts +8 -7
- package/esm/BigBedAdapter/BigBedAdapter.js +99 -107
- package/esm/BigBedAdapter/configSchema.d.ts +38 -16
- package/esm/BigBedAdapter/configSchema.js +46 -13
- package/esm/BigBedAdapter/index.js +3 -2
- package/esm/BigBedTextSearchAdapter/BigBedTextSearchAdapter.d.ts +27 -0
- package/esm/BigBedTextSearchAdapter/BigBedTextSearchAdapter.js +128 -0
- package/esm/BigBedTextSearchAdapter/configSchema.d.ts +51 -0
- package/esm/BigBedTextSearchAdapter/configSchema.js +57 -0
- package/esm/BigBedTextSearchAdapter/index.d.ts +2 -0
- package/esm/BigBedTextSearchAdapter/index.js +11 -0
- package/esm/StarFusionAdapter/StarFusionAdapter.d.ts +14 -0
- package/esm/StarFusionAdapter/StarFusionAdapter.js +66 -0
- package/esm/StarFusionAdapter/configSchema.d.ts +30 -0
- package/esm/StarFusionAdapter/configSchema.js +43 -0
- package/esm/StarFusionAdapter/index.d.ts +2 -0
- package/esm/StarFusionAdapter/index.js +12 -0
- package/esm/adapterUtil.d.ts +5 -0
- package/esm/adapterUtil.js +43 -0
- package/esm/bedGraphUtil.d.ts +11 -0
- package/esm/bedGraphUtil.js +20 -0
- package/esm/copyExcept.d.ts +1 -0
- package/esm/copyExcept.js +11 -0
- package/esm/generateBedMethylFeature.d.ts +1 -1
- package/esm/generateBedMethylFeature.js +24 -6
- package/esm/generateRastairMethylFeature.d.ts +28 -0
- package/esm/generateRastairMethylFeature.js +38 -0
- package/esm/generateRepeatMaskerFeature.d.ts +17 -51
- package/esm/generateRepeatMaskerFeature.js +27 -37
- package/esm/generateUcscTranscript.d.ts +15 -7
- package/esm/generateUcscTranscript.js +106 -29
- package/esm/index.d.ts +2 -0
- package/esm/index.js +12 -8
- package/esm/util.d.ts +32 -27
- package/esm/util.js +139 -98
- package/package.json +10 -13
- package/esm/GuessAdapter/index.d.ts +0 -2
- package/esm/GuessAdapter/index.js +0 -71
|
@@ -1,104 +1,114 @@
|
|
|
1
|
-
import BED from '@gmod/bed';
|
|
2
1
|
import { TabixIndexedFile } from '@gmod/tabix';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
2
|
+
import { readConfObject } from '@jbrowse/core/configuration';
|
|
3
|
+
import { BaseFeatureDataAdapter, cachedSetup, } from '@jbrowse/core/data_adapters/BaseAdapter';
|
|
4
|
+
import { SimpleFeature, downloadStatus } from '@jbrowse/core/util';
|
|
5
|
+
import { checkAbortSignal } from '@jbrowse/core/util/aborting';
|
|
6
|
+
import { sharedBgzfWorkerPool } from '@jbrowse/core/util/bgzfWorkerPool';
|
|
7
|
+
import { decompressedBytesBudget } from '@jbrowse/core/util/cacheBudgets';
|
|
8
|
+
import { openLocation, openTabixIndexFilehandle } from '@jbrowse/core/util/io';
|
|
6
9
|
import { ObservableCreate } from '@jbrowse/core/util/rxjs';
|
|
7
|
-
import {
|
|
8
|
-
import { featureData } from
|
|
10
|
+
import { readTabixHeaderLines } from '@jbrowse/core/util/tabix';
|
|
11
|
+
import { featureData, makeParser, parseNamesFromHeader } from '../util.js';
|
|
9
12
|
export default class BedTabixAdapter extends BaseFeatureDataAdapter {
|
|
10
|
-
parser
|
|
13
|
+
// the parser needs the column names, which come from the file's header, so
|
|
14
|
+
// it cannot be built in the constructor
|
|
15
|
+
getParser = cachedSetup({
|
|
16
|
+
setup: async () => makeParser({
|
|
17
|
+
autoSql: readConfObject(this.config, 'autoSql'),
|
|
18
|
+
columnNames: await this.getNames(),
|
|
19
|
+
}),
|
|
20
|
+
});
|
|
21
|
+
bedGzLoc;
|
|
11
22
|
bed;
|
|
12
|
-
columnNames;
|
|
13
|
-
scoreColumn;
|
|
14
23
|
static capabilities = ['getFeatures', 'getRefNames'];
|
|
15
|
-
|
|
24
|
+
// `label` because the index metadata download narrates nothing itself; the
|
|
25
|
+
// helper shows it only while the first attempt is in flight, so pan/zoom
|
|
26
|
+
// re-entry (every getFeatures awaits it) doesn't re-flash "Downloading index"
|
|
27
|
+
getMetadata = cachedSetup({
|
|
28
|
+
label: 'Downloading index',
|
|
29
|
+
setup: () => this.bed.getMetadata(),
|
|
30
|
+
});
|
|
31
|
+
// Memoized: getFeatures needs the names on every query, and reading them goes
|
|
32
|
+
// to the file's leading blocks — a fetch and a decompress that was being
|
|
33
|
+
// repeated on every pan and zoom. Resolves undefined when the file declares
|
|
34
|
+
// no column names — parseNamesFromHeader's answer for a header it can't read
|
|
35
|
+
// names out of.
|
|
36
|
+
getNames = cachedSetup({ setup: () => this.readNames() });
|
|
16
37
|
constructor(config, getSubAdapter, pluginManager) {
|
|
17
38
|
super(config, getSubAdapter, pluginManager);
|
|
18
|
-
|
|
19
|
-
const type = this.
|
|
20
|
-
const loc = this.
|
|
21
|
-
const autoSql = this.getConf('autoSql');
|
|
39
|
+
this.bedGzLoc = readConfObject(this.config, 'bedGzLocation');
|
|
40
|
+
const type = readConfObject(this.config, ['index', 'indexType']);
|
|
41
|
+
const loc = readConfObject(this.config, ['index', 'location']);
|
|
22
42
|
const pm = this.pluginManager;
|
|
23
43
|
this.bed = new TabixIndexedFile({
|
|
24
|
-
filehandle: openLocation(bedGzLoc, pm),
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
44
|
+
filehandle: openLocation(this.bedGzLoc, pm),
|
|
45
|
+
...openTabixIndexFilehandle(loc, type, pm),
|
|
46
|
+
chunkCacheBudget: decompressedBytesBudget,
|
|
47
|
+
bgzfWorkerPool: sharedBgzfWorkerPool(),
|
|
28
48
|
});
|
|
29
|
-
this.columnNames = this.getConf('columnNames');
|
|
30
|
-
this.scoreColumn = this.getConf('scoreColumn');
|
|
31
|
-
this.parser = new BED({ autoSql });
|
|
32
49
|
}
|
|
33
50
|
async getRefNames(opts = {}) {
|
|
34
|
-
return this.bed.getReferenceSequenceNames(opts);
|
|
51
|
+
return downloadStatus('Downloading index', opts.statusCallback, onProgress => this.bed.getReferenceSequenceNames({ ...opts, onProgress }));
|
|
35
52
|
}
|
|
36
53
|
async getHeader(opts) {
|
|
37
54
|
return this.bed.getHeader(opts);
|
|
38
55
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
return this.setupP;
|
|
47
|
-
}
|
|
48
|
-
async getMetadataPre() {
|
|
49
|
-
const meta = await this.bed.getMetadata();
|
|
50
|
-
return { meta };
|
|
51
|
-
}
|
|
52
|
-
async getMetadata(opts) {
|
|
53
|
-
const { statusCallback = () => { } } = opts || {};
|
|
54
|
-
return updateStatus('Downloading index', statusCallback, () => this.getMetadataPre2(opts));
|
|
56
|
+
/**
|
|
57
|
+
* Estimate compressed bytes for regions straight from the tabix index — no
|
|
58
|
+
* feature download. Lets wrapping adapters (e.g. MafTabix) byte-budget a
|
|
59
|
+
* fetch before pulling the (potentially huge) per-line payload.
|
|
60
|
+
*/
|
|
61
|
+
async getRegionByteSize(regions, opts) {
|
|
62
|
+
return this.bed.bytesForRegions(regions, opts);
|
|
55
63
|
}
|
|
56
|
-
async
|
|
57
|
-
|
|
58
|
-
|
|
64
|
+
async readNames() {
|
|
65
|
+
const columnNames = readConfObject(this.config, 'columnNames');
|
|
66
|
+
if (columnNames.length) {
|
|
67
|
+
return columnNames;
|
|
59
68
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
return
|
|
64
|
-
? defline
|
|
65
|
-
.slice(1)
|
|
66
|
-
.split('\t')
|
|
67
|
-
.map(f => f.trim())
|
|
68
|
-
: undefined;
|
|
69
|
+
// readTabixHeaderLines covers both ways a tabix file keeps a header: a
|
|
70
|
+
// `#`-commented block, which getHeader() returns, and a plain row skipped
|
|
71
|
+
// via `tabix -S N`, which it does not.
|
|
72
|
+
return parseNamesFromHeader((await readTabixHeaderLines(this.bed)).join('\n'));
|
|
69
73
|
}
|
|
70
74
|
getFeatures(query, opts) {
|
|
71
|
-
const {
|
|
75
|
+
const { signal, statusCallback } = opts ?? {};
|
|
72
76
|
return ObservableCreate(async (observer) => {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
const colStart = columnNumbers.start - 1;
|
|
77
|
-
const colEnd = columnNumbers.end - 1;
|
|
77
|
+
// warms the index under its own status label — getLines would otherwise
|
|
78
|
+
// download it under "Downloading features"
|
|
79
|
+
await this.getMetadata(opts);
|
|
78
80
|
const names = await this.getNames();
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
81
|
+
const parser = await this.getParser();
|
|
82
|
+
const scoreColumn = readConfObject(this.config, 'scoreColumn');
|
|
83
|
+
const disableGeneHeuristic = readConfObject(this.config, 'disableGeneHeuristic');
|
|
84
|
+
checkAbortSignal(signal);
|
|
85
|
+
await downloadStatus('Downloading features', statusCallback, onProgress =>
|
|
86
|
+
// start/end come from @gmod/tabix rather than being re-derived from
|
|
87
|
+
// the line: it located the coordinate columns to find these lines at
|
|
88
|
+
// all, and already applied the index's coordinate offset (-1 for a
|
|
89
|
+
// 1-based-closed preset) and its no-end-column convention (a single
|
|
90
|
+
// position becomes start..start+1). refName is likewise the query's
|
|
91
|
+
// — getLines only calls back for lines whose ref column matches it.
|
|
92
|
+
this.bed.getLines(query.refName, query.start, query.end, {
|
|
93
|
+
lineCallback: (line, fileOffset, start, end) => {
|
|
94
|
+
checkAbortSignal(signal);
|
|
95
|
+
const splitLine = line.split('\t');
|
|
88
96
|
observer.next(new SimpleFeature(featureData({
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
scoreColumn
|
|
94
|
-
parser
|
|
97
|
+
splitLine,
|
|
98
|
+
refName: query.refName,
|
|
99
|
+
start,
|
|
100
|
+
end,
|
|
101
|
+
scoreColumn,
|
|
102
|
+
parser,
|
|
95
103
|
uniqueId: `${this.id}-${fileOffset}`,
|
|
96
104
|
names,
|
|
97
105
|
disableGeneHeuristic,
|
|
98
106
|
})));
|
|
99
107
|
},
|
|
108
|
+
onProgress,
|
|
109
|
+
signal,
|
|
100
110
|
}));
|
|
101
111
|
observer.complete();
|
|
102
|
-
},
|
|
112
|
+
}, signal);
|
|
103
113
|
}
|
|
104
114
|
}
|
|
@@ -1,44 +1,68 @@
|
|
|
1
|
+
import type { Instance } from '@jbrowse/mobx-state-tree';
|
|
2
|
+
export declare function normalizeSnapshot(snap: Record<string, unknown>): Record<string, unknown>;
|
|
3
|
+
/**
|
|
4
|
+
* #config BedTabixAdapter
|
|
5
|
+
* #trackType FeatureTrack
|
|
6
|
+
* #fileFormat feature | BED (tabix)
|
|
7
|
+
*
|
|
8
|
+
* #example
|
|
9
|
+
* The `uri` shorthand auto-resolves the `.tbi` index; add `csi: true` for a
|
|
10
|
+
* `.csi` index instead:
|
|
11
|
+
* ```js
|
|
12
|
+
* {
|
|
13
|
+
* type: 'BedTabixAdapter',
|
|
14
|
+
* uri: 'https://example.com/features.bed.gz',
|
|
15
|
+
* }
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
1
18
|
declare const BedTabixAdapter: import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaType<{
|
|
2
|
-
|
|
3
|
-
type:
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
19
|
+
readonly densityAdapter: {
|
|
20
|
+
type: "maybeFrozen";
|
|
21
|
+
};
|
|
22
|
+
type: {
|
|
23
|
+
type: "string";
|
|
24
|
+
} & {
|
|
25
|
+
defaultValue: string;
|
|
26
|
+
};
|
|
27
|
+
readonly bedGzLocation: {
|
|
28
|
+
type: "fileLocation";
|
|
29
|
+
} & {
|
|
30
|
+
defaultValue: unknown;
|
|
8
31
|
};
|
|
9
|
-
index: import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaType<{
|
|
10
|
-
indexType: {
|
|
11
|
-
|
|
12
|
-
|
|
32
|
+
readonly index: import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaType<{
|
|
33
|
+
readonly indexType: {
|
|
34
|
+
type: "stringEnum";
|
|
35
|
+
} & {
|
|
36
|
+
model: import("@jbrowse/mobx-state-tree").ISimpleType<"CSI" | "TBI">;
|
|
37
|
+
} & {
|
|
13
38
|
defaultValue: string;
|
|
14
39
|
};
|
|
15
|
-
location: {
|
|
16
|
-
type:
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
locationType: string;
|
|
20
|
-
};
|
|
40
|
+
readonly location: {
|
|
41
|
+
type: "fileLocation";
|
|
42
|
+
} & {
|
|
43
|
+
defaultValue: unknown;
|
|
21
44
|
};
|
|
22
|
-
}, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, undefined>>;
|
|
23
|
-
columnNames: {
|
|
24
|
-
type:
|
|
25
|
-
|
|
26
|
-
defaultValue:
|
|
45
|
+
}, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, undefined, undefined, import("@jbrowse/core/configuration").ConfigurationSchemaRequirement<Partial<Record<string, string[]>>, string>, any>>;
|
|
46
|
+
readonly columnNames: {
|
|
47
|
+
type: "stringArray";
|
|
48
|
+
} & {
|
|
49
|
+
defaultValue: unknown;
|
|
27
50
|
};
|
|
28
|
-
scoreColumn: {
|
|
29
|
-
type: string;
|
|
30
|
-
|
|
51
|
+
readonly scoreColumn: {
|
|
52
|
+
type: "string";
|
|
53
|
+
} & {
|
|
31
54
|
defaultValue: string;
|
|
32
55
|
};
|
|
33
|
-
autoSql: {
|
|
34
|
-
type: string;
|
|
35
|
-
|
|
56
|
+
readonly autoSql: {
|
|
57
|
+
type: "string";
|
|
58
|
+
} & {
|
|
36
59
|
defaultValue: string;
|
|
37
60
|
};
|
|
38
|
-
disableGeneHeuristic: {
|
|
39
|
-
type:
|
|
40
|
-
|
|
61
|
+
readonly disableGeneHeuristic: {
|
|
62
|
+
type: "boolean";
|
|
63
|
+
} & {
|
|
41
64
|
defaultValue: boolean;
|
|
42
65
|
};
|
|
43
|
-
}, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, undefined>>;
|
|
66
|
+
}, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, undefined, true, import("@jbrowse/core/configuration").ConfigurationSchemaRequirement<Partial<Record<string, string[]>>, string>, any>>;
|
|
67
|
+
export type BedTabixAdapterConfig = Instance<typeof BedTabixAdapter>;
|
|
44
68
|
export default BedTabixAdapter;
|
|
@@ -1,7 +1,29 @@
|
|
|
1
|
-
import { ConfigurationSchema } from '@jbrowse/core/configuration';
|
|
2
|
-
import {
|
|
3
|
-
function
|
|
1
|
+
import { ConfigurationSchema, expandTabixShorthand, tabixIndexSchema, } from '@jbrowse/core/configuration';
|
|
2
|
+
import { densityAdapterConfigSchemaFields } from '@jbrowse/core/data_adapters/BaseAdapter';
|
|
3
|
+
export function normalizeSnapshot(snap) {
|
|
4
|
+
return expandTabixShorthand(snap, 'bedGzLocation');
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* #config BedTabixAdapter
|
|
8
|
+
* #trackType FeatureTrack
|
|
9
|
+
* #fileFormat feature | BED (tabix)
|
|
10
|
+
*
|
|
11
|
+
* #example
|
|
12
|
+
* The `uri` shorthand auto-resolves the `.tbi` index; add `csi: true` for a
|
|
13
|
+
* `.csi` index instead:
|
|
14
|
+
* ```js
|
|
15
|
+
* {
|
|
16
|
+
* type: 'BedTabixAdapter',
|
|
17
|
+
* uri: 'https://example.com/features.bed.gz',
|
|
18
|
+
* }
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
4
21
|
const BedTabixAdapter = ConfigurationSchema('BedTabixAdapter', {
|
|
22
|
+
/**
|
|
23
|
+
* #slot
|
|
24
|
+
* location of the bgzip-compressed BED, sorted by position. Must be bgzip
|
|
25
|
+
* rather than plain gzip, which tabix cannot index.
|
|
26
|
+
*/
|
|
5
27
|
bedGzLocation: {
|
|
6
28
|
type: 'fileLocation',
|
|
7
29
|
defaultValue: {
|
|
@@ -9,58 +31,59 @@ const BedTabixAdapter = ConfigurationSchema('BedTabixAdapter', {
|
|
|
9
31
|
locationType: 'UriLocation',
|
|
10
32
|
},
|
|
11
33
|
},
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
uri: '/path/to/my.bed.gz.tbi',
|
|
22
|
-
locationType: 'UriLocation',
|
|
23
|
-
},
|
|
24
|
-
},
|
|
25
|
-
}),
|
|
34
|
+
/**
|
|
35
|
+
* #slot
|
|
36
|
+
* where the tabix index is and which kind it is. The `uri` shorthand derives
|
|
37
|
+
* both, so a config using it states neither.
|
|
38
|
+
*/
|
|
39
|
+
index: tabixIndexSchema(),
|
|
40
|
+
/**
|
|
41
|
+
* #slot
|
|
42
|
+
*/
|
|
26
43
|
columnNames: {
|
|
27
44
|
type: 'stringArray',
|
|
28
|
-
description:
|
|
45
|
+
description: "List of column names. A column named like a standard BED column is parsed as that column's type (chromStart numeric, blockSizes a numeric list); any other column is text",
|
|
29
46
|
defaultValue: [],
|
|
30
47
|
},
|
|
48
|
+
/**
|
|
49
|
+
* #slot
|
|
50
|
+
*/
|
|
31
51
|
scoreColumn: {
|
|
32
52
|
type: 'string',
|
|
33
53
|
description: 'The column to use as a "score" attribute',
|
|
34
54
|
defaultValue: '',
|
|
35
55
|
},
|
|
56
|
+
/**
|
|
57
|
+
* #slot
|
|
58
|
+
*/
|
|
36
59
|
autoSql: {
|
|
37
60
|
type: 'string',
|
|
38
61
|
description: 'The autoSql definition for the data fields in the file',
|
|
39
62
|
defaultValue: '',
|
|
40
63
|
},
|
|
64
|
+
/**
|
|
65
|
+
* #slot
|
|
66
|
+
*/
|
|
41
67
|
disableGeneHeuristic: {
|
|
42
68
|
type: 'boolean',
|
|
43
69
|
description: 'Disable the heuristic that auto-detects BED12 features as gene/transcript structures. Useful for files that have BED12-like structure but are not genes (e.g. tandem duplications)',
|
|
44
70
|
defaultValue: false,
|
|
45
71
|
},
|
|
72
|
+
...densityAdapterConfigSchemaFields,
|
|
46
73
|
}, {
|
|
47
74
|
explicitlyTyped: true,
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
},
|
|
62
|
-
}
|
|
63
|
-
: snap;
|
|
64
|
-
},
|
|
75
|
+
/**
|
|
76
|
+
* #preProcessSnapshot
|
|
77
|
+
*
|
|
78
|
+
*
|
|
79
|
+
* preprocessor to allow minimal config, assumes yourfile.bed.gz.tbi:
|
|
80
|
+
* ```json
|
|
81
|
+
* {
|
|
82
|
+
* "type": "BedTabixAdapter",
|
|
83
|
+
* "uri": "yourfile.bed.gz"
|
|
84
|
+
* }
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
preProcessSnapshot: normalizeSnapshot,
|
|
65
88
|
});
|
|
66
89
|
export default BedTabixAdapter;
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import AdapterType from '@jbrowse/core/pluggableElementTypes/AdapterType';
|
|
2
|
-
import configSchema from
|
|
2
|
+
import configSchema, { normalizeSnapshot } from './configSchema.js';
|
|
3
3
|
export default function BedTabixAdapterF(pluginManager) {
|
|
4
4
|
pluginManager.addAdapterType(() => new AdapterType({
|
|
5
5
|
name: 'BedTabixAdapter',
|
|
6
6
|
displayName: 'BED tabix adapter',
|
|
7
7
|
configSchema,
|
|
8
|
-
getAdapterClass: () => import(
|
|
8
|
+
getAdapterClass: () => import('./BedTabixAdapter.js').then(r => r.default),
|
|
9
|
+
locationKey: 'bedGzLocation',
|
|
10
|
+
normalizeSnapshot,
|
|
9
11
|
}));
|
|
10
12
|
}
|
|
@@ -1,22 +1,15 @@
|
|
|
1
1
|
import { BaseFeatureDataAdapter } from '@jbrowse/core/data_adapters/BaseAdapter';
|
|
2
|
-
import {
|
|
2
|
+
import type { BedpeAdapterConfig } from './configSchema.ts';
|
|
3
3
|
import type { BaseOptions } from '@jbrowse/core/data_adapters/BaseAdapter';
|
|
4
|
-
import type {
|
|
5
|
-
export default class BedpeAdapter extends BaseFeatureDataAdapter {
|
|
6
|
-
|
|
7
|
-
header: string;
|
|
8
|
-
feats1: Record<string, string[]>;
|
|
9
|
-
feats2: Record<string, string[]>;
|
|
10
|
-
columnNames: string[];
|
|
11
|
-
}>;
|
|
12
|
-
protected intervalTrees: Record<string, Promise<IntervalTree<Feature> | undefined> | undefined>;
|
|
4
|
+
import type { Region } from '@jbrowse/core/util';
|
|
5
|
+
export default class BedpeAdapter extends BaseFeatureDataAdapter<BedpeAdapterConfig> {
|
|
6
|
+
private loadData;
|
|
13
7
|
static capabilities: string[];
|
|
14
8
|
private loadDataP;
|
|
15
|
-
private loadData;
|
|
16
9
|
getRefNames(opts?: BaseOptions): Promise<string[]>;
|
|
17
10
|
getHeader(opts?: BaseOptions): Promise<string>;
|
|
18
11
|
getNames(): Promise<string[] | undefined>;
|
|
19
12
|
private loadFeatureTreeP;
|
|
20
|
-
private
|
|
21
|
-
getFeatures(query: Region, opts?: BaseOptions): import("rxjs").Observable<Feature>;
|
|
13
|
+
private treeFeatures;
|
|
14
|
+
getFeatures(query: Region, opts?: BaseOptions): import("rxjs").Observable<import("@jbrowse/core/util").Feature>;
|
|
22
15
|
}
|
|
@@ -1,54 +1,38 @@
|
|
|
1
|
-
import { BaseFeatureDataAdapter } from '@jbrowse/core/data_adapters/BaseAdapter';
|
|
2
|
-
import {
|
|
1
|
+
import { BaseFeatureDataAdapter, cachedSetup, } from '@jbrowse/core/data_adapters/BaseAdapter';
|
|
2
|
+
import { fetchAndMaybeUnzip } from '@jbrowse/core/util';
|
|
3
3
|
import { openLocation } from '@jbrowse/core/util/io';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { parseLineByLine } from '@jbrowse/core/util/parseLineByLine';
|
|
5
|
+
import { buildPairedIntervalTree, intervalTreeFeatures, } from '../adapterUtil.js';
|
|
6
|
+
import { resolveColumnNames } from '../util.js';
|
|
7
|
+
import { featureData } from './util.js';
|
|
6
8
|
export default class BedpeAdapter extends BaseFeatureDataAdapter {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
+
// No `label`: `fetchAndMaybeUnzip` narrates the download from inside.
|
|
10
|
+
loadData = cachedSetup({ setup: opts => this.loadDataP(opts) });
|
|
9
11
|
static capabilities = ['getFeatures', 'getRefNames'];
|
|
10
12
|
async loadDataP(opts) {
|
|
11
|
-
const
|
|
12
|
-
const lines = data.split(/\n|\r\n|\r/).filter(f => !!f);
|
|
13
|
+
const buffer = await fetchAndMaybeUnzip(openLocation(this.getConf('bedpeLocation'), this.pluginManager), opts);
|
|
13
14
|
const headerLines = [];
|
|
14
|
-
let i = 0;
|
|
15
|
-
for (; i < lines.length && lines[i].startsWith('#'); i++) {
|
|
16
|
-
headerLines.push(lines[i]);
|
|
17
|
-
}
|
|
18
|
-
const header = headerLines.join('\n');
|
|
19
15
|
const feats1 = {};
|
|
20
16
|
const feats2 = {};
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
const r1 = cols[0];
|
|
25
|
-
const r2 = cols[3];
|
|
26
|
-
if (!feats1[r1]) {
|
|
27
|
-
feats1[r1] = [];
|
|
17
|
+
parseLineByLine(buffer, line => {
|
|
18
|
+
if (line.startsWith('#')) {
|
|
19
|
+
headerLines.push(line);
|
|
28
20
|
}
|
|
29
|
-
if (!
|
|
30
|
-
|
|
21
|
+
else if (!line.startsWith('track') && !line.startsWith('browser')) {
|
|
22
|
+
const cols = line.split('\t');
|
|
23
|
+
const r1 = cols[0];
|
|
24
|
+
const r2 = cols[3];
|
|
25
|
+
(feats1[r1] ??= []).push(line);
|
|
26
|
+
(feats2[r2] ??= []).push(line);
|
|
31
27
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}
|
|
35
|
-
const columnNames = this.getConf('columnNames');
|
|
28
|
+
return true;
|
|
29
|
+
}, opts?.statusCallback);
|
|
36
30
|
return {
|
|
37
|
-
header,
|
|
31
|
+
header: headerLines.join('\n'),
|
|
38
32
|
feats1,
|
|
39
33
|
feats2,
|
|
40
|
-
columnNames,
|
|
41
34
|
};
|
|
42
35
|
}
|
|
43
|
-
async loadData(opts = {}) {
|
|
44
|
-
if (!this.bedpeFeatures) {
|
|
45
|
-
this.bedpeFeatures = this.loadDataP(opts).catch((e) => {
|
|
46
|
-
this.bedpeFeatures = undefined;
|
|
47
|
-
throw e;
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
return this.bedpeFeatures;
|
|
51
|
-
}
|
|
52
36
|
async getRefNames(opts = {}) {
|
|
53
37
|
const { feats1, feats2 } = await this.loadData(opts);
|
|
54
38
|
return [...new Set([...Object.keys(feats1), ...Object.keys(feats2)])];
|
|
@@ -58,47 +42,15 @@ export default class BedpeAdapter extends BaseFeatureDataAdapter {
|
|
|
58
42
|
return header;
|
|
59
43
|
}
|
|
60
44
|
async getNames() {
|
|
61
|
-
|
|
62
|
-
if (columnNames.length) {
|
|
63
|
-
return columnNames;
|
|
64
|
-
}
|
|
65
|
-
const defs = header.split(/\n|\r\n|\r/).filter(f => !!f);
|
|
66
|
-
const defline = defs.at(-1);
|
|
67
|
-
return defline?.includes('\t')
|
|
68
|
-
? defline
|
|
69
|
-
.slice(1)
|
|
70
|
-
.split('\t')
|
|
71
|
-
.map(field => field.trim())
|
|
72
|
-
: undefined;
|
|
45
|
+
return resolveColumnNames(this.getConf('columnNames'), async () => (await this.loadData()).header);
|
|
73
46
|
}
|
|
74
47
|
async loadFeatureTreeP(refName) {
|
|
75
48
|
const { feats1, feats2 } = await this.loadData();
|
|
76
49
|
const names = await this.getNames();
|
|
77
|
-
|
|
78
|
-
const ret1 = feats1[refName]?.map((f, i) => featureData(f, `${this.id}-${refName}-${i}-r1`, false, names)) ?? [];
|
|
79
|
-
const ret2 = feats2[refName]?.map((f, i) => featureData(f, `${this.id}-${refName}-${i}-r2`, true, names)) ?? [];
|
|
80
|
-
for (const obj of [...ret1, ...ret2]) {
|
|
81
|
-
intervalTree.insert([obj.get('start'), obj.get('end')], obj);
|
|
82
|
-
}
|
|
83
|
-
return intervalTree;
|
|
84
|
-
}
|
|
85
|
-
async loadFeatureTree(refName) {
|
|
86
|
-
if (!this.intervalTrees[refName]) {
|
|
87
|
-
this.intervalTrees[refName] = this.loadFeatureTreeP(refName).catch((e) => {
|
|
88
|
-
this.intervalTrees[refName] = undefined;
|
|
89
|
-
throw e;
|
|
90
|
-
});
|
|
91
|
-
}
|
|
92
|
-
return this.intervalTrees[refName];
|
|
50
|
+
return buildPairedIntervalTree(feats1, feats2, refName, this.id, (line, uniqueId, flip) => featureData(line, uniqueId, flip, names));
|
|
93
51
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
const intervalTree = await this.loadFeatureTree(refName);
|
|
98
|
-
for (const f of intervalTree?.search([start, end]) || []) {
|
|
99
|
-
observer.next(f);
|
|
100
|
-
}
|
|
101
|
-
observer.complete();
|
|
102
|
-
}, opts.stopToken);
|
|
52
|
+
treeFeatures = intervalTreeFeatures(opts => this.loadData(opts), refName => this.loadFeatureTreeP(refName));
|
|
53
|
+
getFeatures(query, opts) {
|
|
54
|
+
return this.treeFeatures(query, opts);
|
|
103
55
|
}
|
|
104
56
|
}
|
|
@@ -1,16 +1,35 @@
|
|
|
1
|
+
import type { Instance } from '@jbrowse/mobx-state-tree';
|
|
2
|
+
export declare function normalizeSnapshot(snap: Record<string, unknown>): Record<string, unknown>;
|
|
3
|
+
/**
|
|
4
|
+
* #config BedpeAdapter
|
|
5
|
+
* #trackType VariantTrack
|
|
6
|
+
* #fileFormat variants | BEDPE | Paired/breakend records, e.g. SV calls or Hi-C loops
|
|
7
|
+
* intended for SVs in a single assembly
|
|
8
|
+
*
|
|
9
|
+
* #example
|
|
10
|
+
* ```js
|
|
11
|
+
* {
|
|
12
|
+
* type: 'BedpeAdapter',
|
|
13
|
+
* uri: 'https://example.com/sv.bedpe',
|
|
14
|
+
* }
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
1
17
|
declare const BedpeAdapter: import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaType<{
|
|
2
|
-
|
|
3
|
-
type: string;
|
|
4
|
-
|
|
5
|
-
defaultValue:
|
|
6
|
-
uri: string;
|
|
7
|
-
locationType: string;
|
|
8
|
-
};
|
|
18
|
+
type: {
|
|
19
|
+
type: "string";
|
|
20
|
+
} & {
|
|
21
|
+
defaultValue: string;
|
|
9
22
|
};
|
|
10
|
-
|
|
11
|
-
type:
|
|
12
|
-
|
|
13
|
-
defaultValue:
|
|
23
|
+
readonly bedpeLocation: {
|
|
24
|
+
type: "fileLocation";
|
|
25
|
+
} & {
|
|
26
|
+
defaultValue: unknown;
|
|
14
27
|
};
|
|
15
|
-
|
|
28
|
+
readonly columnNames: {
|
|
29
|
+
type: "stringArray";
|
|
30
|
+
} & {
|
|
31
|
+
defaultValue: unknown;
|
|
32
|
+
};
|
|
33
|
+
}, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, undefined, true, import("@jbrowse/core/configuration").ConfigurationSchemaRequirement<Partial<Record<string, string[]>>, string>, any>>;
|
|
34
|
+
export type BedpeAdapterConfig = Instance<typeof BedpeAdapter>;
|
|
16
35
|
export default BedpeAdapter;
|