Skip to content

Commit 524b2e0

Browse files
authored
Hubs 2 (#1721)
* Export ucsc HUB class * Add method to extract all loadable track configurations for web-app menu
1 parent fe33399 commit 524b2e0

File tree

8 files changed

+129
-71
lines changed

8 files changed

+129
-71
lines changed

dev/ucsc/hub.html

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,10 @@
3535

3636

3737
const hubOptions = {
38-
url: "https://hgdownload.soe.ucsc.edu/hubs/GCA/018/471/515/GCA_018471515.1/hub.txt",
39-
includeTracks: "all"
38+
includeTracks: true
4039
}
4140

42-
43-
const hub = await Hub.loadHub(hubOptions)
41+
const hub = await Hub.loadHub("https://hgdownload.soe.ucsc.edu/hubs/GCA/018/471/515/GCA_018471515.1/hub.txt", hubOptions)
4442
const ref = hub.getGenomeConfig()
4543

4644
const igvConfig = {

dev/ucsc/slowHub.html

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,11 @@
1616

1717

1818
const hubOptions = {
19-
url: "https://hgdownload.soe.ucsc.edu/hubs/GCA/004/027/145/GCA_004027145.1/hub.txt",
20-
includeTracks: "all"
19+
includeTracks: true
2120
}
2221

22+
const hub = await Hub.loadHub("https://hgdownload.soe.ucsc.edu/hubs/GCA/004/027/145/GCA_004027145.1/hub.txt", hubOptions)
2323

24-
const hub = await Hub.loadHub(hubOptions)
2524

2625
const igvConfig = {
2726
showChromosomeWidget: false,

js/browser.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -493,7 +493,9 @@ class Browser {
493493
return new XMLSession(string, knownGenomes)
494494

495495
} else if (filename.endsWith("hub.txt")) {
496-
const hub = await Hub.loadHub(options)
496+
497+
const hub = await Hub.loadHub(urlOrFile, options)
498+
497499
if(chromosomeSelectWidget) {
498500
chromosomeSelectWidget.hide()
499501
}
@@ -763,7 +765,7 @@ class Browser {
763765

764766
let genomeConfig
765767
if (idOrConfig.url && StringUtils.isString(idOrConfig.url) && idOrConfig.url.endsWith("/hub.txt")) {
766-
const hub = await Hub.loadHub(idOrConfig)
768+
const hub = await Hub.loadHub(idOrConfig.url, idOrConfig)
767769
genomeConfig = hub.getGenomeConfig("genes")
768770
} else {
769771
genomeConfig = idOrConfig //await GenomeUtils.expandReference(this.alert, idOrConfig)
@@ -793,7 +795,7 @@ class Browser {
793795
*/
794796
async loadTrackHub(options) {
795797

796-
const hub = await Hub.loadHub(options)
798+
const hub = await Hub.loadHub(options.url, options)
797799
const genomeConfig = hub.getGenomeConfig()
798800
const initialLocus = hub.getDefaultPosition()
799801
if (initialLocus) {

js/index.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {registerFileFormats} from "./util/trackUtils.js"
1111
import {igvxhr} from "../node_modules/igv-utils/src/index.js"
1212
import {registerTrackClass, registerTrackCreatorFunction} from "./trackFactory.js"
1313
import TrackBase from "./trackBase.js"
14+
import Hub from "./ucsc/ucscHub.js"
1415

1516
const setApiKey = igvxhr.setApiKey
1617

@@ -45,6 +46,7 @@ export default {
4546
TrackBase,
4647
registerTrackClass,
4748
registerTrackCreatorFunction,
48-
registerFileFormats
49+
registerFileFormats,
50+
Hub
4951
}
5052

js/jbrowse/circularViewUtils.js

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -149,15 +149,17 @@ const makeVCFChords = (features) => {
149149
function makeCircViewChromosomes(genome) {
150150
const regions = []
151151
const colors = []
152-
for (let chrName of genome.wgChromosomeNames) {
153-
const chr = genome.getChromosome(chrName)
154-
colors.push(getChrColor(chr.name))
155-
regions.push(
156-
{
157-
name: chr.name,
158-
bpLength: chr.bpLength
159-
}
160-
)
152+
if(genome.wgChromosomeNames) {
153+
for (let chrName of genome.wgChromosomeNames) {
154+
const chr = genome.getChromosome(chrName)
155+
colors.push(getChrColor(chr.name))
156+
regions.push(
157+
{
158+
name: chr.name,
159+
bpLength: chr.bpLength
160+
}
161+
)
162+
}
161163
}
162164
return regions
163165
}

js/ucsc/ucscHub.js

Lines changed: 59 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -9,32 +9,27 @@ import {igvxhr} from "../../node_modules/igv-utils/src/index.js"
99

1010
class Hub {
1111

12-
static async loadHub(options) {
13-
14-
if (!options.url) {
15-
throw Error("Expected url")
16-
}
12+
static supportedTypes = new Set(["bigBed", "bigWig", "bigGenePred"])
13+
static filterTracks = new Set(["cytoBandIdeo", "assembly", "gap", "gapOverlap", "allGaps",
14+
"cpgIslandExtUnmasked", "windowMasker"])
1715

18-
const stanzas = await loadStanzas(options)
16+
static async loadHub(url, options) {
1917

18+
const stanzas = await loadStanzas(url, options)
2019
let groups
2120
if ("genome" === stanzas[1].type) {
2221
const genome = stanzas[1]
2322
if (genome.hasProperty("groups")) {
24-
const idx = options.url.lastIndexOf("/")
25-
const baseURL = options.url.substring(0, idx + 1)
23+
const idx = url.lastIndexOf("/")
24+
const baseURL = url.substring(0, idx + 1)
2625
const groupsTxtURL = baseURL + genome.getProperty("groups")
27-
groups = await loadStanzas({url: groupsTxtURL})
26+
groups = await loadStanzas(groupsTxtURL)
2827
}
2928
}
30-
return new Hub(options.url, stanzas, groups)
29+
return new Hub(url, stanzas, groups)
3130
}
3231

33-
static supportedTypes = new Set(["bigBed", "bigWig", "bigGenePred"])
34-
static filterTracks = new Set(["cytoBandIdeo", "assembly", "gap", "gapOverlap", "allGaps",
35-
"cpgIslandExtUnmasked", "windowMasker"])
36-
37-
constructor(url, stanzas, groups) {
32+
constructor(url, stanzas, groupStanzas) {
3833

3934
const idx = url.lastIndexOf("/")
4035
this.baseURL = url.substring(0, idx + 1)
@@ -69,21 +64,60 @@ class Hub {
6964
}
7065
}
7166

72-
if (groups) {
67+
if (groupStanzas) {
68+
this.groupStanzas = groupStanzas
7369
this.groupPriorityMap = new Map()
74-
for (let g of groups) {
70+
for (let g of groupStanzas) {
7571
if (g.hasProperty("priority")) {
7672
this.groupPriorityMap.set(g.getProperty("name"), Number.parseInt(g.getProperty("priority")) * 10)
7773
}
7874
}
79-
this.groupPriorities = new Map()
8075
}
8176
}
8277

8378
getDefaultPosition() {
8479
return this.genomeStanza.getProperty("defaultPos")
8580
}
8681

82+
getTrackConfigurations() {
83+
84+
// Organize track configs by group
85+
const trackConfigMap = new Map()
86+
for (let c of this.#getTracksConfigs()) {
87+
const name = c.group || "other"
88+
if (trackConfigMap.has(name)) {
89+
trackConfigMap.get(name).push(c)
90+
} else {
91+
trackConfigMap.set(name, [c])
92+
}
93+
}
94+
95+
// Build group structure
96+
const t = []
97+
if (this.groupStanzas) {
98+
for (let g of this.groupStanzas) {
99+
const groupName = g.getProperty("name")
100+
if(trackConfigMap.has(groupName)) {
101+
t.push(
102+
{
103+
label: g.getProperty("label"),
104+
tracks: trackConfigMap.get(g.getProperty("name"))
105+
}
106+
)
107+
}
108+
}
109+
}
110+
111+
if(trackConfigMap.has("other")) {
112+
t.push({
113+
label: "other",
114+
tracks: trackConfigMap.get("other")
115+
})
116+
}
117+
118+
return t
119+
}
120+
87121
/* Example genome stanza
88122
genome GCF_000186305.1
89123
taxId 176946
@@ -123,6 +157,7 @@ isPcr dynablat-01.soe.ucsc.edu 4040 dynamic GCF/000/186/305/GCF_000186305.1
123157
if (this.genomeStanza.hasProperty("twoBitBptURL")) {
124158
config.twoBitBptURL = this.baseURL + this.genomeStanza.getProperty("twoBitBptURL")
125159
}
160+
126161
if (this.genomeStanza.hasProperty("twoBitBptUrl")) {
127162
config.twoBitBptURL = this.baseURL + this.genomeStanza.getProperty("twoBitBptUrl")
128163
}
@@ -161,7 +196,7 @@ isPcr dynablat-01.soe.ucsc.edu 4040 dynamic GCF/000/186/305/GCF_000186305.1
161196

162197
// Tracks. To prevent loading tracks set `includeTracks`to false
163198
if (includeTracks) {
164-
config.tracks = this.#getTracksConfigs(includeTracks)
199+
config.tracks = this.#getTracksConfigs(Hub.filterTracks)
165200
}
166201

167202
return config
@@ -170,14 +205,12 @@ isPcr dynablat-01.soe.ucsc.edu 4040 dynamic GCF/000/186/305/GCF_000186305.1
170205
/**
171206
* Return collection of igv track config object, organized by "group*
172207
*/
173-
#getTracksConfigs(group) {
208+
#getTracksConfigs(filter) {
174209
return this.trackStanzas.filter(t => {
175210
return t.getProperty("visibility") !== "hide" &&
176211
Hub.supportedTypes.has(t.format) &&
177-
!Hub.filterTracks.has(t.name) &&
178-
t.hasProperty("bigDataUrl") &&
179-
("all" === group || group === t.getProperty("group"))
180-
212+
(!filter || !Hub.filterTracks.has(t.name) &&
213+
t.hasProperty("bigDataUrl"))
181214
})
182215
.map(t => this.#getTrackConfig(t))
183216
}
@@ -353,9 +386,9 @@ class Stanza {
353386
* @param url
354387
* @returns {Promise<*[]>}
355388
*/
356-
async function loadStanzas(options) {
389+
async function loadStanzas(url, options) {
357390

358-
const data = await igvxhr.loadString(options.url)
391+
const data = await igvxhr.loadString(url)
359392
const lines = data.split(/\n|\r\n|\r/g)
360393

361394
const nodes = []

test/testHubs.js

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import "./utils/mockObjects.js"
2+
import {assert} from 'chai'
3+
import Hub from "../js/ucsc/ucscHub.js"
4+
import Trix from "../js/bigwig/trix.js"
5+
import BWReader from "../js/bigwig/bwReader.js"
6+
import BPTree from "../js/bigwig/bpTree.js"
7+
import {isString} from "../node_modules/igv-utils/src/stringUtils.js"
8+
9+
10+
suite("hub.txt", function () {
11+
12+
13+
test("genome", async function () {
14+
15+
const hub = await Hub.loadHub("test/data/hubs/hub.txt")
16+
assert.ok(hub.hub)
17+
assert.ok(hub.genomeStanza)
18+
assert.equal(22, hub.trackStanzas.length)
19+
20+
const genomeConfig = hub.getGenomeConfig()
21+
//const genome = await Genome.loadGenome(genomeConfig)
22+
23+
assert.ok(genomeConfig)
24+
assert.equal("GCF_000186305.1", genomeConfig.id)
25+
assert.equal("Python bivittatus", genomeConfig.name)
26+
assert.ok(genomeConfig.twoBitBptURL)
27+
assert.ok(genomeConfig.twoBitURL)
28+
assert.ok(genomeConfig.chromAliasBbURL)
29+
assert.ok(genomeConfig.cytobandBbURL)
30+
})
31+
32+
test("track configs", async function () {
33+
34+
const hub = await Hub.loadHub("test/data/hubs/hub.txt")
35+
assert.ok(hub.hub)
36+
assert.ok(hub.genomeStanza)
37+
assert.equal(22, hub.trackStanzas.length)
38+
39+
const trackConfigs = hub.getTrackConfigurations()
40+
41+
assert.ok(trackConfigs.length > 0)
42+
43+
})
44+
45+
46+
})
47+

test/testUCSC.js

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,34 +3,9 @@ import {assert} from 'chai'
33
import Hub from "../js/ucsc/ucscHub.js"
44
import Trix from "../js/bigwig/trix.js"
55
import BWReader from "../js/bigwig/bwReader.js"
6-
import BPTree from "../js/bigwig/bpTree.js"
7-
import {isString} from "../node_modules/igv-utils/src/stringUtils.js"
8-
96

107
suite("ucsc utilities", function () {
118

12-
13-
test("hub.txt", async function () {
14-
15-
this.timeout(200000)
16-
17-
const hub = await Hub.loadHub({url: "test/data/hubs/hub.txt"})
18-
assert.ok(hub.hub)
19-
assert.ok(hub.genomeStanza)
20-
assert.equal(22, hub.trackStanzas.length)
21-
22-
const genomeConfig = hub.getGenomeConfig()
23-
//const genome = await Genome.loadGenome(genomeConfig)
24-
25-
assert.ok(genomeConfig)
26-
assert.equal("GCF_000186305.1", genomeConfig.id)
27-
assert.equal("Python bivittatus", genomeConfig.name)
28-
assert.ok(genomeConfig.twoBitBptURL)
29-
assert.ok(genomeConfig.twoBitURL)
30-
assert.ok(genomeConfig.chromAliasBbURL)
31-
assert.ok(genomeConfig.cytobandBbURL)
32-
})
33-
349
test("trix", async function () {
3510

3611
this.timeout(200000)

0 commit comments

Comments
 (0)