@jbrowse/plugin-bed 4.3.0 → 5.0.0-beta.2
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 +4 -19
- package/esm/BedAdapter/BedAdapter.js +31 -88
- package/esm/BedAdapter/configSchema.d.ts +89 -40
- package/esm/BedAdapter/configSchema.js +65 -13
- package/esm/BedAdapter/index.js +4 -2
- package/esm/BedGraphAdapter/BedGraphAdapter.d.ts +4 -9
- package/esm/BedGraphAdapter/BedGraphAdapter.js +31 -85
- package/esm/BedGraphAdapter/configSchema.d.ts +35 -9
- package/esm/BedGraphAdapter/configSchema.js +47 -12
- package/esm/BedGraphAdapter/index.js +3 -2
- package/esm/BedGraphTabixAdapter/BedGraphTabixAdapter.d.ts +5 -5
- package/esm/BedGraphTabixAdapter/BedGraphTabixAdapter.js +62 -57
- package/esm/BedGraphTabixAdapter/configSchema.d.ts +48 -19
- package/esm/BedGraphTabixAdapter/configSchema.js +42 -34
- package/esm/BedGraphTabixAdapter/index.js +3 -2
- package/esm/BedTabixAdapter/BedTabixAdapter.d.ts +34 -38
- package/esm/BedTabixAdapter/BedTabixAdapter.js +82 -71
- package/esm/BedTabixAdapter/configSchema.d.ts +73 -31
- package/esm/BedTabixAdapter/configSchema.js +53 -35
- package/esm/BedTabixAdapter/index.js +4 -2
- package/esm/BedpeAdapter/BedpeAdapter.d.ts +4 -10
- package/esm/BedpeAdapter/BedpeAdapter.js +28 -69
- package/esm/BedpeAdapter/configSchema.d.ts +33 -10
- package/esm/BedpeAdapter/configSchema.js +45 -12
- package/esm/BedpeAdapter/index.js +4 -2
- package/esm/BedpeAdapter/util.js +22 -23
- package/esm/BigBedAdapter/BigBedAdapter.d.ts +8 -7
- package/esm/BigBedAdapter/BigBedAdapter.js +100 -107
- package/esm/BigBedAdapter/configSchema.d.ts +52 -17
- package/esm/BigBedAdapter/configSchema.js +53 -12
- package/esm/BigBedAdapter/index.js +3 -2
- package/esm/StarFusionAdapter/StarFusionAdapter.d.ts +15 -0
- package/esm/StarFusionAdapter/StarFusionAdapter.js +121 -0
- package/esm/StarFusionAdapter/configSchema.d.ts +31 -0
- package/esm/StarFusionAdapter/configSchema.js +52 -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 +28 -0
- package/esm/bedGraphUtil.d.ts +10 -0
- package/esm/bedGraphUtil.js +18 -0
- package/esm/generateBedMethylFeature.d.ts +1 -1
- package/esm/generateBedMethylFeature.js +19 -6
- package/esm/generateRastairMethylFeature.d.ts +28 -0
- package/esm/generateRastairMethylFeature.js +38 -0
- package/esm/generateRepeatMaskerFeature.d.ts +4 -51
- package/esm/generateRepeatMaskerFeature.js +28 -41
- package/esm/generateUcscTranscript.d.ts +15 -7
- package/esm/generateUcscTranscript.js +58 -28
- package/esm/index.d.ts +2 -0
- package/esm/index.js +10 -8
- package/esm/util.d.ts +32 -27
- package/esm/util.js +127 -97
- package/package.json +9 -13
- package/esm/GuessAdapter/index.d.ts +0 -2
- package/esm/GuessAdapter/index.js +0 -71
|
@@ -1,32 +1,17 @@
|
|
|
1
|
-
import BED from '@gmod/bed';
|
|
2
1
|
import { BaseFeatureDataAdapter } from '@jbrowse/core/data_adapters/BaseAdapter';
|
|
3
2
|
import { IntervalTree } from '@jbrowse/core/util';
|
|
3
|
+
import type { BedAdapterConfig } from './configSchema.ts';
|
|
4
4
|
import type { BaseOptions } from '@jbrowse/core/data_adapters/BaseAdapter';
|
|
5
5
|
import type { Feature, Region } from '@jbrowse/core/util';
|
|
6
|
-
export default class BedAdapter extends BaseFeatureDataAdapter {
|
|
7
|
-
|
|
6
|
+
export default class BedAdapter extends BaseFeatureDataAdapter<BedAdapterConfig> {
|
|
7
|
+
loadData: (opts?: BaseOptions) => Promise<{
|
|
8
8
|
header: string;
|
|
9
9
|
features: Record<string, string[]>;
|
|
10
|
-
parser: BED;
|
|
11
|
-
columnNames: string[];
|
|
12
|
-
scoreColumn: string;
|
|
13
|
-
colRef: number;
|
|
14
|
-
colStart: number;
|
|
15
|
-
colEnd: number;
|
|
16
10
|
}>;
|
|
11
|
+
private getParser;
|
|
17
12
|
protected intervalTrees: Record<string, Promise<IntervalTree<Feature> | undefined> | undefined>;
|
|
18
13
|
static capabilities: string[];
|
|
19
14
|
private loadDataP;
|
|
20
|
-
loadData(opts?: BaseOptions): Promise<{
|
|
21
|
-
header: string;
|
|
22
|
-
features: Record<string, string[]>;
|
|
23
|
-
parser: BED;
|
|
24
|
-
columnNames: string[];
|
|
25
|
-
scoreColumn: string;
|
|
26
|
-
colRef: number;
|
|
27
|
-
colStart: number;
|
|
28
|
-
colEnd: number;
|
|
29
|
-
}>;
|
|
30
15
|
getRefNames(opts?: BaseOptions): Promise<string[]>;
|
|
31
16
|
getHeader(opts?: BaseOptions): Promise<string>;
|
|
32
17
|
getNames(): Promise<string[] | undefined>;
|
|
@@ -1,60 +1,24 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { BaseFeatureDataAdapter } from '@jbrowse/core/data_adapters/BaseAdapter';
|
|
1
|
+
import { BaseFeatureDataAdapter, cachedSetup, } from '@jbrowse/core/data_adapters/BaseAdapter';
|
|
3
2
|
import { IntervalTree, SimpleFeature, fetchAndMaybeUnzip, } from '@jbrowse/core/util';
|
|
4
3
|
import { openLocation } from '@jbrowse/core/util/io';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { featureData } from "../util.js";
|
|
4
|
+
import { intervalTreeFeatures } from '../adapterUtil.js';
|
|
5
|
+
import { bedFeatureLocus, bucketBedLines, featureData, makeParser, resolveColumnNames, } from '../util.js';
|
|
8
6
|
export default class BedAdapter extends BaseFeatureDataAdapter {
|
|
9
|
-
|
|
7
|
+
// No `label`: `fetchAndMaybeUnzip` narrates the download from inside.
|
|
8
|
+
loadData = cachedSetup({ setup: opts => this.loadDataP(opts) });
|
|
9
|
+
// the parser needs the column names, which come from the header, so it can
|
|
10
|
+
// only be built once the file is loaded
|
|
11
|
+
getParser = cachedSetup({
|
|
12
|
+
setup: async () => makeParser({
|
|
13
|
+
autoSql: this.getConf('autoSql'),
|
|
14
|
+
columnNames: await this.getNames(),
|
|
15
|
+
}),
|
|
16
|
+
});
|
|
10
17
|
intervalTrees = {};
|
|
11
18
|
static capabilities = ['getFeatures', 'getRefNames'];
|
|
12
19
|
async loadDataP(opts) {
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
const headerLines = [];
|
|
16
|
-
const features = {};
|
|
17
|
-
parseLineByLine(buffer, line => {
|
|
18
|
-
if (line.startsWith('#')) {
|
|
19
|
-
headerLines.push(line);
|
|
20
|
-
}
|
|
21
|
-
else {
|
|
22
|
-
const tab = line.indexOf('\t');
|
|
23
|
-
const refName = line.slice(0, tab);
|
|
24
|
-
if (!features[refName]) {
|
|
25
|
-
features[refName] = [];
|
|
26
|
-
}
|
|
27
|
-
features[refName].push(line);
|
|
28
|
-
}
|
|
29
|
-
return true;
|
|
30
|
-
}, opts?.statusCallback);
|
|
31
|
-
const header = headerLines.join('\n');
|
|
32
|
-
const autoSql = this.getConf('autoSql');
|
|
33
|
-
const parser = new BED({ autoSql });
|
|
34
|
-
const columnNames = this.getConf('columnNames');
|
|
35
|
-
const scoreColumn = this.getConf('scoreColumn');
|
|
36
|
-
const colRef = this.getConf('colRef');
|
|
37
|
-
const colStart = this.getConf('colStart');
|
|
38
|
-
const colEnd = this.getConf('colEnd');
|
|
39
|
-
return {
|
|
40
|
-
header,
|
|
41
|
-
features,
|
|
42
|
-
parser,
|
|
43
|
-
columnNames,
|
|
44
|
-
scoreColumn,
|
|
45
|
-
colRef,
|
|
46
|
-
colStart,
|
|
47
|
-
colEnd,
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
async loadData(opts = {}) {
|
|
51
|
-
if (!this.bedFeatures) {
|
|
52
|
-
this.bedFeatures = this.loadDataP(opts).catch((e) => {
|
|
53
|
-
this.bedFeatures = undefined;
|
|
54
|
-
throw e;
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
return this.bedFeatures;
|
|
20
|
+
const buffer = await fetchAndMaybeUnzip(openLocation(this.getConf('bedLocation'), this.pluginManager), opts);
|
|
21
|
+
return bucketBedLines(buffer, opts?.statusCallback);
|
|
58
22
|
}
|
|
59
23
|
async getRefNames(opts = {}) {
|
|
60
24
|
const { features } = await this.loadData(opts);
|
|
@@ -65,39 +29,30 @@ export default class BedAdapter extends BaseFeatureDataAdapter {
|
|
|
65
29
|
return header;
|
|
66
30
|
}
|
|
67
31
|
async getNames() {
|
|
68
|
-
|
|
69
|
-
if (columnNames.length) {
|
|
70
|
-
return columnNames;
|
|
71
|
-
}
|
|
72
|
-
const defs = header.split(/\n|\r\n|\r/).filter(f => !!f);
|
|
73
|
-
const defline = defs.at(-1);
|
|
74
|
-
return defline?.includes('\t')
|
|
75
|
-
? defline
|
|
76
|
-
.slice(1)
|
|
77
|
-
.split('\t')
|
|
78
|
-
.map(field => field.trim())
|
|
79
|
-
: undefined;
|
|
32
|
+
return resolveColumnNames(this.getConf('columnNames'), async () => (await this.loadData()).header);
|
|
80
33
|
}
|
|
81
34
|
async loadFeatureIntervalTreeHelper(refName) {
|
|
82
|
-
const {
|
|
35
|
+
const { features } = await this.loadData();
|
|
83
36
|
const lines = features[refName];
|
|
84
37
|
if (!lines) {
|
|
85
38
|
return undefined;
|
|
86
39
|
}
|
|
87
40
|
const names = await this.getNames();
|
|
41
|
+
const parser = await this.getParser();
|
|
42
|
+
const scoreColumn = this.getConf('scoreColumn');
|
|
43
|
+
const colRef = this.getConf('colRef');
|
|
44
|
+
const colStart = this.getConf('colStart');
|
|
45
|
+
const colEnd = this.getConf('colEnd');
|
|
88
46
|
const disableGeneHeuristic = this.getConf('disableGeneHeuristic');
|
|
89
47
|
const intervalTree = new IntervalTree();
|
|
90
48
|
for (let i = 0; i < lines.length; i++) {
|
|
91
|
-
const
|
|
92
|
-
const uniqueId = `${this.id}-${refName}-${i}`;
|
|
49
|
+
const splitLine = lines[i].split('\t');
|
|
93
50
|
const feat = new SimpleFeature(featureData({
|
|
94
|
-
|
|
95
|
-
colRef,
|
|
96
|
-
colStart,
|
|
97
|
-
colEnd,
|
|
51
|
+
splitLine,
|
|
52
|
+
...bedFeatureLocus({ splitLine, colRef, colStart, colEnd }),
|
|
98
53
|
scoreColumn,
|
|
99
54
|
parser,
|
|
100
|
-
uniqueId
|
|
55
|
+
uniqueId: `${this.id}-${refName}-${i}`,
|
|
101
56
|
names,
|
|
102
57
|
disableGeneHeuristic,
|
|
103
58
|
}));
|
|
@@ -106,25 +61,13 @@ export default class BedAdapter extends BaseFeatureDataAdapter {
|
|
|
106
61
|
return intervalTree;
|
|
107
62
|
}
|
|
108
63
|
async loadFeatureIntervalTree(refName) {
|
|
109
|
-
|
|
110
|
-
this.intervalTrees[refName] =
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
});
|
|
114
|
-
}
|
|
64
|
+
this.intervalTrees[refName] ??= this.loadFeatureIntervalTreeHelper(refName).catch((e) => {
|
|
65
|
+
this.intervalTrees[refName] = undefined;
|
|
66
|
+
throw e;
|
|
67
|
+
});
|
|
115
68
|
return this.intervalTrees[refName];
|
|
116
69
|
}
|
|
117
70
|
getFeatures(query, opts = {}) {
|
|
118
|
-
return
|
|
119
|
-
const { start, end, refName } = query;
|
|
120
|
-
const intervalTree = await this.loadFeatureIntervalTree(refName);
|
|
121
|
-
const features = intervalTree?.search([start, end]);
|
|
122
|
-
if (features) {
|
|
123
|
-
for (const f of features) {
|
|
124
|
-
observer.next(f);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
observer.complete();
|
|
128
|
-
}, opts.stopToken);
|
|
71
|
+
return intervalTreeFeatures(query, opts, refName => this.loadFeatureIntervalTree(refName));
|
|
129
72
|
}
|
|
130
73
|
}
|
|
@@ -1,46 +1,95 @@
|
|
|
1
|
+
import type { Instance } from '@jbrowse/mobx-state-tree';
|
|
2
|
+
export declare function normalizeSnapshot(snap: Record<string, unknown>): Record<string, unknown>;
|
|
3
|
+
/**
|
|
4
|
+
* #config BedAdapter
|
|
5
|
+
* #trackType FeatureTrack
|
|
6
|
+
* #fileFormat feature | BED (plain) | Loaded entirely into memory; for small files
|
|
7
|
+
* #gotcha Named BED columns past `name`/`score`/`strand` (`itemRgb`,
|
|
8
|
+
* `thickStart`, ...) are only guaranteed for BED12 or a track with an
|
|
9
|
+
* `autoSql`/`columnNames`. For a BED7-BED11 file JBrowse cannot know what the
|
|
10
|
+
* extra columns mean, so it exposes them generically as `field6`, `field7`,
|
|
11
|
+
* ... and a jexl callback reading `feature.itemRgb` gets `undefined`. Set
|
|
12
|
+
* `columnNames` to refer to them by name.
|
|
13
|
+
*
|
|
14
|
+
* used to load plain-text BED files. Loads the whole file into memory, so
|
|
15
|
+
* prefer the BedTabixAdapter for large files.
|
|
16
|
+
*
|
|
17
|
+
* #example
|
|
18
|
+
* ```js
|
|
19
|
+
* {
|
|
20
|
+
* type: 'BedAdapter',
|
|
21
|
+
* uri: 'https://example.com/features.bed',
|
|
22
|
+
* }
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
1
25
|
declare const BedAdapter: import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaType<{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
26
|
+
/**
|
|
27
|
+
* #slot
|
|
28
|
+
*/
|
|
29
|
+
readonly bedLocation: {
|
|
30
|
+
readonly type: "fileLocation";
|
|
31
|
+
readonly description: "path to bed file, also allows gzipped bed";
|
|
32
|
+
readonly defaultValue: {
|
|
33
|
+
readonly uri: "/path/to/my.bed.gz";
|
|
34
|
+
readonly locationType: "UriLocation";
|
|
8
35
|
};
|
|
9
36
|
};
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
37
|
+
/**
|
|
38
|
+
* #slot
|
|
39
|
+
*/
|
|
40
|
+
readonly columnNames: {
|
|
41
|
+
readonly type: "stringArray";
|
|
42
|
+
readonly 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";
|
|
43
|
+
readonly defaultValue: readonly [];
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* #slot
|
|
47
|
+
*/
|
|
48
|
+
readonly scoreColumn: {
|
|
49
|
+
readonly type: "string";
|
|
50
|
+
readonly description: "The column to use as a \"score\" attribute";
|
|
51
|
+
readonly defaultValue: "";
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* #slot
|
|
55
|
+
*/
|
|
56
|
+
readonly autoSql: {
|
|
57
|
+
readonly type: "string";
|
|
58
|
+
readonly description: "The autoSql definition for the data fields in the file";
|
|
59
|
+
readonly defaultValue: "";
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* #slot
|
|
63
|
+
*/
|
|
64
|
+
readonly colRef: {
|
|
65
|
+
readonly type: "number";
|
|
66
|
+
readonly description: "The column to use as a \"refName\" attribute";
|
|
67
|
+
readonly defaultValue: 0;
|
|
68
|
+
};
|
|
69
|
+
/**
|
|
70
|
+
* #slot
|
|
71
|
+
*/
|
|
72
|
+
readonly colStart: {
|
|
73
|
+
readonly type: "number";
|
|
74
|
+
readonly description: "The column to use as a \"start\" attribute";
|
|
75
|
+
readonly defaultValue: 1;
|
|
76
|
+
};
|
|
77
|
+
/**
|
|
78
|
+
* #slot
|
|
79
|
+
*/
|
|
80
|
+
readonly colEnd: {
|
|
81
|
+
readonly type: "number";
|
|
82
|
+
readonly description: "The column to use as a \"end\" attribute";
|
|
83
|
+
readonly defaultValue: 2;
|
|
84
|
+
};
|
|
85
|
+
/**
|
|
86
|
+
* #slot
|
|
87
|
+
*/
|
|
88
|
+
readonly disableGeneHeuristic: {
|
|
89
|
+
readonly type: "boolean";
|
|
90
|
+
readonly 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)";
|
|
91
|
+
readonly defaultValue: false;
|
|
44
92
|
};
|
|
45
93
|
}, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, undefined>>;
|
|
94
|
+
export type BedAdapterConfig = Instance<typeof BedAdapter>;
|
|
46
95
|
export default BedAdapter;
|
|
@@ -1,6 +1,35 @@
|
|
|
1
1
|
import { ConfigurationSchema } from '@jbrowse/core/configuration';
|
|
2
|
-
function
|
|
2
|
+
export function normalizeSnapshot(snap) {
|
|
3
|
+
return snap.uri
|
|
4
|
+
? { ...snap, bedLocation: { uri: snap.uri, baseUri: snap.baseUri } }
|
|
5
|
+
: snap;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* #config BedAdapter
|
|
9
|
+
* #trackType FeatureTrack
|
|
10
|
+
* #fileFormat feature | BED (plain) | Loaded entirely into memory; for small files
|
|
11
|
+
* #gotcha Named BED columns past `name`/`score`/`strand` (`itemRgb`,
|
|
12
|
+
* `thickStart`, ...) are only guaranteed for BED12 or a track with an
|
|
13
|
+
* `autoSql`/`columnNames`. For a BED7-BED11 file JBrowse cannot know what the
|
|
14
|
+
* extra columns mean, so it exposes them generically as `field6`, `field7`,
|
|
15
|
+
* ... and a jexl callback reading `feature.itemRgb` gets `undefined`. Set
|
|
16
|
+
* `columnNames` to refer to them by name.
|
|
17
|
+
*
|
|
18
|
+
* used to load plain-text BED files. Loads the whole file into memory, so
|
|
19
|
+
* prefer the BedTabixAdapter for large files.
|
|
20
|
+
*
|
|
21
|
+
* #example
|
|
22
|
+
* ```js
|
|
23
|
+
* {
|
|
24
|
+
* type: 'BedAdapter',
|
|
25
|
+
* uri: 'https://example.com/features.bed',
|
|
26
|
+
* }
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
3
29
|
const BedAdapter = ConfigurationSchema('BedAdapter', {
|
|
30
|
+
/**
|
|
31
|
+
* #slot
|
|
32
|
+
*/
|
|
4
33
|
bedLocation: {
|
|
5
34
|
type: 'fileLocation',
|
|
6
35
|
description: 'path to bed file, also allows gzipped bed',
|
|
@@ -9,36 +38,57 @@ const BedAdapter = ConfigurationSchema('BedAdapter', {
|
|
|
9
38
|
locationType: 'UriLocation',
|
|
10
39
|
},
|
|
11
40
|
},
|
|
41
|
+
/**
|
|
42
|
+
* #slot
|
|
43
|
+
*/
|
|
12
44
|
columnNames: {
|
|
13
45
|
type: 'stringArray',
|
|
14
|
-
description:
|
|
46
|
+
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",
|
|
15
47
|
defaultValue: [],
|
|
16
48
|
},
|
|
49
|
+
/**
|
|
50
|
+
* #slot
|
|
51
|
+
*/
|
|
17
52
|
scoreColumn: {
|
|
18
53
|
type: 'string',
|
|
19
54
|
description: 'The column to use as a "score" attribute',
|
|
20
55
|
defaultValue: '',
|
|
21
56
|
},
|
|
57
|
+
/**
|
|
58
|
+
* #slot
|
|
59
|
+
*/
|
|
22
60
|
autoSql: {
|
|
23
61
|
type: 'string',
|
|
24
62
|
description: 'The autoSql definition for the data fields in the file',
|
|
25
63
|
defaultValue: '',
|
|
26
64
|
},
|
|
65
|
+
/**
|
|
66
|
+
* #slot
|
|
67
|
+
*/
|
|
27
68
|
colRef: {
|
|
28
69
|
type: 'number',
|
|
29
70
|
description: 'The column to use as a "refName" attribute',
|
|
30
71
|
defaultValue: 0,
|
|
31
72
|
},
|
|
73
|
+
/**
|
|
74
|
+
* #slot
|
|
75
|
+
*/
|
|
32
76
|
colStart: {
|
|
33
77
|
type: 'number',
|
|
34
78
|
description: 'The column to use as a "start" attribute',
|
|
35
79
|
defaultValue: 1,
|
|
36
80
|
},
|
|
81
|
+
/**
|
|
82
|
+
* #slot
|
|
83
|
+
*/
|
|
37
84
|
colEnd: {
|
|
38
85
|
type: 'number',
|
|
39
86
|
description: 'The column to use as a "end" attribute',
|
|
40
87
|
defaultValue: 2,
|
|
41
88
|
},
|
|
89
|
+
/**
|
|
90
|
+
* #slot
|
|
91
|
+
*/
|
|
42
92
|
disableGeneHeuristic: {
|
|
43
93
|
type: 'boolean',
|
|
44
94
|
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)',
|
|
@@ -46,16 +96,18 @@ const BedAdapter = ConfigurationSchema('BedAdapter', {
|
|
|
46
96
|
},
|
|
47
97
|
}, {
|
|
48
98
|
explicitlyTyped: true,
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
99
|
+
/**
|
|
100
|
+
* #preProcessSnapshot
|
|
101
|
+
*
|
|
102
|
+
*
|
|
103
|
+
* preprocessor to allow minimal config:
|
|
104
|
+
* ```json
|
|
105
|
+
* {
|
|
106
|
+
* "type": "BedAdapter",
|
|
107
|
+
* "uri": "yourfile.bed"
|
|
108
|
+
* }
|
|
109
|
+
* ```
|
|
110
|
+
*/
|
|
111
|
+
preProcessSnapshot: normalizeSnapshot,
|
|
60
112
|
});
|
|
61
113
|
export default BedAdapter;
|
package/esm/BedAdapter/index.js
CHANGED
|
@@ -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 BedAdapterF(pluginManager) {
|
|
4
4
|
pluginManager.addAdapterType(() => new AdapterType({
|
|
5
5
|
name: 'BedAdapter',
|
|
6
6
|
displayName: 'BED adapter',
|
|
7
7
|
configSchema,
|
|
8
|
-
getAdapterClass: () => import(
|
|
8
|
+
getAdapterClass: () => import('./BedAdapter.js').then(r => r.default),
|
|
9
|
+
locationKey: 'bedLocation',
|
|
10
|
+
normalizeSnapshot,
|
|
9
11
|
}));
|
|
10
12
|
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { BaseFeatureDataAdapter } from '@jbrowse/core/data_adapters/BaseAdapter';
|
|
2
2
|
import { IntervalTree } from '@jbrowse/core/util';
|
|
3
|
+
import type { BedGraphAdapterConfig } from './configSchema.ts';
|
|
3
4
|
import type { BaseOptions } from '@jbrowse/core/data_adapters/BaseAdapter';
|
|
4
5
|
import type { Feature, Region } from '@jbrowse/core/util';
|
|
5
|
-
export default class BedGraphAdapter extends BaseFeatureDataAdapter {
|
|
6
|
-
|
|
6
|
+
export default class BedGraphAdapter extends BaseFeatureDataAdapter<BedGraphAdapterConfig> {
|
|
7
|
+
loadData: (opts?: BaseOptions) => Promise<{
|
|
7
8
|
header: string;
|
|
8
9
|
features: Record<string, string[]>;
|
|
9
|
-
columnNames: string[];
|
|
10
10
|
}>;
|
|
11
11
|
protected intervalTrees: Record<string, Promise<IntervalTree<Feature> | undefined> | undefined>;
|
|
12
12
|
getNames(): Promise<string[] | undefined>;
|
|
@@ -14,10 +14,5 @@ export default class BedGraphAdapter extends BaseFeatureDataAdapter {
|
|
|
14
14
|
getRefNames(opts?: BaseOptions): Promise<string[]>;
|
|
15
15
|
private loadDataP;
|
|
16
16
|
loadFeatureIntervalTree(refName: string): Promise<IntervalTree<Feature> | undefined>;
|
|
17
|
-
|
|
18
|
-
header: string;
|
|
19
|
-
features: Record<string, string[]>;
|
|
20
|
-
columnNames: string[];
|
|
21
|
-
}>;
|
|
22
|
-
getFeatures(query: Region, _opts?: BaseOptions): import("rxjs").Observable<Feature>;
|
|
17
|
+
getFeatures(query: Region, opts?: BaseOptions): import("rxjs").Observable<Feature>;
|
|
23
18
|
}
|
|
@@ -1,24 +1,15 @@
|
|
|
1
|
-
import { BaseFeatureDataAdapter } from '@jbrowse/core/data_adapters/BaseAdapter';
|
|
2
|
-
import { IntervalTree,
|
|
1
|
+
import { BaseFeatureDataAdapter, cachedSetup, } from '@jbrowse/core/data_adapters/BaseAdapter';
|
|
2
|
+
import { IntervalTree, fetchAndMaybeUnzip } from '@jbrowse/core/util';
|
|
3
3
|
import { openLocation } from '@jbrowse/core/util/io';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { intervalTreeFeatures } from '../adapterUtil.js';
|
|
5
|
+
import { makeBedGraphFeature } from '../bedGraphUtil.js';
|
|
6
|
+
import { bucketBedLines, resolveColumnNames } from '../util.js';
|
|
6
7
|
export default class BedGraphAdapter extends BaseFeatureDataAdapter {
|
|
7
|
-
|
|
8
|
+
// No `label`: `fetchAndMaybeUnzip` narrates the download from inside.
|
|
9
|
+
loadData = cachedSetup({ setup: opts => this.loadDataP(opts) });
|
|
8
10
|
intervalTrees = {};
|
|
9
11
|
async getNames() {
|
|
10
|
-
|
|
11
|
-
if (columnNames.length) {
|
|
12
|
-
return columnNames;
|
|
13
|
-
}
|
|
14
|
-
const defs = header.split(/\n|\r\n|\r/).filter(f => !!f);
|
|
15
|
-
const defline = defs.at(-1);
|
|
16
|
-
return defline?.includes('\t')
|
|
17
|
-
? defline
|
|
18
|
-
.slice(1)
|
|
19
|
-
.split('\t')
|
|
20
|
-
.map(field => field.trim())
|
|
21
|
-
: undefined;
|
|
12
|
+
return resolveColumnNames(this.getConf('columnNames'), async () => (await this.loadData()).header);
|
|
22
13
|
}
|
|
23
14
|
async loadFeatureIntervalTreeHelper(refName) {
|
|
24
15
|
const { features } = await this.loadData();
|
|
@@ -26,28 +17,24 @@ export default class BedGraphAdapter extends BaseFeatureDataAdapter {
|
|
|
26
17
|
if (!lines) {
|
|
27
18
|
return undefined;
|
|
28
19
|
}
|
|
29
|
-
const names = (await this.getNames())?.slice(3)
|
|
20
|
+
const names = (await this.getNames())?.slice(3) ?? [];
|
|
30
21
|
const intervalTree = new IntervalTree();
|
|
31
22
|
for (let i = 0, l = lines.length; i < l; i++) {
|
|
32
|
-
const
|
|
33
|
-
const
|
|
23
|
+
const [refName, s, e, ...rest] = lines[i].split('\t');
|
|
24
|
+
const start = +s;
|
|
25
|
+
const end = +e;
|
|
34
26
|
for (let j = 0, l2 = rest.length; j < l2; j++) {
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
end,
|
|
47
|
-
score,
|
|
48
|
-
source,
|
|
49
|
-
},
|
|
50
|
-
}));
|
|
27
|
+
const feat = makeBedGraphFeature({
|
|
28
|
+
uniqueId: `${this.id}-${refName}-${i}-${j}`,
|
|
29
|
+
refName: refName,
|
|
30
|
+
start,
|
|
31
|
+
end,
|
|
32
|
+
names,
|
|
33
|
+
j,
|
|
34
|
+
value: rest[j],
|
|
35
|
+
});
|
|
36
|
+
if (feat) {
|
|
37
|
+
intervalTree.insert([start, end], feat);
|
|
51
38
|
}
|
|
52
39
|
}
|
|
53
40
|
}
|
|
@@ -58,58 +45,17 @@ export default class BedGraphAdapter extends BaseFeatureDataAdapter {
|
|
|
58
45
|
return Object.keys(features);
|
|
59
46
|
}
|
|
60
47
|
async loadDataP(opts = {}) {
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
const buffer = await fetchAndMaybeUnzip(openLocation(bedLoc, pm), opts);
|
|
64
|
-
const features = {};
|
|
65
|
-
const headerLines = [];
|
|
66
|
-
parseLineByLine(buffer, line => {
|
|
67
|
-
if (line.startsWith('#')) {
|
|
68
|
-
headerLines.push(line);
|
|
69
|
-
}
|
|
70
|
-
else {
|
|
71
|
-
const tab = line.indexOf('\t');
|
|
72
|
-
const refName = line.slice(0, tab);
|
|
73
|
-
if (!features[refName]) {
|
|
74
|
-
features[refName] = [];
|
|
75
|
-
}
|
|
76
|
-
features[refName].push(line);
|
|
77
|
-
}
|
|
78
|
-
return true;
|
|
79
|
-
}, opts.statusCallback);
|
|
80
|
-
const columnNames = this.getConf('columnNames');
|
|
81
|
-
return {
|
|
82
|
-
header: headerLines.join('\n'),
|
|
83
|
-
features,
|
|
84
|
-
columnNames,
|
|
85
|
-
};
|
|
48
|
+
const buffer = await fetchAndMaybeUnzip(openLocation(this.getConf('bedGraphLocation'), this.pluginManager), opts);
|
|
49
|
+
return bucketBedLines(buffer, opts.statusCallback);
|
|
86
50
|
}
|
|
87
51
|
async loadFeatureIntervalTree(refName) {
|
|
88
|
-
|
|
89
|
-
this.intervalTrees[refName] =
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
});
|
|
93
|
-
}
|
|
52
|
+
this.intervalTrees[refName] ??= this.loadFeatureIntervalTreeHelper(refName).catch((e) => {
|
|
53
|
+
this.intervalTrees[refName] = undefined;
|
|
54
|
+
throw e;
|
|
55
|
+
});
|
|
94
56
|
return this.intervalTrees[refName];
|
|
95
57
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
this.bedFeatures = this.loadDataP(opts).catch((e) => {
|
|
99
|
-
this.bedFeatures = undefined;
|
|
100
|
-
throw e;
|
|
101
|
-
});
|
|
102
|
-
}
|
|
103
|
-
return this.bedFeatures;
|
|
104
|
-
}
|
|
105
|
-
getFeatures(query, _opts = {}) {
|
|
106
|
-
return ObservableCreate(async (observer) => {
|
|
107
|
-
const { start, end, refName } = query;
|
|
108
|
-
const intervalTree = await this.loadFeatureIntervalTree(refName);
|
|
109
|
-
for (const feature of intervalTree?.search([start, end]) || []) {
|
|
110
|
-
observer.next(feature);
|
|
111
|
-
}
|
|
112
|
-
observer.complete();
|
|
113
|
-
});
|
|
58
|
+
getFeatures(query, opts = {}) {
|
|
59
|
+
return intervalTreeFeatures(query, opts, refName => this.loadFeatureIntervalTree(refName));
|
|
114
60
|
}
|
|
115
61
|
}
|