Skip to content

Commit 2bbccd5

Browse files
authored
support whole genome view and chr dropdown under some conditions (#1906)
1 parent e3fdbb4 commit 2bbccd5

File tree

8 files changed

+88
-63
lines changed

8 files changed

+88
-63
lines changed

dev/ucsc/genome.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@
1212

1313
import igv from "../../js/index.js"
1414

15+
//https://hgdownload.soe.ucsc.edu/hubs/GCF/000/002/035/GCF_000002035.6/hub.txt
1516
const igvConfig = {
16-
genome: "GCA_000002305.1"
17+
genome: "GCF_000002035.6"
1718
}
1819

1920

js/bigwig/bwReader.js

Lines changed: 13 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ class BWReader {
5454
this.config = config
5555
this.bufferSize = BUFFER_SIZE
5656
this.loader = isDataURL(this.path) ?
57-
new DataBuffer(this.path) : igvxhr
57+
new DataBuffer(BGZip.decodeDataURI(this.path).buffer) :
58+
igvxhr
5859

5960
const trixURL = config.trixURL || config.searchTrix
6061
if (trixURL) {
@@ -63,6 +64,15 @@ class BWReader {
6364

6465
}
6566

67+
/**
68+
* Preload all the data for this bb file
69+
* @returns {Promise<void>}
70+
*/
71+
async preload() {
72+
const data = await igvxhr.loadArrayBuffer(this.path)
73+
this.loader = new DataBuffer(data)
74+
}
75+
6676
async readWGFeatures(bpPerPixel, windowFunction) {
6777
await this.loadHeader()
6878
const chrIdx1 = 0
@@ -732,8 +742,8 @@ function decodeZoomData(data, chrIdx1, bpStart, chrIdx2, bpEnd, featureArray, ch
732742

733743
class DataBuffer {
734744

735-
constructor(dataURI) {
736-
this.data = BGZip.decodeDataURI(dataURI).buffer
745+
constructor(data) {
746+
this.data = data
737747
}
738748

739749
/**
@@ -762,49 +772,5 @@ class DataBuffer {
762772
}
763773
}
764774

765-
class WholeFileBuffer {
766-
767-
data
768-
769-
constructor(path) {
770-
this.path = path
771-
}
772-
773-
async loadFile() {
774-
this.data = await igvxhr.loadArrayBuffer(this.path)
775-
}
776-
777-
/**
778-
* igvxhr interface
779-
* @param ignore
780-
* @param options
781-
* @returns {any}
782-
*/
783-
async loadArrayBuffer(ignore, options) {
784-
if (!this.data) {
785-
await this.loadFile()
786-
}
787-
const range = options.range
788-
return range ? this.data.slice(range.start, range.start + range.size) : this.data
789-
}
790-
791-
/**
792-
* BufferedReader interface
793-
*
794-
* @param requestedRange - byte rangeas {start, size}
795-
* @param fulfill - function to receive result
796-
* @param asUint8 - optional flag to return result as an UInt8Array
797-
*/
798-
async dataViewForRange(requestedRange, asUint8) {
799-
if (!this.data) {
800-
await this.loadFile()
801-
}
802-
const len = Math.min(this.data.byteLength - requestedRange.start, requestedRange.size)
803-
return asUint8 ?
804-
new Uint8Array(this.data, requestedRange.start, len) :
805-
new DataView(this.data, requestedRange.start, len)
806-
}
807-
808-
}
809775

810776
export default BWReader

js/genome/chromAliasBB.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,13 @@ class ChromAliasBB {
1919
this.reader = new BWReader(config, genome)
2020
}
2121

22+
async preload(chrNames) {
23+
await this.reader.preload();
24+
for(let nm of chrNames) {
25+
await this.search(nm)
26+
}
27+
}
28+
2229
/**
2330
* Return the cached canonical chromosome name for the alias. If none found return the alias.
2431
*

js/genome/chromAliasDefaults.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ class ChromAliasDefaults {
1414
this.update(id, chromosomeNames)
1515
}
1616

17+
async preload() {
18+
// no-op
19+
}
1720

1821
/**
1922
* Return the canonical chromosome name for the alias. If none found return the alias

js/genome/chromAliasFile.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ class ChromAliasFile {
2222
this.genome = genome
2323
}
2424

25+
async preload() {
26+
return this.loadAliases();
27+
}
28+
2529
/**
2630
* Return the canonical chromosome name for the alias. If none found return the alias
2731
*

js/genome/genome.js

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -57,28 +57,28 @@ class Genome {
5757

5858
if (config.chromAliasBbURL) {
5959
this.chromAlias = new ChromAliasBB(config.chromAliasBbURL, Object.assign({}, config), this)
60-
if(!this.chromosomeNames) {
60+
if (!this.chromosomeNames) {
6161
this.chromosomeNames = await this.chromAlias.getChromosomeNames()
6262
}
6363
} else if (config.aliasURL) {
6464
this.chromAlias = new ChromAliasFile(config.aliasURL, Object.assign({}, config), this)
6565
} else if (this.chromosomeNames) {
66-
this.chromAlias = new ChromAliasDefaults(this.id, this.chromosomeNames);
66+
this.chromAlias = new ChromAliasDefaults(this.id, this.chromosomeNames)
6767
}
6868

6969
if (config.cytobandBbURL) {
7070
this.cytobandSource = new CytobandFileBB(config.cytobandBbURL, Object.assign({}, config), this)
71-
if(!this.chromosomeNames) {
71+
if (!this.chromosomeNames) {
7272
this.chromosomeNames = await this.cytobandSource.getChromosomeNames()
7373
}
7474
} else if (config.cytobandURL) {
7575
this.cytobandSource = new CytobandFile(config.cytobandURL, Object.assign({}, config))
76-
if(!this.chromosomeNames) {
76+
if (!this.chromosomeNames) {
7777
this.chromosomeNames = await this.cytobandSource.getChromosomeNames()
7878
}
79-
if(this.chromosomes.size === 0) {
79+
if (this.chromosomes.size === 0) {
8080
const c = await this.cytobandSource.getChromosomes()
81-
for(let chromosome of c) {
81+
for (let chromosome of c) {
8282
this.chromosomes.set(c.name, c)
8383
}
8484
}
@@ -96,6 +96,7 @@ class Genome {
9696
} else {
9797
this.#wgChromosomeNames = trimSmallChromosomes(this.chromosomes)
9898
}
99+
await this.chromAlias.preload(this.#wgChromosomeNames)
99100
}
100101

101102
// Optionally create the psuedo chromosome "all" to support whole genome view
@@ -162,15 +163,15 @@ class Genome {
162163
async loadChromosome(chr) {
163164

164165
if (this.chromAlias) {
165-
const chromAliasRecord = await this.chromAlias.search(chr)
166-
if(chromAliasRecord) {
166+
const chromAliasRecord = await this.chromAlias.search(chr)
167+
if (chromAliasRecord) {
167168
chr = chromAliasRecord.chr
168169
}
169170
}
170171

171172
if (!this.chromosomes.has(chr)) {
172173
let chromosome
173-
const sequenceRecord = await this.sequence.getSequenceRecord(chr)
174+
const sequenceRecord = await this.sequence.getSequenceRecord(chr)
174175
if (sequenceRecord) {
175176
chromosome = new Chromosome(chr, 0, sequenceRecord.bpLength)
176177
}
@@ -180,6 +181,7 @@ class Genome {
180181

181182
return this.chromosomes.get(chr)
182183
}
184+
183185
async getAliasRecord(chr) {
184186
if (this.chromAlias) {
185187
return this.chromAlias.search(chr)
@@ -199,7 +201,7 @@ class Genome {
199201
}
200202

201203
get wgChromosomeNames() {
202-
return this.#wgChromosomeNames ? this.#wgChromosomeNames.slice() : undefined
204+
return this.#wgChromosomeNames ? this.#wgChromosomeNames.slice() : undefined
203205
}
204206

205207
get showChromosomeWidget() {
@@ -303,7 +305,7 @@ class Genome {
303305
* @param end
304306
*/
305307
getSequenceInterval(chr, start, end) {
306-
if(typeof this.sequence.getSequenceInterval === 'function') {
308+
if (typeof this.sequence.getSequenceInterval === 'function') {
307309
return this.sequence.getSequenceInterval(chr, start, end)
308310
} else {
309311
return undefined

js/ucsc/ucscHub.js

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,16 @@ class Hub {
2424
const groupsTxtURL = baseURL + genome.getProperty("groups")
2525
groups = await loadStanzas(groupsTxtURL)
2626
}
27+
28+
// If the genome has a chromSizes file, and it is not too large, set the chromSizesURL property. This will
29+
// enable whole genome view and the chromosome pulldown
30+
if (genome.hasProperty("chromSizes")) {
31+
const chromSizesURL = baseURL + genome.getProperty("chromSizes")
32+
const l = await getContentLength(chromSizesURL)
33+
if (l !== null && Number.parseInt(l) < 1000000) {
34+
genome.setProperty("chromSizesURL", chromSizesURL)
35+
}
36+
}
2737
}
2838

2939
// TODO -- categorize extra "user" supplied and other tracks in some distinctive way before including them
@@ -126,8 +136,13 @@ isPcr dynablat-01.soe.ucsc.edu 4040 dynamic GCF/000/186/305/GCF_000186305.1
126136
name: name,
127137
twoBitURL: this.baseURL + this.genomeStanza.getProperty("twoBitPath"),
128138
nameSet: "ucsc",
129-
wholeGenomeView: false,
130-
showChromosomeWidget: false
139+
}
140+
141+
if (this.genomeStanza.hasProperty("chromSizesURL")) {
142+
config.chromSizesURL = this.genomeStanza.getProperty("chromSizesURL")
143+
} else {
144+
config.wholeGenomeView = false
145+
config.showChromosomeWidget = false
131146
}
132147

133148
if (this.genomeStanza.hasProperty("defaultPos")) {
@@ -419,6 +434,26 @@ class Stanza {
419434
}
420435
}
421436

437+
438+
/**
439+
* Return the content length of the resource. If the content length cannot be determined return null;
440+
* @param url
441+
* @returns {Promise<number|string>}
442+
*/
443+
async function getContentLength(url) {
444+
try {
445+
const response = await fetch(url, {method: 'HEAD'})
446+
const headers = response.headers
447+
if (headers.has("content-length")) {
448+
return headers.get("content-length")
449+
} else {
450+
return null
451+
}
452+
} catch (e) {
453+
return null
454+
}
455+
}
456+
422457
/**
423458
* Parse a UCSC file
424459
* @param url

js/ui/chromosomeSelectWidget.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ class ChromosomeSelectWidget {
4747
})
4848

4949
this.showAllChromosomes = browser.config.showAllChromosomes !== false // i.e. default to true
50-
50+
this.genome = browser.genome
5151
}
5252

5353
show() {
@@ -58,10 +58,16 @@ class ChromosomeSelectWidget {
5858
this.container.style.display = 'none'
5959
}
6060

61+
setValue(chrName) {
62+
this.select.value = this.genome.getChromosomeDisplayName(chrName)
63+
}
64+
6165
update(genome) {
6266

67+
this.genome = genome
68+
6369
// Start with explicit chromosome name list
64-
const list = genome.wgChromosomeNames || []
70+
const list = genome.wgChromosomeNames.map(nm => genome.getChromosomeDisplayName(nm)) || []
6571

6672
if (this.showAllChromosomes && genome.chromosomeNames.length > 1) {
6773
const exclude = new Set(list)
@@ -72,6 +78,7 @@ class ChromosomeSelectWidget {
7278
break
7379
}
7480
if (!exclude.has(nm)) {
81+
nm = genome.getChromosomeDisplayName(nm)
7582
list.push(nm)
7683
}
7784
}

0 commit comments

Comments
 (0)