Skip to content

Commit

Permalink
Bug -- sorting GFF feature components did not account for chromosome,…
Browse files Browse the repository at this point in the history
… causing some indexed GFF files to prematurely truncate queried feature lists. See igvteam/igv-webapp#301
  • Loading branch information
jrobinso committed Aug 26, 2024
1 parent 1126da7 commit 3e29afd
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 41 deletions.
61 changes: 33 additions & 28 deletions js/feature/featureFileReader.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,20 +105,30 @@ class FeatureFileReader {
await this.readHeader()
}

let allFeatures
const index = await this.getIndex()
if (index) {
this.indexed = true
return this.loadFeaturesWithIndex(chr, start, end)
allFeatures = await this.loadFeaturesWithIndex(chr, start, end)
} else if (this.dataURI) {
this.indexed = false
return this.loadFeaturesFromDataURI()
allFeatures = await this.loadFeaturesFromDataURI()
} else if ("service" === this.config.sourceType) {
return this.loadFeaturesFromService(chr, start, end)
allFeatures = await this.loadFeaturesFromService(chr, start, end)
} else {
this.indexed = false
return this.loadFeaturesNoIndex()
allFeatures = await this.loadFeaturesNoIndex()
}

allFeatures.sort(function (a, b) {
if (a.chr === b.chr) {
return a.start - b.start
} else {
return a.chr.localeCompare(b.chr)
}
})

return allFeatures
}

async readHeader() {
Expand Down Expand Up @@ -290,9 +300,6 @@ class FeatureFileReader {
await this._parse(allFeatures, dataWrapper, chr, end, start)

}
allFeatures.sort(function (a, b) {
return a.start - b.start
})

return allFeatures
}
Expand Down Expand Up @@ -322,8 +329,13 @@ class FeatureFileReader {

let features = await this.parser.parseFeatures(dataWrapper)

// Filter psuedo-features (e.g. created mates for VCF SV records) TODO why?
//slicedFeatures = slicedFeatures.filter(f => f._f === undefined)
features.sort(function (a, b) {
if (a.chr === b.chr) {
return a.start - b.start
} else {
return a.chr.localeCompare(b.chr)
}
})

// Filter features not in requested range.
if (undefined === chr) {
Expand All @@ -332,28 +344,21 @@ class FeatureFileReader {
let inInterval = false
for (let i = 0; i < features.length; i++) {
const f = features[i]
if (f.chr !== chr) {
if (allFeatures.length === 0) {
continue //adjacent chr to the left
} else {
break //adjacent chr to the right
if (f.chr === chr) {
if (f.start > end) {
allFeatures.push(f) // First feature beyond interval
break
}
}
if (f.start > end) {
allFeatures.push(f) // First feature beyond interval
break
}
if (f.end >= start && f.start <= end) {
// All this to grab first feature before start of interval. Needed for some track renderers, like line plot
if (!inInterval) {
inInterval = true
if (i > 0) {
allFeatures.push(features[i - 1])
} else {
// TODO -- get block before this one for first feature;
if (f.end >= start && f.start <= end) {
// All this to grab first feature before start of interval. Needed for some track renderers, like line plot
if (!inInterval) {
inInterval = true
if (i > 0) {
allFeatures.push(features[i - 1])
}
}
allFeatures.push(f)
}
allFeatures.push(f)
}
}
}
Expand Down
4 changes: 1 addition & 3 deletions js/feature/gff/gffHelper.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,7 @@ class GFFHelper {
} else {
combinedFeatures = this.combineFeaturesByType(features)
}
combinedFeatures.sort(function (a, b) {
return a.start - b.start
})

this.numberExons(combinedFeatures, genomicInterval)
this.nameFeatures(combinedFeatures)
return combinedFeatures
Expand Down
4 changes: 2 additions & 2 deletions test/testBED.js
Original file line number Diff line number Diff line change
Expand Up @@ -376,10 +376,10 @@ suite("testBed", function () {
const features = await reader.readFeatures("chr1", 0, Number.MAX_VALUE)
assert.ok(features)
assert.equal(features.length, 4)
assert.equal(features[1].name, 'terminator')
assert.equal(features[1].name, 'INS230')
assert.equal(features[2].name, 'M13 origin')
assert.equal(features[3].name, 'M13 origin')
assert.equal("Baz", features[3].getAttributeValue("Key2"))
assert.equal("Bar", features[0].getAttributeValue("Key2"))
})

})
Expand Down
27 changes: 19 additions & 8 deletions test/testGFF.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,18 @@ import {decodeGFFAttribute, parseAttributeString} from "../js/feature/gff/parseA

suite("testGFF", function () {

const combineFeatures = (features, helper) => {
const combinedFeatures = helper.combineFeatures(features)
combinedFeatures.sort(function (a, b) {
if (a.chr === b.chr) {
return a.start - b.start
} else {
return a.chr.localeCompare(b.chr)
}
})
return combinedFeatures
}

test("Eden GFF", async function () {

const chr = "chr1"
Expand All @@ -32,7 +44,7 @@ suite("testGFF", function () {

// Combine features
const helper = new GFFHelper({format: "gff3"})
const combinedFeatures = helper.combineFeatures(features)
const combinedFeatures = combineFeatures(features, helper)
assert.equal(4, combinedFeatures.length)

// Check last transcript
Expand Down Expand Up @@ -73,7 +85,7 @@ CDS 7000 7600 . + 1 ID=cds00003;Parent=mRNA00003;Name=edenprotein.3

// Combine features
const helper = new GFFHelper({format: "gff3"})
const combinedFeatures = helper.combineFeatures(features)
const combinedFeatures = combineFeatures(features, helper)
assert.equal(1, combinedFeatures.length)
assert.equal(3, combinedFeatures[0].exons.length)
})
Expand All @@ -97,7 +109,7 @@ CDS 7000 7600 . + 1 ID=cds00003;Parent=mRNA00003;Name=edenprotein.3

// Combine features
const helper = new GFFHelper({format: "gff3"})
const combinedFeatures = helper.combineFeatures(features)
const combinedFeatures = combineFeatures(features, helper)

// 9 mRNAs, 11 biological regions
assert.equal(20, combinedFeatures.length)
Expand Down Expand Up @@ -125,7 +137,7 @@ CDS 7000 7600 . + 1 ID=cds00003;Parent=mRNA00003;Name=edenprotein.3

// Combine features
const helper = new GFFHelper({format: "gtf"})
const combinedFeatures = helper.combineFeatures(features)
const combinedFeatures = combineFeatures(features, helper)
assert.equal(2, combinedFeatures.length)

const transcript1 = combinedFeatures[0]
Expand Down Expand Up @@ -159,7 +171,7 @@ CDS 7000 7600 . + 1 ID=cds00003;Parent=mRNA00003;Name=edenprotein.3

// Combine features
const helper = new GFFHelper({format: "gtf"})
const combinedFeatures = helper.combineFeatures(features)
const combinedFeatures = combineFeatures(features, helper)
assert.equal(2, combinedFeatures.length)
assert.equal(3, combinedFeatures[0].exons.length)
assert.equal(3, combinedFeatures[0].exons.length)
Expand All @@ -184,7 +196,7 @@ CDS 7000 7600 . + 1 ID=cds00003;Parent=mRNA00003;Name=edenprotein.3

// Combine features
const helper = new GFFHelper({format: "gtf"})
const combinedFeatures = helper.combineFeatures(features)
const combinedFeatures = combineFeatures(features, helper)
assert.equal(1, combinedFeatures.length)
assert.equal(2, combinedFeatures[0].exons.length)

Expand Down Expand Up @@ -226,7 +238,7 @@ CDS 7000 7600 . + 1 ID=cds00003;Parent=mRNA00003;Name=edenprotein.3

// Combine features
const helper = new GFFHelper({format: "gtf"})
const combinedFeatures = helper.combineFeatures(features)
const combinedFeatures = combineFeatures(features, helper)
assert.equal(5, combinedFeatures.length)
assert.equal(5, combinedFeatures[0].exons.length)

Expand Down Expand Up @@ -261,7 +273,6 @@ CDS 7000 7600 . + 1 ID=cds00003;Parent=mRNA00003;Name=edenprotein.3

})


test("GFF query", async function () {

const chr = "chr1"
Expand Down

0 comments on commit 3e29afd

Please sign in to comment.