@jbrowse/plugin-bed 2.10.3 → 2.11.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.
@@ -7,9 +7,10 @@ const bed_1 = __importDefault(require("@gmod/bed"));
7
7
  const BaseAdapter_1 = require("@jbrowse/core/data_adapters/BaseAdapter");
8
8
  const io_1 = require("@jbrowse/core/util/io");
9
9
  const rxjs_1 = require("@jbrowse/core/util/rxjs");
10
- const util_1 = require("../util");
11
10
  const interval_tree_1 = __importDefault(require("@flatten-js/interval-tree"));
12
11
  const bgzf_filehandle_1 = require("@gmod/bgzf-filehandle");
12
+ // locals
13
+ const util_1 = require("../util");
13
14
  function isGzip(buf) {
14
15
  return buf[0] === 31 && buf[1] === 139 && buf[2] === 8;
15
16
  }
@@ -1,4 +1,4 @@
1
- import { BigBed } from '@gmod/bbi';
1
+ import { BigBed, Header } from '@gmod/bbi';
2
2
  import BED from '@gmod/bed';
3
3
  import { BaseFeatureDataAdapter, BaseOptions } from '@jbrowse/core/data_adapters/BaseAdapter';
4
4
  import { Region } from '@jbrowse/core/util/types';
@@ -7,18 +7,18 @@ export default class BigBedAdapter extends BaseFeatureDataAdapter {
7
7
  private cached?;
8
8
  configurePre(opts?: BaseOptions): Promise<{
9
9
  bigbed: BigBed;
10
- header: import("@gmod/bbi").Header;
10
+ header: Header;
11
11
  parser: BED;
12
12
  }>;
13
13
  configure(opts?: BaseOptions): Promise<{
14
14
  bigbed: BigBed;
15
- header: any;
15
+ header: Header;
16
16
  parser: BED;
17
17
  }>;
18
18
  getRefNames(opts?: BaseOptions): Promise<string[]>;
19
19
  getHeader(opts?: BaseOptions): Promise<{
20
20
  version: any;
21
- fileType: any;
21
+ fileType: string;
22
22
  autoSql: {};
23
23
  fields: {
24
24
  [k: string]: string;
@@ -3,7 +3,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- /* eslint-disable @typescript-eslint/no-explicit-any */
7
6
  const bbi_1 = require("@gmod/bbi");
8
7
  const bed_1 = __importDefault(require("@gmod/bed"));
9
8
  const BaseAdapter_1 = require("@jbrowse/core/data_adapters/BaseAdapter");
@@ -11,10 +10,8 @@ const io_1 = require("@jbrowse/core/util/io");
11
10
  const rxjs_1 = require("@jbrowse/core/util/rxjs");
12
11
  const simpleFeature_1 = __importDefault(require("@jbrowse/core/util/simpleFeature"));
13
12
  const operators_1 = require("rxjs/operators");
13
+ // locals
14
14
  const util_1 = require("../util");
15
- function isUCSC(f) {
16
- return f.get('thickStart') && f.get('blockCount') && f.get('strand') !== 0;
17
- }
18
15
  class BigBedAdapter extends BaseAdapter_1.BaseFeatureDataAdapter {
19
16
  async configurePre(opts) {
20
17
  const pm = this.pluginManager;
@@ -40,6 +37,7 @@ class BigBedAdapter extends BaseAdapter_1.BaseFeatureDataAdapter {
40
37
  }
41
38
  async getHeader(opts) {
42
39
  const { parser, header } = await this.configure(opts);
40
+ // @ts-expect-error
43
41
  const { version, fileType } = header;
44
42
  const { fields, ...rest } = parser.autoSql;
45
43
  return {
@@ -50,53 +48,66 @@ class BigBedAdapter extends BaseAdapter_1.BaseFeatureDataAdapter {
50
48
  };
51
49
  }
52
50
  getFeatures(region, opts = {}) {
53
- const { refName, start, end } = region;
54
51
  const { signal } = opts;
52
+ const scoreColumn = this.getConf('scoreColumn');
55
53
  return (0, rxjs_1.ObservableCreate)(async (observer) => {
56
54
  try {
57
55
  const { parser, bigbed } = await this.configure(opts);
58
- const ob = await bigbed.getFeatureStream(refName, start, end, {
56
+ const ob = await bigbed.getFeatureStream(region.refName, region.start, region.end, {
59
57
  signal,
60
- basesPerSpan: end - start,
58
+ basesPerSpan: region.end - region.start,
61
59
  });
62
- ob.pipe((0, operators_1.mergeAll)(), (0, operators_1.map)(r => {
63
- const data = parser.parseLine(`${refName}\t${r.start}\t${r.end}\t${r.rest}`, {
64
- uniqueId: r.uniqueId,
60
+ ob.pipe((0, operators_1.mergeAll)(), (0, operators_1.map)(feat => {
61
+ const data = parser.parseLine(`${region.refName}\t${feat.start}\t${feat.end}\t${feat.rest}`, {
62
+ uniqueId: feat.uniqueId,
65
63
  });
66
- const { blockCount, blockSizes, blockStarts, chromStarts } = data;
67
- if (blockCount) {
68
- const starts = chromStarts || blockStarts || [];
69
- const sizes = blockSizes;
70
- const blocksOffset = r.start;
71
- data.subfeatures = [];
72
- for (let b = 0; b < blockCount; b += 1) {
73
- const bmin = (starts[b] || 0) + blocksOffset;
74
- const bmax = bmin + (sizes[b] || 0);
75
- data.subfeatures.push({
76
- uniqueId: `${r.uniqueId}-${b}`,
77
- start: bmin,
78
- end: bmax,
79
- type: 'block',
80
- });
81
- }
82
- }
83
- if (r.uniqueId === undefined) {
64
+ if (feat.uniqueId === undefined) {
84
65
  throw new Error('invalid bbi feature');
85
66
  }
86
- const { chromStart, chromEnd, chrom, ...rest } = data;
87
- const f = new simpleFeature_1.default({
88
- id: `${this.id}-${r.uniqueId}`,
89
- data: {
90
- ...rest,
91
- start: r.start,
92
- end: r.end,
93
- refName,
94
- },
67
+ const { uniqueId, type, chromStart, chromStarts, blockStarts, blockCount, blockSizes, chromEnd, thickStart, thickEnd, chrom, score, ...rest } = data;
68
+ const subfeatures = blockCount
69
+ ? (0, util_1.makeBlocks)({
70
+ chromStarts,
71
+ blockStarts,
72
+ blockCount,
73
+ blockSizes,
74
+ uniqueId,
75
+ refName: region.refName,
76
+ start: feat.start,
77
+ })
78
+ : [];
79
+ // collection of heuristics for suggesting that this feature should
80
+ // be converted to a gene, CNV bigbed has many gene like features
81
+ // including thickStart and blockCount but no strand
82
+ return new simpleFeature_1.default({
83
+ id: `${this.id}-${uniqueId}`,
84
+ data: (0, util_1.isUCSC)(data)
85
+ ? (0, util_1.ucscProcessedTranscript)({
86
+ ...rest,
87
+ uniqueId,
88
+ type,
89
+ start: feat.start,
90
+ end: feat.end,
91
+ refName: region.refName,
92
+ score: scoreColumn ? +data[scoreColumn] : score,
93
+ chromStarts,
94
+ blockCount,
95
+ blockSizes,
96
+ thickStart,
97
+ thickEnd,
98
+ subfeatures,
99
+ })
100
+ : {
101
+ ...rest,
102
+ uniqueId,
103
+ type,
104
+ start: feat.start,
105
+ score: scoreColumn ? +data[scoreColumn] : score,
106
+ end: feat.end,
107
+ refName: region.refName,
108
+ subfeatures,
109
+ },
95
110
  });
96
- // collection of heuristics for suggesting that this feature
97
- // should be converted to a gene, CNV bigbed has many gene like
98
- // features including thickStart and blockCount but no strand
99
- return isUCSC(f) ? (0, util_1.ucscProcessedTranscript)(f) : f;
100
111
  })).subscribe(observer);
101
112
  }
102
113
  catch (e) {
@@ -9,5 +9,13 @@ declare const BigBedAdapter: import("@jbrowse/core/configuration/configurationSc
9
9
  locationType: string;
10
10
  };
11
11
  };
12
+ /**
13
+ * #slot
14
+ */
15
+ scoreColumn: {
16
+ type: string;
17
+ description: string;
18
+ defaultValue: string;
19
+ };
12
20
  }, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, undefined>>;
13
21
  export default BigBedAdapter;
@@ -13,5 +13,13 @@ const BigBedAdapter = (0, configuration_1.ConfigurationSchema)('BigBedAdapter',
13
13
  type: 'fileLocation',
14
14
  defaultValue: { uri: '/path/to/my.bb', locationType: 'UriLocation' },
15
15
  },
16
+ /**
17
+ * #slot
18
+ */
19
+ scoreColumn: {
20
+ type: 'string',
21
+ description: 'The column to use as a "score" attribute',
22
+ defaultValue: '',
23
+ },
16
24
  }, { explicitlyTyped: true });
17
25
  exports.default = BigBedAdapter;
package/dist/util.d.ts CHANGED
@@ -1,4 +1,47 @@
1
- import { SimpleFeature, Feature } from '@jbrowse/core/util';
2
1
  import BED from '@gmod/bed';
3
- export declare function ucscProcessedTranscript(feature: Feature): Feature | SimpleFeature;
4
- export declare function featureData(line: string, colRef: number, colStart: number, colEnd: number, scoreColumn: string, parser: BED, uniqueId: string, names?: string[]): Feature | SimpleFeature;
2
+ import { SimpleFeature } from '@jbrowse/core/util';
3
+ interface MinimalFeature {
4
+ type: string;
5
+ start: number;
6
+ end: number;
7
+ refName: string;
8
+ }
9
+ interface TranscriptFeat {
10
+ thickStart: number;
11
+ thickEnd: number;
12
+ blockCount: number;
13
+ blockSizes: number[];
14
+ chromStarts: number[];
15
+ refName: string;
16
+ strand?: number;
17
+ subfeatures: MinimalFeature[];
18
+ [key: string]: unknown;
19
+ }
20
+ export declare function ucscProcessedTranscript(feature: TranscriptFeat): TranscriptFeat | {
21
+ strand: number;
22
+ type: string;
23
+ refName: string;
24
+ subfeatures: MinimalFeature[];
25
+ };
26
+ export declare function makeBlocks({ start, uniqueId, refName, chromStarts, blockCount, blockSizes, blockStarts, }: {
27
+ blockCount: number;
28
+ start: number;
29
+ uniqueId: string;
30
+ refName: string;
31
+ chromStarts: number[];
32
+ blockSizes: number[];
33
+ blockStarts: number[];
34
+ }): {
35
+ uniqueId: string;
36
+ start: number;
37
+ end: number;
38
+ refName: string;
39
+ type: string;
40
+ }[];
41
+ export declare function featureData(line: string, colRef: number, colStart: number, colEnd: number, scoreColumn: string, parser: BED, uniqueId: string, names?: string[]): SimpleFeature;
42
+ export declare function isUCSC(f: {
43
+ thickStart?: number;
44
+ blockCount?: number;
45
+ strand?: number;
46
+ }): boolean | 0 | undefined;
47
+ export {};
package/dist/util.js CHANGED
@@ -1,29 +1,23 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.featureData = exports.ucscProcessedTranscript = void 0;
3
+ exports.isUCSC = exports.featureData = exports.makeBlocks = exports.ucscProcessedTranscript = void 0;
4
4
  const util_1 = require("@jbrowse/core/util");
5
5
  function ucscProcessedTranscript(feature) {
6
- const children = feature.children();
7
- // split the blocks into UTR, CDS, and exons
8
- const thickStart = feature.get('thickStart');
9
- const thickEnd = feature.get('thickEnd');
10
- const refName = feature.get('refName');
11
- if (!thickStart && !thickEnd) {
6
+ var _a;
7
+ const { subfeatures: oldSubfeatures, thickStart, thickEnd, blockCount, blockSizes, chromStarts, refName, strand = 0, ...rest } = feature;
8
+ if (!thickStart || !thickEnd || !strand) {
12
9
  return feature;
13
10
  }
14
- const blocks = children
15
- ? children
16
- .filter(child => child.get('type') === 'block')
17
- .sort((a, b) => a.get('start') - b.get('start'))
18
- : [];
19
- const newChildren = [];
20
- blocks.forEach(block => {
21
- const start = block.get('start');
22
- const end = block.get('end');
11
+ const subfeatures = [];
12
+ (_a = oldSubfeatures
13
+ .filter(child => child.type === 'block')
14
+ .sort((a, b) => a.start - b.start)) === null || _a === void 0 ? void 0 : _a.forEach(block => {
15
+ const start = block.start;
16
+ const end = block.end;
23
17
  if (thickStart >= end) {
24
18
  // left-side UTR
25
- const prime = feature.get('strand') > 0 ? 'five' : 'three';
26
- newChildren.push({
19
+ const prime = strand > 0 ? 'five' : 'three';
20
+ subfeatures.push({
27
21
  type: `${prime}_prime_UTR`,
28
22
  start,
29
23
  end,
@@ -32,8 +26,8 @@ function ucscProcessedTranscript(feature) {
32
26
  }
33
27
  else if (thickStart > start && thickStart < end && thickEnd >= end) {
34
28
  // UTR | CDS
35
- const prime = feature.get('strand') > 0 ? 'five' : 'three';
36
- newChildren.push({
29
+ const prime = strand > 0 ? 'five' : 'three';
30
+ subfeatures.push({
37
31
  type: `${prime}_prime_UTR`,
38
32
  start,
39
33
  end: thickStart,
@@ -47,7 +41,7 @@ function ucscProcessedTranscript(feature) {
47
41
  }
48
42
  else if (thickStart <= start && thickEnd >= end) {
49
43
  // CDS
50
- newChildren.push({
44
+ subfeatures.push({
51
45
  type: 'CDS',
52
46
  start,
53
47
  end,
@@ -56,9 +50,9 @@ function ucscProcessedTranscript(feature) {
56
50
  }
57
51
  else if (thickStart > start && thickStart < end && thickEnd < end) {
58
52
  // UTR | CDS | UTR
59
- const leftPrime = feature.get('strand') > 0 ? 'five' : 'three';
60
- const rightPrime = feature.get('strand') > 0 ? 'three' : 'five';
61
- newChildren.push({
53
+ const leftPrime = strand > 0 ? 'five' : 'three';
54
+ const rightPrime = strand > 0 ? 'three' : 'five';
55
+ subfeatures.push({
62
56
  type: `${leftPrime}_prime_UTR`,
63
57
  start,
64
58
  end: thickStart,
@@ -77,8 +71,8 @@ function ucscProcessedTranscript(feature) {
77
71
  }
78
72
  else if (thickStart <= start && thickEnd > start && thickEnd < end) {
79
73
  // CDS | UTR
80
- const prime = feature.get('strand') > 0 ? 'three' : 'five';
81
- newChildren.push({
74
+ const prime = strand > 0 ? 'three' : 'five';
75
+ subfeatures.push({
82
76
  type: `CDS`,
83
77
  start,
84
78
  end: thickEnd,
@@ -92,8 +86,8 @@ function ucscProcessedTranscript(feature) {
92
86
  }
93
87
  else if (thickEnd <= start) {
94
88
  // right-side UTR
95
- const prime = feature.get('strand') > 0 ? 'three' : 'five';
96
- newChildren.push({
89
+ const prime = strand > 0 ? 'three' : 'five';
90
+ subfeatures.push({
97
91
  type: `${prime}_prime_UTR`,
98
92
  start,
99
93
  end,
@@ -101,28 +95,38 @@ function ucscProcessedTranscript(feature) {
101
95
  });
102
96
  }
103
97
  });
104
- const newData = Object.fromEntries(feature.tags().map(tag => [tag, feature.get(tag)]));
105
- newData.subfeatures = newChildren;
106
- newData.type = 'mRNA';
107
- newData.uniqueId = feature.id();
108
- delete newData.chromStarts;
109
- delete newData.chromStart;
110
- delete newData.chromEnd;
111
- delete newData.chrom;
112
- delete newData.blockStarts;
113
- delete newData.blockSizes;
114
- delete newData.blockCount;
115
- delete newData.thickStart;
116
- delete newData.thickEnd;
117
- return new util_1.SimpleFeature({
118
- data: newData,
119
- id: feature.id(),
120
- });
98
+ return { ...rest, strand, type: 'mRNA', refName, subfeatures };
121
99
  }
122
100
  exports.ucscProcessedTranscript = ucscProcessedTranscript;
123
101
  function defaultParser(fields, line) {
124
- return Object.fromEntries(line.split('\t').map((f, i) => [fields[i], f]));
102
+ const { blockStarts, blockCount, chromStarts, thickEnd, thickStart, blockSizes, ...rest } = Object.fromEntries(line.split('\t').map((f, i) => [fields[i], f]));
103
+ return {
104
+ ...rest,
105
+ blockStarts: blockStarts === null || blockStarts === void 0 ? void 0 : blockStarts.split(',').map(r => +r),
106
+ chromStarts: chromStarts === null || chromStarts === void 0 ? void 0 : chromStarts.split(',').map(r => +r),
107
+ blockSizes: blockSizes === null || blockSizes === void 0 ? void 0 : blockSizes.split(',').map(r => +r),
108
+ thickStart: +thickStart,
109
+ thickEnd: +thickEnd,
110
+ blockCount: +blockCount,
111
+ };
125
112
  }
113
+ function makeBlocks({ start, uniqueId, refName, chromStarts, blockCount, blockSizes, blockStarts, }) {
114
+ const subfeatures = [];
115
+ const starts = chromStarts || blockStarts || [];
116
+ for (let b = 0; b < blockCount; b++) {
117
+ const bmin = (starts[b] || 0) + start;
118
+ const bmax = bmin + ((blockSizes === null || blockSizes === void 0 ? void 0 : blockSizes[b]) || 0);
119
+ subfeatures.push({
120
+ uniqueId: `${uniqueId}-${b}`,
121
+ start: bmin,
122
+ end: bmax,
123
+ refName,
124
+ type: 'block',
125
+ });
126
+ }
127
+ return subfeatures;
128
+ }
129
+ exports.makeBlocks = makeBlocks;
126
130
  function featureData(line, colRef, colStart, colEnd, scoreColumn, parser, uniqueId, names) {
127
131
  const l = line.split('\t');
128
132
  const refName = l[colRef];
@@ -132,37 +136,44 @@ function featureData(line, colRef, colStart, colEnd, scoreColumn, parser, unique
132
136
  const data = names
133
137
  ? defaultParser(names, line)
134
138
  : parser.parseLine(line, { uniqueId });
135
- const { blockCount, blockSizes, blockStarts, chromStarts } = data;
136
- if (blockCount) {
137
- const starts = chromStarts || blockStarts || [];
138
- const sizes = blockSizes;
139
- const blocksOffset = start;
140
- data.subfeatures = [];
141
- for (let b = 0; b < blockCount; b += 1) {
142
- const bmin = (starts[b] || 0) + blocksOffset;
143
- const bmax = bmin + (sizes[b] || 0);
144
- data.subfeatures.push({
145
- uniqueId: `${uniqueId}-${b}`,
146
- start: bmin,
147
- end: bmax,
148
- refName,
149
- type: 'block',
150
- });
151
- }
152
- }
153
- if (scoreColumn) {
154
- data.score = +data[scoreColumn];
155
- }
156
- delete data.chrom;
157
- delete data.chromStart;
158
- delete data.chromEnd;
159
- const f = new util_1.SimpleFeature({
160
- ...data,
139
+ const { blockCount, blockSizes, blockStarts, chromStarts, thickStart, thickEnd, type, score, chrom: _1, chromStart: _2, chromEnd: _3, ...rest } = data;
140
+ const subfeatures = blockCount
141
+ ? makeBlocks({
142
+ start,
143
+ uniqueId,
144
+ refName,
145
+ chromStarts,
146
+ blockCount,
147
+ blockSizes,
148
+ blockStarts,
149
+ })
150
+ : [];
151
+ const f = {
152
+ ...rest,
153
+ type,
154
+ score: scoreColumn ? +data[scoreColumn] : score,
161
155
  start,
162
156
  end,
163
157
  refName,
164
158
  uniqueId,
159
+ subfeatures,
160
+ };
161
+ return new util_1.SimpleFeature({
162
+ id: uniqueId,
163
+ data: isUCSC(data)
164
+ ? ucscProcessedTranscript({
165
+ thickStart,
166
+ thickEnd,
167
+ blockCount,
168
+ blockSizes,
169
+ chromStarts,
170
+ ...f,
171
+ })
172
+ : f,
165
173
  });
166
- return f.get('thickStart') ? ucscProcessedTranscript(f) : f;
167
174
  }
168
175
  exports.featureData = featureData;
176
+ function isUCSC(f) {
177
+ return f.thickStart && f.blockCount && f.strand !== 0;
178
+ }
179
+ exports.isUCSC = isUCSC;
@@ -2,9 +2,10 @@ import BED from '@gmod/bed';
2
2
  import { BaseFeatureDataAdapter, } from '@jbrowse/core/data_adapters/BaseAdapter';
3
3
  import { openLocation } from '@jbrowse/core/util/io';
4
4
  import { ObservableCreate } from '@jbrowse/core/util/rxjs';
5
- import { featureData } from '../util';
6
5
  import IntervalTree from '@flatten-js/interval-tree';
7
6
  import { unzip } from '@gmod/bgzf-filehandle';
7
+ // locals
8
+ import { featureData } from '../util';
8
9
  function isGzip(buf) {
9
10
  return buf[0] === 31 && buf[1] === 139 && buf[2] === 8;
10
11
  }
@@ -1,4 +1,4 @@
1
- import { BigBed } from '@gmod/bbi';
1
+ import { BigBed, Header } from '@gmod/bbi';
2
2
  import BED from '@gmod/bed';
3
3
  import { BaseFeatureDataAdapter, BaseOptions } from '@jbrowse/core/data_adapters/BaseAdapter';
4
4
  import { Region } from '@jbrowse/core/util/types';
@@ -7,18 +7,18 @@ export default class BigBedAdapter extends BaseFeatureDataAdapter {
7
7
  private cached?;
8
8
  configurePre(opts?: BaseOptions): Promise<{
9
9
  bigbed: BigBed;
10
- header: import("@gmod/bbi").Header;
10
+ header: Header;
11
11
  parser: BED;
12
12
  }>;
13
13
  configure(opts?: BaseOptions): Promise<{
14
14
  bigbed: BigBed;
15
- header: any;
15
+ header: Header;
16
16
  parser: BED;
17
17
  }>;
18
18
  getRefNames(opts?: BaseOptions): Promise<string[]>;
19
19
  getHeader(opts?: BaseOptions): Promise<{
20
20
  version: any;
21
- fileType: any;
21
+ fileType: string;
22
22
  autoSql: {};
23
23
  fields: {
24
24
  [k: string]: string;
@@ -1,4 +1,3 @@
1
- /* eslint-disable @typescript-eslint/no-explicit-any */
2
1
  import { BigBed } from '@gmod/bbi';
3
2
  import BED from '@gmod/bed';
4
3
  import { BaseFeatureDataAdapter, } from '@jbrowse/core/data_adapters/BaseAdapter';
@@ -6,10 +5,8 @@ import { openLocation } from '@jbrowse/core/util/io';
6
5
  import { ObservableCreate } from '@jbrowse/core/util/rxjs';
7
6
  import SimpleFeature from '@jbrowse/core/util/simpleFeature';
8
7
  import { map, mergeAll } from 'rxjs/operators';
9
- import { ucscProcessedTranscript } from '../util';
10
- function isUCSC(f) {
11
- return f.get('thickStart') && f.get('blockCount') && f.get('strand') !== 0;
12
- }
8
+ // locals
9
+ import { isUCSC, makeBlocks, ucscProcessedTranscript } from '../util';
13
10
  export default class BigBedAdapter extends BaseFeatureDataAdapter {
14
11
  async configurePre(opts) {
15
12
  const pm = this.pluginManager;
@@ -35,6 +32,7 @@ export default class BigBedAdapter extends BaseFeatureDataAdapter {
35
32
  }
36
33
  async getHeader(opts) {
37
34
  const { parser, header } = await this.configure(opts);
35
+ // @ts-expect-error
38
36
  const { version, fileType } = header;
39
37
  const { fields, ...rest } = parser.autoSql;
40
38
  return {
@@ -45,53 +43,66 @@ export default class BigBedAdapter extends BaseFeatureDataAdapter {
45
43
  };
46
44
  }
47
45
  getFeatures(region, opts = {}) {
48
- const { refName, start, end } = region;
49
46
  const { signal } = opts;
47
+ const scoreColumn = this.getConf('scoreColumn');
50
48
  return ObservableCreate(async (observer) => {
51
49
  try {
52
50
  const { parser, bigbed } = await this.configure(opts);
53
- const ob = await bigbed.getFeatureStream(refName, start, end, {
51
+ const ob = await bigbed.getFeatureStream(region.refName, region.start, region.end, {
54
52
  signal,
55
- basesPerSpan: end - start,
53
+ basesPerSpan: region.end - region.start,
56
54
  });
57
- ob.pipe(mergeAll(), map(r => {
58
- const data = parser.parseLine(`${refName}\t${r.start}\t${r.end}\t${r.rest}`, {
59
- uniqueId: r.uniqueId,
55
+ ob.pipe(mergeAll(), map(feat => {
56
+ const data = parser.parseLine(`${region.refName}\t${feat.start}\t${feat.end}\t${feat.rest}`, {
57
+ uniqueId: feat.uniqueId,
60
58
  });
61
- const { blockCount, blockSizes, blockStarts, chromStarts } = data;
62
- if (blockCount) {
63
- const starts = chromStarts || blockStarts || [];
64
- const sizes = blockSizes;
65
- const blocksOffset = r.start;
66
- data.subfeatures = [];
67
- for (let b = 0; b < blockCount; b += 1) {
68
- const bmin = (starts[b] || 0) + blocksOffset;
69
- const bmax = bmin + (sizes[b] || 0);
70
- data.subfeatures.push({
71
- uniqueId: `${r.uniqueId}-${b}`,
72
- start: bmin,
73
- end: bmax,
74
- type: 'block',
75
- });
76
- }
77
- }
78
- if (r.uniqueId === undefined) {
59
+ if (feat.uniqueId === undefined) {
79
60
  throw new Error('invalid bbi feature');
80
61
  }
81
- const { chromStart, chromEnd, chrom, ...rest } = data;
82
- const f = new SimpleFeature({
83
- id: `${this.id}-${r.uniqueId}`,
84
- data: {
85
- ...rest,
86
- start: r.start,
87
- end: r.end,
88
- refName,
89
- },
62
+ const { uniqueId, type, chromStart, chromStarts, blockStarts, blockCount, blockSizes, chromEnd, thickStart, thickEnd, chrom, score, ...rest } = data;
63
+ const subfeatures = blockCount
64
+ ? makeBlocks({
65
+ chromStarts,
66
+ blockStarts,
67
+ blockCount,
68
+ blockSizes,
69
+ uniqueId,
70
+ refName: region.refName,
71
+ start: feat.start,
72
+ })
73
+ : [];
74
+ // collection of heuristics for suggesting that this feature should
75
+ // be converted to a gene, CNV bigbed has many gene like features
76
+ // including thickStart and blockCount but no strand
77
+ return new SimpleFeature({
78
+ id: `${this.id}-${uniqueId}`,
79
+ data: isUCSC(data)
80
+ ? ucscProcessedTranscript({
81
+ ...rest,
82
+ uniqueId,
83
+ type,
84
+ start: feat.start,
85
+ end: feat.end,
86
+ refName: region.refName,
87
+ score: scoreColumn ? +data[scoreColumn] : score,
88
+ chromStarts,
89
+ blockCount,
90
+ blockSizes,
91
+ thickStart,
92
+ thickEnd,
93
+ subfeatures,
94
+ })
95
+ : {
96
+ ...rest,
97
+ uniqueId,
98
+ type,
99
+ start: feat.start,
100
+ score: scoreColumn ? +data[scoreColumn] : score,
101
+ end: feat.end,
102
+ refName: region.refName,
103
+ subfeatures,
104
+ },
90
105
  });
91
- // collection of heuristics for suggesting that this feature
92
- // should be converted to a gene, CNV bigbed has many gene like
93
- // features including thickStart and blockCount but no strand
94
- return isUCSC(f) ? ucscProcessedTranscript(f) : f;
95
106
  })).subscribe(observer);
96
107
  }
97
108
  catch (e) {
@@ -9,5 +9,13 @@ declare const BigBedAdapter: import("@jbrowse/core/configuration/configurationSc
9
9
  locationType: string;
10
10
  };
11
11
  };
12
+ /**
13
+ * #slot
14
+ */
15
+ scoreColumn: {
16
+ type: string;
17
+ description: string;
18
+ defaultValue: string;
19
+ };
12
20
  }, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, undefined>>;
13
21
  export default BigBedAdapter;
@@ -11,5 +11,13 @@ const BigBedAdapter = ConfigurationSchema('BigBedAdapter', {
11
11
  type: 'fileLocation',
12
12
  defaultValue: { uri: '/path/to/my.bb', locationType: 'UriLocation' },
13
13
  },
14
+ /**
15
+ * #slot
16
+ */
17
+ scoreColumn: {
18
+ type: 'string',
19
+ description: 'The column to use as a "score" attribute',
20
+ defaultValue: '',
21
+ },
14
22
  }, { explicitlyTyped: true });
15
23
  export default BigBedAdapter;
package/esm/util.d.ts CHANGED
@@ -1,4 +1,47 @@
1
- import { SimpleFeature, Feature } from '@jbrowse/core/util';
2
1
  import BED from '@gmod/bed';
3
- export declare function ucscProcessedTranscript(feature: Feature): Feature | SimpleFeature;
4
- export declare function featureData(line: string, colRef: number, colStart: number, colEnd: number, scoreColumn: string, parser: BED, uniqueId: string, names?: string[]): Feature | SimpleFeature;
2
+ import { SimpleFeature } from '@jbrowse/core/util';
3
+ interface MinimalFeature {
4
+ type: string;
5
+ start: number;
6
+ end: number;
7
+ refName: string;
8
+ }
9
+ interface TranscriptFeat {
10
+ thickStart: number;
11
+ thickEnd: number;
12
+ blockCount: number;
13
+ blockSizes: number[];
14
+ chromStarts: number[];
15
+ refName: string;
16
+ strand?: number;
17
+ subfeatures: MinimalFeature[];
18
+ [key: string]: unknown;
19
+ }
20
+ export declare function ucscProcessedTranscript(feature: TranscriptFeat): TranscriptFeat | {
21
+ strand: number;
22
+ type: string;
23
+ refName: string;
24
+ subfeatures: MinimalFeature[];
25
+ };
26
+ export declare function makeBlocks({ start, uniqueId, refName, chromStarts, blockCount, blockSizes, blockStarts, }: {
27
+ blockCount: number;
28
+ start: number;
29
+ uniqueId: string;
30
+ refName: string;
31
+ chromStarts: number[];
32
+ blockSizes: number[];
33
+ blockStarts: number[];
34
+ }): {
35
+ uniqueId: string;
36
+ start: number;
37
+ end: number;
38
+ refName: string;
39
+ type: string;
40
+ }[];
41
+ export declare function featureData(line: string, colRef: number, colStart: number, colEnd: number, scoreColumn: string, parser: BED, uniqueId: string, names?: string[]): SimpleFeature;
42
+ export declare function isUCSC(f: {
43
+ thickStart?: number;
44
+ blockCount?: number;
45
+ strand?: number;
46
+ }): boolean | 0 | undefined;
47
+ export {};
package/esm/util.js CHANGED
@@ -1,26 +1,20 @@
1
1
  import { SimpleFeature } from '@jbrowse/core/util';
2
2
  export function ucscProcessedTranscript(feature) {
3
- const children = feature.children();
4
- // split the blocks into UTR, CDS, and exons
5
- const thickStart = feature.get('thickStart');
6
- const thickEnd = feature.get('thickEnd');
7
- const refName = feature.get('refName');
8
- if (!thickStart && !thickEnd) {
3
+ var _a;
4
+ const { subfeatures: oldSubfeatures, thickStart, thickEnd, blockCount, blockSizes, chromStarts, refName, strand = 0, ...rest } = feature;
5
+ if (!thickStart || !thickEnd || !strand) {
9
6
  return feature;
10
7
  }
11
- const blocks = children
12
- ? children
13
- .filter(child => child.get('type') === 'block')
14
- .sort((a, b) => a.get('start') - b.get('start'))
15
- : [];
16
- const newChildren = [];
17
- blocks.forEach(block => {
18
- const start = block.get('start');
19
- const end = block.get('end');
8
+ const subfeatures = [];
9
+ (_a = oldSubfeatures
10
+ .filter(child => child.type === 'block')
11
+ .sort((a, b) => a.start - b.start)) === null || _a === void 0 ? void 0 : _a.forEach(block => {
12
+ const start = block.start;
13
+ const end = block.end;
20
14
  if (thickStart >= end) {
21
15
  // left-side UTR
22
- const prime = feature.get('strand') > 0 ? 'five' : 'three';
23
- newChildren.push({
16
+ const prime = strand > 0 ? 'five' : 'three';
17
+ subfeatures.push({
24
18
  type: `${prime}_prime_UTR`,
25
19
  start,
26
20
  end,
@@ -29,8 +23,8 @@ export function ucscProcessedTranscript(feature) {
29
23
  }
30
24
  else if (thickStart > start && thickStart < end && thickEnd >= end) {
31
25
  // UTR | CDS
32
- const prime = feature.get('strand') > 0 ? 'five' : 'three';
33
- newChildren.push({
26
+ const prime = strand > 0 ? 'five' : 'three';
27
+ subfeatures.push({
34
28
  type: `${prime}_prime_UTR`,
35
29
  start,
36
30
  end: thickStart,
@@ -44,7 +38,7 @@ export function ucscProcessedTranscript(feature) {
44
38
  }
45
39
  else if (thickStart <= start && thickEnd >= end) {
46
40
  // CDS
47
- newChildren.push({
41
+ subfeatures.push({
48
42
  type: 'CDS',
49
43
  start,
50
44
  end,
@@ -53,9 +47,9 @@ export function ucscProcessedTranscript(feature) {
53
47
  }
54
48
  else if (thickStart > start && thickStart < end && thickEnd < end) {
55
49
  // UTR | CDS | UTR
56
- const leftPrime = feature.get('strand') > 0 ? 'five' : 'three';
57
- const rightPrime = feature.get('strand') > 0 ? 'three' : 'five';
58
- newChildren.push({
50
+ const leftPrime = strand > 0 ? 'five' : 'three';
51
+ const rightPrime = strand > 0 ? 'three' : 'five';
52
+ subfeatures.push({
59
53
  type: `${leftPrime}_prime_UTR`,
60
54
  start,
61
55
  end: thickStart,
@@ -74,8 +68,8 @@ export function ucscProcessedTranscript(feature) {
74
68
  }
75
69
  else if (thickStart <= start && thickEnd > start && thickEnd < end) {
76
70
  // CDS | UTR
77
- const prime = feature.get('strand') > 0 ? 'three' : 'five';
78
- newChildren.push({
71
+ const prime = strand > 0 ? 'three' : 'five';
72
+ subfeatures.push({
79
73
  type: `CDS`,
80
74
  start,
81
75
  end: thickEnd,
@@ -89,8 +83,8 @@ export function ucscProcessedTranscript(feature) {
89
83
  }
90
84
  else if (thickEnd <= start) {
91
85
  // right-side UTR
92
- const prime = feature.get('strand') > 0 ? 'three' : 'five';
93
- newChildren.push({
86
+ const prime = strand > 0 ? 'three' : 'five';
87
+ subfeatures.push({
94
88
  type: `${prime}_prime_UTR`,
95
89
  start,
96
90
  end,
@@ -98,26 +92,35 @@ export function ucscProcessedTranscript(feature) {
98
92
  });
99
93
  }
100
94
  });
101
- const newData = Object.fromEntries(feature.tags().map(tag => [tag, feature.get(tag)]));
102
- newData.subfeatures = newChildren;
103
- newData.type = 'mRNA';
104
- newData.uniqueId = feature.id();
105
- delete newData.chromStarts;
106
- delete newData.chromStart;
107
- delete newData.chromEnd;
108
- delete newData.chrom;
109
- delete newData.blockStarts;
110
- delete newData.blockSizes;
111
- delete newData.blockCount;
112
- delete newData.thickStart;
113
- delete newData.thickEnd;
114
- return new SimpleFeature({
115
- data: newData,
116
- id: feature.id(),
117
- });
95
+ return { ...rest, strand, type: 'mRNA', refName, subfeatures };
118
96
  }
119
97
  function defaultParser(fields, line) {
120
- return Object.fromEntries(line.split('\t').map((f, i) => [fields[i], f]));
98
+ const { blockStarts, blockCount, chromStarts, thickEnd, thickStart, blockSizes, ...rest } = Object.fromEntries(line.split('\t').map((f, i) => [fields[i], f]));
99
+ return {
100
+ ...rest,
101
+ blockStarts: blockStarts === null || blockStarts === void 0 ? void 0 : blockStarts.split(',').map(r => +r),
102
+ chromStarts: chromStarts === null || chromStarts === void 0 ? void 0 : chromStarts.split(',').map(r => +r),
103
+ blockSizes: blockSizes === null || blockSizes === void 0 ? void 0 : blockSizes.split(',').map(r => +r),
104
+ thickStart: +thickStart,
105
+ thickEnd: +thickEnd,
106
+ blockCount: +blockCount,
107
+ };
108
+ }
109
+ export function makeBlocks({ start, uniqueId, refName, chromStarts, blockCount, blockSizes, blockStarts, }) {
110
+ const subfeatures = [];
111
+ const starts = chromStarts || blockStarts || [];
112
+ for (let b = 0; b < blockCount; b++) {
113
+ const bmin = (starts[b] || 0) + start;
114
+ const bmax = bmin + ((blockSizes === null || blockSizes === void 0 ? void 0 : blockSizes[b]) || 0);
115
+ subfeatures.push({
116
+ uniqueId: `${uniqueId}-${b}`,
117
+ start: bmin,
118
+ end: bmax,
119
+ refName,
120
+ type: 'block',
121
+ });
122
+ }
123
+ return subfeatures;
121
124
  }
122
125
  export function featureData(line, colRef, colStart, colEnd, scoreColumn, parser, uniqueId, names) {
123
126
  const l = line.split('\t');
@@ -128,36 +131,42 @@ export function featureData(line, colRef, colStart, colEnd, scoreColumn, parser,
128
131
  const data = names
129
132
  ? defaultParser(names, line)
130
133
  : parser.parseLine(line, { uniqueId });
131
- const { blockCount, blockSizes, blockStarts, chromStarts } = data;
132
- if (blockCount) {
133
- const starts = chromStarts || blockStarts || [];
134
- const sizes = blockSizes;
135
- const blocksOffset = start;
136
- data.subfeatures = [];
137
- for (let b = 0; b < blockCount; b += 1) {
138
- const bmin = (starts[b] || 0) + blocksOffset;
139
- const bmax = bmin + (sizes[b] || 0);
140
- data.subfeatures.push({
141
- uniqueId: `${uniqueId}-${b}`,
142
- start: bmin,
143
- end: bmax,
144
- refName,
145
- type: 'block',
146
- });
147
- }
148
- }
149
- if (scoreColumn) {
150
- data.score = +data[scoreColumn];
151
- }
152
- delete data.chrom;
153
- delete data.chromStart;
154
- delete data.chromEnd;
155
- const f = new SimpleFeature({
156
- ...data,
134
+ const { blockCount, blockSizes, blockStarts, chromStarts, thickStart, thickEnd, type, score, chrom: _1, chromStart: _2, chromEnd: _3, ...rest } = data;
135
+ const subfeatures = blockCount
136
+ ? makeBlocks({
137
+ start,
138
+ uniqueId,
139
+ refName,
140
+ chromStarts,
141
+ blockCount,
142
+ blockSizes,
143
+ blockStarts,
144
+ })
145
+ : [];
146
+ const f = {
147
+ ...rest,
148
+ type,
149
+ score: scoreColumn ? +data[scoreColumn] : score,
157
150
  start,
158
151
  end,
159
152
  refName,
160
153
  uniqueId,
154
+ subfeatures,
155
+ };
156
+ return new SimpleFeature({
157
+ id: uniqueId,
158
+ data: isUCSC(data)
159
+ ? ucscProcessedTranscript({
160
+ thickStart,
161
+ thickEnd,
162
+ blockCount,
163
+ blockSizes,
164
+ chromStarts,
165
+ ...f,
166
+ })
167
+ : f,
161
168
  });
162
- return f.get('thickStart') ? ucscProcessedTranscript(f) : f;
169
+ }
170
+ export function isUCSC(f) {
171
+ return f.thickStart && f.blockCount && f.strand !== 0;
163
172
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jbrowse/plugin-bed",
3
- "version": "2.10.3",
3
+ "version": "2.11.0",
4
4
  "description": "JBrowse 2 bed adapters, tracks, etc.",
5
5
  "keywords": [
6
6
  "jbrowse",
@@ -55,5 +55,5 @@
55
55
  "distModule": "esm/index.js",
56
56
  "srcModule": "src/index.ts",
57
57
  "module": "esm/index.js",
58
- "gitHead": "c8fc800cd17decd72b2e971c7a6add3b95214e72"
58
+ "gitHead": "3d43a820b9274a6160aa4dc15616147f390d9094"
59
59
  }