@jbrowse/plugin-gff3 5.0.0-beta.1 → 5.0.0-beta.11
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/Gff3Adapter/Gff3Adapter.js +16 -14
- package/esm/Gff3Adapter/configSchema.d.ts +9 -11
- package/esm/Gff3Adapter/configSchema.js +2 -10
- package/esm/Gff3Feature.d.ts +1 -5
- package/esm/Gff3TabixAdapter/Gff3TabixAdapter.js +28 -11
- package/esm/Gff3TabixAdapter/configSchema.d.ts +24 -37
- package/esm/Gff3TabixAdapter/configSchema.js +9 -2
- package/package.json +10 -6
|
@@ -22,17 +22,16 @@ export default class Gff3Adapter extends BaseFeatureDataAdapter {
|
|
|
22
22
|
// that resident set small (8.5x on GENCODE-shaped input), and the
|
|
23
23
|
// render path reads only a handful of attributes anyway — see
|
|
24
24
|
// Gff3Feature.
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
}, 'Parsing GFF data');
|
|
25
|
+
//
|
|
26
|
+
// The id the tree entry carries is minted here, beside the feature
|
|
27
|
+
// rather than stamped onto it, so the parsed feature is the library's
|
|
28
|
+
// shape and Gff3Feature serializes it identically for both adapters.
|
|
29
|
+
(lines, refName) => parseLinesLazy(lines).map((feature, i) => ({
|
|
30
|
+
start: feature.start,
|
|
31
|
+
end: feature.end,
|
|
32
|
+
feature,
|
|
33
|
+
uniqueId: `${this.id}-${refName}-${i}`,
|
|
34
|
+
})), 'Parsing GFF data');
|
|
36
35
|
return { header: headerLines.join('\n'), intervalTreeMap };
|
|
37
36
|
},
|
|
38
37
|
});
|
|
@@ -52,11 +51,14 @@ export default class Gff3Adapter extends BaseFeatureDataAdapter {
|
|
|
52
51
|
const { intervalTreeMap } = await this.loadData(opts);
|
|
53
52
|
const tree = intervalTreeMap[refName];
|
|
54
53
|
if (tree) {
|
|
55
|
-
for (const
|
|
56
|
-
|
|
54
|
+
for (const { feature, uniqueId } of tree(opts.statusCallback).search([
|
|
55
|
+
start,
|
|
56
|
+
end,
|
|
57
|
+
])) {
|
|
58
|
+
observer.next(new Gff3Feature(feature, uniqueId));
|
|
57
59
|
}
|
|
58
60
|
}
|
|
59
61
|
observer.complete();
|
|
60
|
-
}, opts.
|
|
62
|
+
}, opts.signal);
|
|
61
63
|
}
|
|
62
64
|
}
|
|
@@ -17,18 +17,16 @@ export declare function normalizeSnapshot(snap: Record<string, unknown>): Record
|
|
|
17
17
|
* ```
|
|
18
18
|
*/
|
|
19
19
|
declare const Gff3Adapter: import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaType<{
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
type: {
|
|
21
|
+
type: "string";
|
|
22
|
+
} & {
|
|
23
|
+
defaultValue: string;
|
|
24
|
+
};
|
|
25
25
|
readonly gffLocation: {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
readonly locationType: "UriLocation";
|
|
30
|
-
};
|
|
26
|
+
type: "fileLocation";
|
|
27
|
+
} & {
|
|
28
|
+
defaultValue: unknown;
|
|
31
29
|
};
|
|
32
|
-
}, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, undefined>>;
|
|
30
|
+
}, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, undefined, true, import("@jbrowse/core/configuration").ConfigurationSchemaRequirement<Partial<Record<string, string[]>>, string>, any>>;
|
|
33
31
|
export type Gff3AdapterConfig = Instance<typeof Gff3Adapter>;
|
|
34
32
|
export default Gff3Adapter;
|
|
@@ -1,14 +1,6 @@
|
|
|
1
|
-
import { ConfigurationSchema } from '@jbrowse/core/configuration';
|
|
1
|
+
import { ConfigurationSchema, expandUriShorthand, } from '@jbrowse/core/configuration';
|
|
2
2
|
export function normalizeSnapshot(snap) {
|
|
3
|
-
return snap
|
|
4
|
-
? {
|
|
5
|
-
...snap,
|
|
6
|
-
gffLocation: {
|
|
7
|
-
uri: snap.uri,
|
|
8
|
-
baseUri: snap.baseUri,
|
|
9
|
-
},
|
|
10
|
-
}
|
|
11
|
-
: snap;
|
|
3
|
+
return expandUriShorthand(snap, 'gffLocation');
|
|
12
4
|
}
|
|
13
5
|
/**
|
|
14
6
|
* #config Gff3Adapter
|
package/esm/Gff3Feature.d.ts
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
import type { Feature, SimpleFeatureSerialized } from '@jbrowse/core/util/simpleFeature';
|
|
2
2
|
import type { LazyGffFeature } from 'gff-nostream';
|
|
3
|
-
/** A parsed GFF3 feature carrying the id the adapter minted for it. */
|
|
4
|
-
export type IdentifiedGffFeature = LazyGffFeature & {
|
|
5
|
-
uniqueId: string;
|
|
6
|
-
};
|
|
7
3
|
/**
|
|
8
4
|
* A {@link Feature} over a GFF3 feature whose attributes are still raw column-9
|
|
9
5
|
* text, resolving each one only when something asks for it.
|
|
@@ -26,7 +22,7 @@ export declare class Gff3Feature implements Feature {
|
|
|
26
22
|
private uniqueId;
|
|
27
23
|
private parentFeature?;
|
|
28
24
|
private inflated?;
|
|
29
|
-
constructor(data:
|
|
25
|
+
constructor(data: LazyGffFeature, uniqueId: string, parentFeature?: Feature | undefined);
|
|
30
26
|
/**
|
|
31
27
|
* A switch rather than a lookup table or a `data[name]` fallthrough: the
|
|
32
28
|
* fixed columns are read tens of times per feature by the layout pass, and
|
|
@@ -1,30 +1,28 @@
|
|
|
1
1
|
import { TabixIndexedFile } from '@gmod/tabix';
|
|
2
2
|
import { BaseFeatureDataAdapter, cachedSetup, } from '@jbrowse/core/data_adapters/BaseAdapter';
|
|
3
3
|
import { downloadStatus } from '@jbrowse/core/util';
|
|
4
|
-
import { sharedBgzfWorkerPool } from '@jbrowse/core/util/bgzfWorkerPool';
|
|
5
4
|
import { decompressedBytesBudget } from '@jbrowse/core/util/cacheBudgets';
|
|
6
5
|
import { openLocation, openTabixIndexFilehandle } from '@jbrowse/core/util/io';
|
|
7
6
|
import { doesIntersect2 } from '@jbrowse/core/util/range';
|
|
8
7
|
import { ObservableCreate } from '@jbrowse/core/util/rxjs';
|
|
9
8
|
import { readTabixLinesRedispatched } from '@jbrowse/core/util/tabix';
|
|
10
|
-
import { parseRecordsLazy } from 'gff-nostream';
|
|
9
|
+
import { hasIdAttribute, parseRecordsLazy } from 'gff-nostream';
|
|
11
10
|
import { Gff3Feature } from '../Gff3Feature.js';
|
|
12
11
|
export default class Gff3TabixAdapter extends BaseFeatureDataAdapter {
|
|
13
12
|
configure = cachedSetup({
|
|
14
13
|
label: 'Downloading index',
|
|
15
|
-
setup: async (
|
|
14
|
+
setup: async (opts, onProgress) => {
|
|
16
15
|
const gff = new TabixIndexedFile({
|
|
17
16
|
filehandle: openLocation(this.getConf('gffGzLocation'), this.pluginManager),
|
|
18
17
|
...openTabixIndexFilehandle(this.getConf(['index', 'location']), this.getConf(['index', 'indexType']), this.pluginManager),
|
|
19
18
|
chunkCacheBudget: decompressedBytesBudget,
|
|
20
|
-
bgzfWorkerPool: sharedBgzfWorkerPool(),
|
|
21
19
|
});
|
|
20
|
+
// the index is a whole-file read, so its byte ticks turn the
|
|
21
|
+
// "Downloading index" label into a determinate bar
|
|
22
|
+
await gff.getReferenceSequenceNames({ onProgress, signal: opts.signal });
|
|
22
23
|
return {
|
|
23
24
|
gff,
|
|
24
25
|
dontRedispatchSet: new Set(this.getConf('dontRedispatch')),
|
|
25
|
-
// the index is a whole-file read, so its byte ticks turn the
|
|
26
|
-
// "Downloading index" label into a determinate bar
|
|
27
|
-
header: await gff.getHeader({ onProgress }),
|
|
28
26
|
};
|
|
29
27
|
},
|
|
30
28
|
});
|
|
@@ -33,8 +31,8 @@ export default class Gff3TabixAdapter extends BaseFeatureDataAdapter {
|
|
|
33
31
|
return downloadStatus('Downloading index', opts.statusCallback, onProgress => gff.getReferenceSequenceNames({ ...opts, onProgress }));
|
|
34
32
|
}
|
|
35
33
|
async getHeader(opts = {}) {
|
|
36
|
-
const {
|
|
37
|
-
return
|
|
34
|
+
const { gff } = await this.configure(opts);
|
|
35
|
+
return gff.getHeader(opts);
|
|
38
36
|
}
|
|
39
37
|
// Index-only compressed-byte estimate (no feature download), used by the
|
|
40
38
|
// feature-fetch RPC to short-circuit an over-budget region before pulling
|
|
@@ -47,7 +45,26 @@ export default class Gff3TabixAdapter extends BaseFeatureDataAdapter {
|
|
|
47
45
|
return ObservableCreate(async (observer) => {
|
|
48
46
|
try {
|
|
49
47
|
const { gff, dontRedispatchSet } = await this.configure(opts);
|
|
50
|
-
|
|
48
|
+
// The bound exists to reach a record's children, so what disqualifies a
|
|
49
|
+
// record is having none. `ID` answers that exactly — nothing can name a
|
|
50
|
+
// parent that has no name — and gff-nostream decides it with the scan
|
|
51
|
+
// its linker uses, so a record the tree would attach children to is
|
|
52
|
+
// never one the bound leaves out. `dontRedispatch` can only approximate
|
|
53
|
+
// the same question by type: every NCBI `GCF_*_genomic.gff.gz` opens
|
|
54
|
+
// each reference with a chromosome-long `match` record no list named,
|
|
55
|
+
// and none of them has an `ID`. The list covers what `ID` cannot see: a
|
|
56
|
+
// record carrying an `ID` that nothing references, which hosted hg19
|
|
57
|
+
// RefSeq's chromosome-long `region` is.
|
|
58
|
+
const canHaveChildren = (line) => hasIdAttribute(line.line) && !dontRedispatchSet.has(line.type);
|
|
59
|
+
const lines = await readTabixLinesRedispatched(gff, query,
|
|
60
|
+
// A caller reading only top-level features is owed nothing by the
|
|
61
|
+
// flanks and pays for them anyway: they complete SUBFEATURE lists, and
|
|
62
|
+
// a top-level feature overlapping the query is in the query's own read
|
|
63
|
+
// already, since tabix returns every overlapping line and a child is
|
|
64
|
+
// contained in its parent. On an NCBI `GCF_*_genomic.gff.gz`, whose
|
|
65
|
+
// chromosome-long `match` widens the bound at every window, that is
|
|
66
|
+
// 193,008 lines parsed to keep 3 features — 2734 ms against 8 ms.
|
|
67
|
+
opts.topLevelOnly ? () => false : canHaveChildren, opts);
|
|
51
68
|
// emit only top-level features intersecting the original query. the
|
|
52
69
|
// byte offset stays on our own record and is used purely to mint a
|
|
53
70
|
// stable id, so it never pollutes the feature's data
|
|
@@ -61,6 +78,6 @@ export default class Gff3TabixAdapter extends BaseFeatureDataAdapter {
|
|
|
61
78
|
catch (e) {
|
|
62
79
|
observer.error(e);
|
|
63
80
|
}
|
|
64
|
-
}, opts.
|
|
81
|
+
}, opts.signal);
|
|
65
82
|
}
|
|
66
83
|
}
|
|
@@ -18,51 +18,38 @@ export declare function normalizeSnapshot(snap: Record<string, unknown>): Record
|
|
|
18
18
|
* ```
|
|
19
19
|
*/
|
|
20
20
|
declare const Gff3TabixAdapter: import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaType<{
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
readonly densityAdapter: {
|
|
22
|
+
type: "maybeFrozen";
|
|
23
|
+
};
|
|
24
|
+
type: {
|
|
25
|
+
type: "string";
|
|
26
|
+
} & {
|
|
27
|
+
defaultValue: string;
|
|
28
|
+
};
|
|
26
29
|
readonly gffGzLocation: {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
readonly locationType: "UriLocation";
|
|
31
|
-
};
|
|
30
|
+
type: "fileLocation";
|
|
31
|
+
} & {
|
|
32
|
+
defaultValue: unknown;
|
|
32
33
|
};
|
|
33
34
|
readonly index: import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaType<{
|
|
34
35
|
readonly indexType: {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
type: "stringEnum";
|
|
37
|
+
} & {
|
|
38
|
+
model: import("@jbrowse/mobx-state-tree").ISimpleType<"CSI" | "TBI">;
|
|
39
|
+
} & {
|
|
40
|
+
defaultValue: string;
|
|
39
41
|
};
|
|
40
42
|
readonly location: {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
readonly locationType: 'UriLocation';
|
|
45
|
-
};
|
|
46
|
-
readonly description: 'location of the tabix index. Only needed when it is not named `<file>.tbi` (or `.csi`), which is what the `uri` shorthand assumes.';
|
|
43
|
+
type: "fileLocation";
|
|
44
|
+
} & {
|
|
45
|
+
defaultValue: unknown;
|
|
47
46
|
};
|
|
48
|
-
}, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, undefined>>;
|
|
49
|
-
/**
|
|
50
|
-
* #slot
|
|
51
|
-
* the Gff3TabixAdapter has to "redispatch" if it fetches a region and
|
|
52
|
-
* features it finds inside that region extend outside the region we requested.
|
|
53
|
-
* you can disable this for certain feature types to avoid fetching e.g. the
|
|
54
|
-
* entire chromosome
|
|
55
|
-
*
|
|
56
|
-
* the defaults are the whole-sequence records the common GFF3 sources emit:
|
|
57
|
-
* `region` (NCBI), `supercontig`/`scaffold` (Ensembl, for non-chromosomal
|
|
58
|
-
* sequences), plus `chromosome` and `contig`. They span an entire reference
|
|
59
|
-
* and have no children, so letting one expand the fetch would pull a whole
|
|
60
|
-
* chromosome to gain nothing
|
|
61
|
-
*/
|
|
47
|
+
}, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, undefined, undefined, import("@jbrowse/core/configuration").ConfigurationSchemaRequirement<Partial<Record<string, string[]>>, string>, any>>;
|
|
62
48
|
readonly dontRedispatch: {
|
|
63
|
-
|
|
64
|
-
|
|
49
|
+
type: "stringArray";
|
|
50
|
+
} & {
|
|
51
|
+
defaultValue: unknown;
|
|
65
52
|
};
|
|
66
|
-
}, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, undefined>>;
|
|
53
|
+
}, import("@jbrowse/core/configuration/configurationSchema").ConfigurationSchemaOptions<undefined, undefined, true, import("@jbrowse/core/configuration").ConfigurationSchemaRequirement<Partial<Record<string, string[]>>, string>, any>>;
|
|
67
54
|
export type Gff3TabixAdapterConfig = Instance<typeof Gff3TabixAdapter>;
|
|
68
55
|
export default Gff3TabixAdapter;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { ConfigurationSchema, expandTabixShorthand,
|
|
1
|
+
import { ConfigurationSchema, expandTabixShorthand, tabixIndexSchema, } from '@jbrowse/core/configuration';
|
|
2
|
+
import { densityAdapterConfigSchemaFields } from '@jbrowse/core/data_adapters/BaseAdapter';
|
|
2
3
|
export function normalizeSnapshot(snap) {
|
|
3
4
|
return expandTabixShorthand(snap, 'gffGzLocation');
|
|
4
5
|
}
|
|
@@ -32,7 +33,12 @@ const Gff3TabixAdapter = ConfigurationSchema('Gff3TabixAdapter', {
|
|
|
32
33
|
locationType: 'UriLocation',
|
|
33
34
|
},
|
|
34
35
|
},
|
|
35
|
-
|
|
36
|
+
/**
|
|
37
|
+
* #slot
|
|
38
|
+
* where the tabix index is and which kind it is. The `uri` shorthand derives
|
|
39
|
+
* both, so a config using it states neither.
|
|
40
|
+
*/
|
|
41
|
+
index: tabixIndexSchema(),
|
|
36
42
|
/**
|
|
37
43
|
* #slot
|
|
38
44
|
* the Gff3TabixAdapter has to "redispatch" if it fetches a region and
|
|
@@ -56,6 +62,7 @@ const Gff3TabixAdapter = ConfigurationSchema('Gff3TabixAdapter', {
|
|
|
56
62
|
'scaffold',
|
|
57
63
|
],
|
|
58
64
|
},
|
|
65
|
+
...densityAdapterConfigSchemaFields,
|
|
59
66
|
}, {
|
|
60
67
|
explicitlyTyped: true,
|
|
61
68
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jbrowse/plugin-gff3",
|
|
3
|
-
"version": "5.0.0-beta.
|
|
3
|
+
"version": "5.0.0-beta.11",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "JBrowse 2 gff3.",
|
|
6
6
|
"keywords": [
|
|
@@ -21,12 +21,16 @@
|
|
|
21
21
|
"esm"
|
|
22
22
|
],
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@gmod/tabix": "^3.
|
|
25
|
-
"@jbrowse/mobx-state-tree": "^6.
|
|
26
|
-
"gff-nostream": "^5.
|
|
27
|
-
"mobx": "^7.0.
|
|
24
|
+
"@gmod/tabix": "^3.9.1",
|
|
25
|
+
"@jbrowse/mobx-state-tree": "^6.7.0",
|
|
26
|
+
"gff-nostream": "^5.6.0",
|
|
27
|
+
"mobx": "^7.0.5",
|
|
28
28
|
"rxjs": "^7.8.2",
|
|
29
|
-
"@jbrowse/core": "^5.0.0-beta.
|
|
29
|
+
"@jbrowse/core": "^5.0.0-beta.11"
|
|
30
|
+
},
|
|
31
|
+
"peerDependencies": {
|
|
32
|
+
"react": ">=19.0.0",
|
|
33
|
+
"react-dom": ">=19.0.0"
|
|
30
34
|
},
|
|
31
35
|
"publishConfig": {
|
|
32
36
|
"access": "public"
|