@apollo-annotation/shared 0.3.1 → 0.3.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apollo-annotation/shared",
3
- "version": "0.3.1",
3
+ "version": "0.3.2",
4
4
  "main": "./dist/index.js",
5
5
  "scripts": {
6
6
  "build": "yarn clean && tsc --build",
@@ -10,12 +10,12 @@
10
10
  "test:ci": "NODE_V8_COVERAGE=./coverage glob -c \"tsx --test --test-reporter spec --experimental-test-coverage \" \"**/*.test.ts\""
11
11
  },
12
12
  "dependencies": {
13
- "@apollo-annotation/common": "^0.3.1",
14
- "@apollo-annotation/mst": "^0.3.1",
15
- "@apollo-annotation/schemas": "^0.3.1",
13
+ "@apollo-annotation/common": "^0.3.2",
14
+ "@apollo-annotation/mst": "^0.3.2",
15
+ "@apollo-annotation/schemas": "^0.3.2",
16
16
  "@gmod/gff": "1.2.0",
17
17
  "@gmod/indexedfasta": "^2.0.4",
18
- "@jbrowse/core": "^2.13.1",
18
+ "@jbrowse/core": "^3.0.1",
19
19
  "bson-objectid": "^2.0.4",
20
20
  "generic-filehandle": "^3.0.0",
21
21
  "jwt-decode": "^3.1.2",
@@ -39,7 +39,7 @@
39
39
  "typescript": "^5.5.3"
40
40
  },
41
41
  "peerDependencies": {
42
- "@mui/material": "^5.11.14",
42
+ "@mui/material": "^6.0.0",
43
43
  "@mui/x-data-grid": "^7.0.0",
44
44
  "mobx": "^6.6.1",
45
45
  "mobx-react": "^7.2.1",
@@ -14,7 +14,7 @@ export function annotationFeatureToGFF3(
14
14
  refSeqNames?: Record<string, string | undefined>,
15
15
  ): GFF3Feature {
16
16
  const attributes: Record<string, string[] | undefined> = JSON.parse(
17
- JSON.stringify(feature.attributes),
17
+ JSON.stringify(feature.attributes ?? {}),
18
18
  )
19
19
  const ontologyTerms: string[] = []
20
20
  const source = feature.attributes?.gff_source?.[0] ?? null
@@ -197,6 +197,37 @@ describe('gff3ToAnnotationFeature examples', () => {
197
197
  })
198
198
  })
199
199
 
200
+ describe('CDS without exons', () => {
201
+ it('Convert mRNA with CDS but without exon', () => {
202
+ const [gffFeature] = readFeatureFile('test_data/cds_without_exon.gff')
203
+ const actual = gff3ToAnnotationFeature(gffFeature)
204
+ const expected = readAnnotationFeatureSnapshot(
205
+ 'test_data/cds_without_exon.json',
206
+ )
207
+ compareFeatures(actual, expected)
208
+ })
209
+ it('Convert mRNA with CDS but without exon and spliced UTR', () => {
210
+ const [gffFeature] = readFeatureFile(
211
+ 'test_data/cds_without_exon_spliced_utr.gff',
212
+ )
213
+ const actual = gff3ToAnnotationFeature(gffFeature)
214
+ const expected = readAnnotationFeatureSnapshot(
215
+ 'test_data/cds_without_exon_spliced_utr.json',
216
+ )
217
+ compareFeatures(actual, expected)
218
+ })
219
+ it('Convert mRNA with one CDS, without exons non-adjacent UTR', () => {
220
+ const [gffFeature] = readFeatureFile(
221
+ 'test_data/onecds_without_exon_spliced_utr.gff',
222
+ )
223
+ const actual = gff3ToAnnotationFeature(gffFeature)
224
+ const expected = readAnnotationFeatureSnapshot(
225
+ 'test_data/onecds_without_exon_spliced_utr.json',
226
+ )
227
+ compareFeatures(actual, expected)
228
+ })
229
+ })
230
+
200
231
  describe('gff3ToAnnotationFeature', () => {
201
232
  for (const testCase of testCases) {
202
233
  const [description, featureLine, convertedFeature] = testCase
@@ -209,3 +240,30 @@ describe('gff3ToAnnotationFeature', () => {
209
240
  })
210
241
  }
211
242
  })
243
+
244
+ describe('Source and score', () => {
245
+ it('Convert score and source', () => {
246
+ const gffFeature: GFF3Feature = [
247
+ {
248
+ seq_id: 'chr1',
249
+ source: 'mySource',
250
+ type: 'gene',
251
+ start: 1000,
252
+ end: 9000,
253
+ score: 0,
254
+ strand: '+',
255
+ phase: null,
256
+ attributes: {
257
+ ID: ['gene10001'],
258
+ Name: ['EDEN'],
259
+ testid: ['t003'],
260
+ },
261
+ child_features: [],
262
+ derived_features: [],
263
+ },
264
+ ]
265
+ const actual = gff3ToAnnotationFeature(gffFeature)
266
+ assert.deepStrictEqual(actual.attributes?.gff_source?.at(0), 'mySource')
267
+ assert.deepStrictEqual(actual.attributes?.gff_score?.at(0), '0')
268
+ })
269
+ })
@@ -121,6 +121,9 @@ function convertFeatureAttributes(
121
121
  const newKey = isGFFReservedAttribute(key) ? gffToInternal[key] : key
122
122
  const existingVal = convertedAttributes[newKey]
123
123
  if (existingVal) {
124
+ // if (JSON.stringify(existingVal) === JSON.stringify(val)) {
125
+ // continue
126
+ // }
124
127
  const valSet = new Set([...existingVal, ...val])
125
128
  convertedAttributes[newKey] = [...valSet]
126
129
  } else {
@@ -154,8 +157,19 @@ function convertChildren(
154
157
  const { child_features: childFeatures } = firstFeature
155
158
 
156
159
  const cdsFeatures: GFF3Feature[] = []
160
+ const exonFeatures: GFF3Feature[] = []
161
+ const utrFeatures: GFF3Feature[] = []
157
162
  for (const childFeature of childFeatures) {
158
163
  const [firstChildFeatureLocation] = childFeature
164
+ if (firstChildFeatureLocation.type === 'exon') {
165
+ exonFeatures.push(childFeature)
166
+ }
167
+ if (
168
+ firstChildFeatureLocation.type === 'three_prime_UTR' ||
169
+ firstChildFeatureLocation.type === 'five_prime_UTR'
170
+ ) {
171
+ utrFeatures.push(childFeature)
172
+ }
159
173
  if (
160
174
  firstChildFeatureLocation.type === 'three_prime_UTR' ||
161
175
  firstChildFeatureLocation.type === 'five_prime_UTR' ||
@@ -172,10 +186,23 @@ function convertChildren(
172
186
  convertedChildren[child._id] = child
173
187
  }
174
188
  }
175
- const processedCDS =
176
- cdsFeatures.length > 0 ? processCDS(cdsFeatures, refSeq, featureIds) : []
177
- for (const cds of processedCDS) {
178
- convertedChildren[cds._id] = cds
189
+
190
+ if (cdsFeatures.length > 0) {
191
+ const processedCDS = processCDS(cdsFeatures, refSeq, featureIds)
192
+
193
+ for (const cds of processedCDS) {
194
+ convertedChildren[cds._id] = cds
195
+ }
196
+
197
+ const missingExons = inferMissingExons(
198
+ cdsFeatures,
199
+ exonFeatures,
200
+ utrFeatures,
201
+ processedCDS[0].refSeq,
202
+ )
203
+ for (const exon of missingExons) {
204
+ convertedChildren[exon._id] = exon
205
+ }
179
206
  }
180
207
 
181
208
  if (Object.keys(convertedChildren).length > 0) {
@@ -184,6 +211,149 @@ function convertChildren(
184
211
  return
185
212
  }
186
213
 
214
+ function inferMissingExons(
215
+ cdsFeatures: GFF3Feature[],
216
+ existingExons: GFF3Feature[],
217
+ utrFeatures: GFF3Feature[],
218
+ refSeq: string,
219
+ ): AnnotationFeatureSnapshot[] {
220
+ // Convert utrFeatures from GFF3Feature to AnnotationFeatureSnapshot
221
+ const utrExons: AnnotationFeatureSnapshot[] = []
222
+ for (const utrs of utrFeatures) {
223
+ for (const utr of utrs) {
224
+ if (!utr.start || !utr.end) {
225
+ throw new Error(
226
+ `UTR has undefined start and/or end\n: ${JSON.stringify(utr, null, 2)}`,
227
+ )
228
+ }
229
+ let strand: 1 | -1 | undefined = undefined
230
+ if (utr.strand === '+') {
231
+ strand = 1
232
+ } else if (utr.strand === '-') {
233
+ strand = -1
234
+ }
235
+ utrExons.push({
236
+ _id: new ObjectID().toHexString(),
237
+ refSeq,
238
+ type: 'exon',
239
+ min: utr.start - 1,
240
+ max: utr.end,
241
+ strand,
242
+ })
243
+ }
244
+ }
245
+ utrExons.sort((a, b) => a.min - b.min)
246
+
247
+ const missingExons: AnnotationFeatureSnapshot[] = []
248
+ for (const protein of cdsFeatures) {
249
+ protein.sort((a, b) => {
250
+ if (!a.start || !b.start) {
251
+ throw new Error('CDS has undefined start')
252
+ }
253
+ return a.start - b.start
254
+ })
255
+ for (let cdsIdx = 0; cdsIdx < protein.length; cdsIdx++) {
256
+ const cds = protein[cdsIdx]
257
+ // For CDS check if there is an exon containing it. If not, create an exon with same coords as the CDS.
258
+ let exonFound = false
259
+ for (const x of existingExons) {
260
+ if (x.length != 1) {
261
+ throw new Error('Unexpected number of exons')
262
+ }
263
+ const [exon] = x
264
+ if (
265
+ exon.start &&
266
+ exon.end &&
267
+ cds.start &&
268
+ cds.end &&
269
+ exon.start <= cds.start &&
270
+ exon.end >= cds.end
271
+ ) {
272
+ exonFound = true
273
+ break
274
+ }
275
+ }
276
+ if (!exonFound) {
277
+ if (!cds.start || !cds.end) {
278
+ throw new Error(
279
+ `CDS has undefined start and/or end: ${JSON.stringify(cds, null, 2)}`,
280
+ )
281
+ }
282
+ let strand: 1 | -1 | undefined = undefined
283
+ if (cds.strand === '+') {
284
+ strand = 1
285
+ } else if (cds.strand === '-') {
286
+ strand = -1
287
+ }
288
+ const newExon: AnnotationFeatureSnapshot = {
289
+ _id: new ObjectID().toHexString(),
290
+ refSeq,
291
+ type: 'exon',
292
+ min: cds.start - 1,
293
+ max: cds.end,
294
+ strand,
295
+ }
296
+ if (cdsIdx === 0) {
297
+ // If this CDS is the leftmost (or the only CDS in this protein), check if we need to add UTRs before it
298
+ for (const utr of utrExons) {
299
+ if (utr.max > newExon.min) {
300
+ break
301
+ }
302
+ if (utr.max === newExon.min) {
303
+ // UTR ends where exon begins: Extend the exon to include this UTR
304
+ newExon.min = utr.min
305
+ } else {
306
+ missingExons.push(utr)
307
+ }
308
+ }
309
+ }
310
+ if (cdsIdx === protein.length - 1) {
311
+ // If this CDS is the rightmost (or the only CDS in this protein), check if we need to add UTRs after it
312
+ for (const utr of utrExons) {
313
+ if (utr.min < newExon.max) {
314
+ continue
315
+ }
316
+ if (utr.min === newExon.max) {
317
+ // UTR begins where exon end: Extend the exon to include this UTR
318
+ newExon.max = utr.max
319
+ } else {
320
+ missingExons.push(utr)
321
+ }
322
+ }
323
+ }
324
+ missingExons.push(newExon)
325
+ }
326
+ }
327
+ }
328
+ const mergedExons = mergeAnnotationFeatures(missingExons)
329
+ return mergedExons
330
+ }
331
+
332
+ function mergeAnnotationFeatures(
333
+ features: AnnotationFeatureSnapshot[],
334
+ ): AnnotationFeatureSnapshot[] {
335
+ if (features.length === 0) {
336
+ return []
337
+ }
338
+ features.sort((a, b) => a.min - b.min)
339
+
340
+ const res = []
341
+ res.push(features[0])
342
+
343
+ for (let i = 1; i < features.length; i++) {
344
+ const last = res.at(-1)
345
+ const curr = features[i]
346
+
347
+ // If current interval overlaps with the last merged interval, merge them
348
+ if (last && curr.min <= last.max) {
349
+ last.max = Math.max(last.max, curr.max)
350
+ } else {
351
+ res.push(curr)
352
+ }
353
+ }
354
+ return res
355
+ }
356
+
187
357
  /**
188
358
  * If a GFF3 file has CDS features that either (1) don't have an ID or (2) have
189
359
  * different IDs for each CDS, we have to do a bit of guessing about how they
@@ -0,0 +1,12 @@
1
+ ##gff-version 3
2
+ ##sequence-region 53cb6b9b4f4ddef1ad47f943 1050 9000
3
+ ctgA example gene 1050 9000 . + . ID=eden
4
+ ctgA example mRNA 1050 9000 . + . ID=eden.1;Parent=eden
5
+ ctgA example five_prime_UTR 1050 1210 . + 0 ID=five1;Parent=eden.1
6
+ ctgA example CDS 1211 1510 . + 0 ID=cds2;Parent=eden.1
7
+ ctgA example CDS 1611 1710 . + 0 ID=cds2;Parent=eden.1
8
+ ctgA example three_prime_UTR 1711 1800 . + 0 ID=three1;Parent=eden.1
9
+ ctgA example exon 1201 1500 . + 0 ID=exon1;Parent=eden.1
10
+ ctgA example CDS 1601 1700 . + 0 ID=cds1;Parent=eden.1
11
+ ctgA example CDS 1201 1500 . + 0 ID=cds1;Parent=eden.1
12
+ ctgA example TF_binding_site 1050 1100 . + . Parent=eden
@@ -0,0 +1,74 @@
1
+ {
2
+ "_id": "67581b7d5890a8eb1bedab6e",
3
+ "refSeq": "ctgA",
4
+ "type": "gene",
5
+ "min": 1049,
6
+ "max": 9000,
7
+ "strand": 1,
8
+ "children": {
9
+ "67581b7d5890a8eb1bedab6c": {
10
+ "_id": "67581b7d5890a8eb1bedab6c",
11
+ "refSeq": "ctgA",
12
+ "type": "mRNA",
13
+ "min": 1049,
14
+ "max": 9000,
15
+ "strand": 1,
16
+ "children": {
17
+ "67581b7d5890a8eb1bedab66": {
18
+ "_id": "67581b7d5890a8eb1bedab66",
19
+ "refSeq": "ctgA",
20
+ "type": "exon",
21
+ "min": 1200,
22
+ "max": 1500,
23
+ "strand": 1,
24
+ "attributes": { "gff_source": ["example"], "gff_id": ["exon1"] }
25
+ },
26
+ "67581b7d5890a8eb1bedab67": {
27
+ "_id": "67581b7d5890a8eb1bedab67",
28
+ "refSeq": "ctgA",
29
+ "type": "CDS",
30
+ "min": 1210,
31
+ "max": 1710,
32
+ "strand": 1,
33
+ "attributes": { "gff_source": ["example"], "gff_id": ["cds2"] }
34
+ },
35
+ "67581b7d5890a8eb1bedab68": {
36
+ "_id": "67581b7d5890a8eb1bedab68",
37
+ "refSeq": "ctgA",
38
+ "type": "CDS",
39
+ "min": 1200,
40
+ "max": 1700,
41
+ "strand": 1,
42
+ "attributes": { "gff_source": ["example"], "gff_id": ["cds1"] }
43
+ },
44
+ "67581b7d5890a8eb1bedab69": {
45
+ "_id": "67581b7d5890a8eb1bedab69",
46
+ "refSeq": "ctgA",
47
+ "type": "exon",
48
+ "min": 1049,
49
+ "max": 1510,
50
+ "strand": 1
51
+ },
52
+ "67581b7d5890a8eb1bedab6b": {
53
+ "_id": "67581b7d5890a8eb1bedab6b",
54
+ "refSeq": "ctgA",
55
+ "type": "exon",
56
+ "min": 1600,
57
+ "max": 1800,
58
+ "strand": 1
59
+ }
60
+ },
61
+ "attributes": { "gff_source": ["example"], "gff_id": ["eden.1"] }
62
+ },
63
+ "67581b7d5890a8eb1bedab6d": {
64
+ "_id": "67581b7d5890a8eb1bedab6d",
65
+ "refSeq": "ctgA",
66
+ "type": "TF_binding_site",
67
+ "min": 1049,
68
+ "max": 1100,
69
+ "strand": 1,
70
+ "attributes": { "gff_source": ["example"] }
71
+ }
72
+ },
73
+ "attributes": { "gff_source": ["example"], "gff_id": ["eden"] }
74
+ }
@@ -0,0 +1,14 @@
1
+ ##gff-version 3
2
+ chr1 . gene 1000 9000 . + . ID=gene00001
3
+ #chr1 . mRNA 1300 9000 . + . ID=mRNA00001;Parent=gene00001
4
+ #chr1 . five_prime_UTR 3000 3300 . + . Parent=mRNA00001
5
+ #chr1 . CDS 5000 5500 . + 1 ID=cds00001;Parent=mRNA00001
6
+ #chr1 . three_prime_UTR 7601 8000 . + . Parent=mRNA00001
7
+ chr1 . mRNA 1300 9000 . + . ID=mRNA00003;Parent=gene00001
8
+ chr1 . five_prime_UTR 1300 1500 . + . Parent=mRNA00003
9
+ chr1 . five_prime_UTR 3000 3300 . + . Parent=mRNA00003
10
+ chr1 . CDS 3301 3902 . + 0 ID=cds00003;Parent=mRNA00003
11
+ chr1 . CDS 5000 5500 . + 1 ID=cds00003;Parent=mRNA00003
12
+ chr1 . CDS 7000 7600 . + 2 ID=cds00003;Parent=mRNA00003
13
+ chr1 . three_prime_UTR 7601 8000 . + . Parent=mRNA00003
14
+ chr1 . three_prime_UTR 8501 8900 . + . Parent=mRNA00003
@@ -0,0 +1,73 @@
1
+ {
2
+ "_id": "675ad4e6a5abb3a5087c0652",
3
+ "refSeq": "chr1",
4
+ "type": "gene",
5
+ "min": 999,
6
+ "max": 9000,
7
+ "strand": 1,
8
+ "children": {
9
+ "675ad4e6a5abb3a5087c0651": {
10
+ "_id": "675ad4e6a5abb3a5087c0651",
11
+ "refSeq": "chr1",
12
+ "type": "mRNA",
13
+ "min": 1299,
14
+ "max": 9000,
15
+ "strand": 1,
16
+ "children": {
17
+ "675ad4e6a5abb3a5087c0649": {
18
+ "_id": "675ad4e6a5abb3a5087c0649",
19
+ "refSeq": "chr1",
20
+ "type": "CDS",
21
+ "min": 3300,
22
+ "max": 7600,
23
+ "strand": 1,
24
+ "attributes": {
25
+ "gff_id": ["cds00003"]
26
+ }
27
+ },
28
+ "675ad4e6a5abb3a5087c064a": {
29
+ "_id": "675ad4e6a5abb3a5087c064a",
30
+ "refSeq": "chr1",
31
+ "type": "exon",
32
+ "min": 1299,
33
+ "max": 1500,
34
+ "strand": 1
35
+ },
36
+ "675ad4e6a5abb3a5087c064e": {
37
+ "_id": "675ad4e6a5abb3a5087c064e",
38
+ "refSeq": "chr1",
39
+ "type": "exon",
40
+ "min": 2999,
41
+ "max": 3902,
42
+ "strand": 1
43
+ },
44
+ "675ad4e6a5abb3a5087c064f": {
45
+ "_id": "675ad4e6a5abb3a5087c064f",
46
+ "refSeq": "chr1",
47
+ "type": "exon",
48
+ "min": 4999,
49
+ "max": 5500,
50
+ "strand": 1
51
+ },
52
+ "675ad4e6a5abb3a5087c0650": {
53
+ "_id": "675ad4e6a5abb3a5087c0650",
54
+ "refSeq": "chr1",
55
+ "type": "exon",
56
+ "min": 6999,
57
+ "max": 8000,
58
+ "strand": 1
59
+ },
60
+ "675ad4e6a5abb3a5087c064d": {
61
+ "_id": "675ad4e6a5abb3a5087c064d",
62
+ "refSeq": "chr1",
63
+ "type": "exon",
64
+ "min": 8500,
65
+ "max": 8900,
66
+ "strand": 1
67
+ }
68
+ },
69
+ "attributes": { "gff_id": ["mRNA00003"] }
70
+ }
71
+ },
72
+ "attributes": { "gff_id": ["gene00001"] }
73
+ }
@@ -1,4 +1,5 @@
1
1
  ##gff-version 3
2
+ ##sequence-region chr1 1000 39000
2
3
  # example 1
3
4
  chr1 . gene 1000 9000 . + . ID=gene10001;Name=EDEN
4
5
  chr1 . TF_binding_site 1000 1012 . + . ID=tfbs10001;Parent=gene10001
@@ -76,10 +77,10 @@ chr1 . CDS 21201 21500 . + 0 ID=cds30005;Parent=mRNA30002;Name=edenprotein.2
76
77
  chr1 . CDS 25000 25500 . + 0 ID=cds30006;Parent=mRNA30002;Name=edenprotein.2
77
78
  chr1 . CDS 27000 27600 . + 0 ID=cds30007;Parent=mRNA30002;Name=edenprotein.2
78
79
  chr1 . CDS 23301 23902 . + 0 ID=cds30008;Parent=mRNA30003;Name=edenprotein.3
79
- chr1 . CDS 25000 25500 . + 1 ID=cds30009;Parent=mRNA30003;Name=edenprotein.3
80
- chr1 . CDS 27000 27600 . + 1 ID=cds30010;Parent=mRNA30003;Name=edenprotein.3
81
- chr1 . CDS 23391 23902 . + 0 ID=cds30011;Parent=mRNA30003;Name=edenprotein.4
82
- chr1 . CDS 25000 25500 . + 1 ID=cds30012;Parent=mRNA30003;Name=edenprotein.4
80
+ chr1 . CDS 25000 25500 . + 2 ID=cds30009;Parent=mRNA30003;Name=edenprotein.3
81
+ chr1 . CDS 27000 27600 . + 2 ID=cds30010;Parent=mRNA30003;Name=edenprotein.3
82
+ chr1 . CDS 23391 23902 . + 1 ID=cds30011;Parent=mRNA30003;Name=edenprotein.4
83
+ chr1 . CDS 25000 25500 . + 2 ID=cds30012;Parent=mRNA30003;Name=edenprotein.4
83
84
  chr1 . CDS 27000 27600 . + 1 ID=cds30013;Parent=mRNA30003;Name=edenprotein.4
84
85
  # example 4
85
86
  chr1 . gene 31000 39000 . + . ID=gene40001;Name=EDEN
@@ -0,0 +1,6 @@
1
+ ##gff-version 3
2
+ chr1 . gene 1000 9000 . + . ID=gene00001
3
+ chr1 . mRNA 1300 9000 . + . ID=mRNA00001;Parent=gene00001
4
+ chr1 . five_prime_UTR 3000 3300 . + . Parent=mRNA00001
5
+ chr1 . CDS 5000 5500 . + 1 ID=cds00001;Parent=mRNA00001
6
+ chr1 . three_prime_UTR 7601 8000 . + . Parent=mRNA00001
@@ -0,0 +1,55 @@
1
+ {
2
+ "_id": "675af35f5758c90ab1d55838",
3
+ "refSeq": "chr1",
4
+ "type": "gene",
5
+ "min": 999,
6
+ "max": 9000,
7
+ "strand": 1,
8
+ "children": {
9
+ "675af35f5758c90ab1d55837": {
10
+ "_id": "675af35f5758c90ab1d55837",
11
+ "refSeq": "chr1",
12
+ "type": "mRNA",
13
+ "min": 1299,
14
+ "max": 9000,
15
+ "strand": 1,
16
+ "children": {
17
+ "675af35f5758c90ab1d55833": {
18
+ "_id": "675af35f5758c90ab1d55833",
19
+ "refSeq": "chr1",
20
+ "type": "CDS",
21
+ "min": 4999,
22
+ "max": 5500,
23
+ "strand": 1,
24
+ "attributes": { "gff_id": ["cds00001"] }
25
+ },
26
+ "675af35f5758c90ab1d55834": {
27
+ "_id": "675af35f5758c90ab1d55834",
28
+ "refSeq": "chr1",
29
+ "type": "exon",
30
+ "min": 2999,
31
+ "max": 3300,
32
+ "strand": 1
33
+ },
34
+ "675af35f5758c90ab1d55836": {
35
+ "_id": "675af35f5758c90ab1d55836",
36
+ "refSeq": "chr1",
37
+ "type": "exon",
38
+ "min": 4999,
39
+ "max": 5500,
40
+ "strand": 1
41
+ },
42
+ "675af35f5758c90ab1d55835": {
43
+ "_id": "675af35f5758c90ab1d55835",
44
+ "refSeq": "chr1",
45
+ "type": "exon",
46
+ "min": 7600,
47
+ "max": 8000,
48
+ "strand": 1
49
+ }
50
+ },
51
+ "attributes": { "gff_id": ["mRNA00001"] }
52
+ }
53
+ },
54
+ "attributes": { "gff_id": ["gene00001"] }
55
+ }