Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hubs 2 #1721

Merged
merged 15 commits into from
Oct 24, 2023
6 changes: 2 additions & 4 deletions dev/ucsc/hub.html
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,10 @@


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


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

const igvConfig = {
Expand Down
5 changes: 2 additions & 3 deletions dev/ucsc/slowHub.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,11 @@


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

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

const hub = await Hub.loadHub(hubOptions)

const igvConfig = {
showChromosomeWidget: false,
Expand Down
8 changes: 5 additions & 3 deletions js/browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -493,7 +493,9 @@ class Browser {
return new XMLSession(string, knownGenomes)

} else if (filename.endsWith("hub.txt")) {
const hub = await Hub.loadHub(options)

const hub = await Hub.loadHub(urlOrFile, options)

if(chromosomeSelectWidget) {
chromosomeSelectWidget.hide()
}
Expand Down Expand Up @@ -763,7 +765,7 @@ class Browser {

let genomeConfig
if (idOrConfig.url && StringUtils.isString(idOrConfig.url) && idOrConfig.url.endsWith("/hub.txt")) {
const hub = await Hub.loadHub(idOrConfig)
const hub = await Hub.loadHub(idOrConfig.url, idOrConfig)
genomeConfig = hub.getGenomeConfig("genes")
} else {
genomeConfig = idOrConfig //await GenomeUtils.expandReference(this.alert, idOrConfig)
Expand Down Expand Up @@ -793,7 +795,7 @@ class Browser {
*/
async loadTrackHub(options) {

const hub = await Hub.loadHub(options)
const hub = await Hub.loadHub(options.url, options)
const genomeConfig = hub.getGenomeConfig()
const initialLocus = hub.getDefaultPosition()
if (initialLocus) {
Expand Down
4 changes: 3 additions & 1 deletion js/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {registerFileFormats} from "./util/trackUtils.js"
import {igvxhr} from "../node_modules/igv-utils/src/index.js"
import {registerTrackClass, registerTrackCreatorFunction} from "./trackFactory.js"
import TrackBase from "./trackBase.js"
import Hub from "./ucsc/ucscHub.js"

const setApiKey = igvxhr.setApiKey

Expand Down Expand Up @@ -45,6 +46,7 @@ export default {
TrackBase,
registerTrackClass,
registerTrackCreatorFunction,
registerFileFormats
registerFileFormats,
Hub
}

20 changes: 11 additions & 9 deletions js/jbrowse/circularViewUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,15 +149,17 @@ const makeVCFChords = (features) => {
function makeCircViewChromosomes(genome) {
const regions = []
const colors = []
for (let chrName of genome.wgChromosomeNames) {
const chr = genome.getChromosome(chrName)
colors.push(getChrColor(chr.name))
regions.push(
{
name: chr.name,
bpLength: chr.bpLength
}
)
if(genome.wgChromosomeNames) {
for (let chrName of genome.wgChromosomeNames) {
const chr = genome.getChromosome(chrName)
colors.push(getChrColor(chr.name))
regions.push(
{
name: chr.name,
bpLength: chr.bpLength
}
)
}
}
return regions
}
Expand Down
85 changes: 59 additions & 26 deletions js/ucsc/ucscHub.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,32 +9,27 @@ import {igvxhr} from "../../node_modules/igv-utils/src/index.js"

class Hub {

static async loadHub(options) {

if (!options.url) {
throw Error("Expected url")
}
static supportedTypes = new Set(["bigBed", "bigWig", "bigGenePred"])
static filterTracks = new Set(["cytoBandIdeo", "assembly", "gap", "gapOverlap", "allGaps",
"cpgIslandExtUnmasked", "windowMasker"])

const stanzas = await loadStanzas(options)
static async loadHub(url, options) {

const stanzas = await loadStanzas(url, options)
let groups
if ("genome" === stanzas[1].type) {
const genome = stanzas[1]
if (genome.hasProperty("groups")) {
const idx = options.url.lastIndexOf("/")
const baseURL = options.url.substring(0, idx + 1)
const idx = url.lastIndexOf("/")
const baseURL = url.substring(0, idx + 1)
const groupsTxtURL = baseURL + genome.getProperty("groups")
groups = await loadStanzas({url: groupsTxtURL})
groups = await loadStanzas(groupsTxtURL)
}
}
return new Hub(options.url, stanzas, groups)
return new Hub(url, stanzas, groups)
}

static supportedTypes = new Set(["bigBed", "bigWig", "bigGenePred"])
static filterTracks = new Set(["cytoBandIdeo", "assembly", "gap", "gapOverlap", "allGaps",
"cpgIslandExtUnmasked", "windowMasker"])

constructor(url, stanzas, groups) {
constructor(url, stanzas, groupStanzas) {

const idx = url.lastIndexOf("/")
this.baseURL = url.substring(0, idx + 1)
Expand Down Expand Up @@ -69,21 +64,60 @@ class Hub {
}
}

if (groups) {
if (groupStanzas) {
this.groupStanzas = groupStanzas
this.groupPriorityMap = new Map()
for (let g of groups) {
for (let g of groupStanzas) {
if (g.hasProperty("priority")) {
this.groupPriorityMap.set(g.getProperty("name"), Number.parseInt(g.getProperty("priority")) * 10)
}
}
this.groupPriorities = new Map()
}
}

getDefaultPosition() {
return this.genomeStanza.getProperty("defaultPos")
}

getTrackConfigurations() {

// Organize track configs by group
const trackConfigMap = new Map()
for (let c of this.#getTracksConfigs()) {
const name = c.group || "other"
if (trackConfigMap.has(name)) {
trackConfigMap.get(name).push(c)
} else {
trackConfigMap.set(name, [c])
}
}

// Build group structure
const t = []
if (this.groupStanzas) {
for (let g of this.groupStanzas) {
const groupName = g.getProperty("name")
if(trackConfigMap.has(groupName)) {
t.push(
{
label: g.getProperty("label"),
tracks: trackConfigMap.get(g.getProperty("name"))
}
)
}
}
}

if(trackConfigMap.has("other")) {
t.push({
label: "other",
tracks: trackConfigMap.get("other")
})
}

return t
}

/* Example genome stanza
genome GCF_000186305.1
taxId 176946
Expand Down Expand Up @@ -123,6 +157,7 @@ isPcr dynablat-01.soe.ucsc.edu 4040 dynamic GCF/000/186/305/GCF_000186305.1
if (this.genomeStanza.hasProperty("twoBitBptURL")) {
config.twoBitBptURL = this.baseURL + this.genomeStanza.getProperty("twoBitBptURL")
}

if (this.genomeStanza.hasProperty("twoBitBptUrl")) {
config.twoBitBptURL = this.baseURL + this.genomeStanza.getProperty("twoBitBptUrl")
}
Expand Down Expand Up @@ -161,7 +196,7 @@ isPcr dynablat-01.soe.ucsc.edu 4040 dynamic GCF/000/186/305/GCF_000186305.1

// Tracks. To prevent loading tracks set `includeTracks`to false
if (includeTracks) {
config.tracks = this.#getTracksConfigs(includeTracks)
config.tracks = this.#getTracksConfigs(Hub.filterTracks)
}

return config
Expand All @@ -170,14 +205,12 @@ isPcr dynablat-01.soe.ucsc.edu 4040 dynamic GCF/000/186/305/GCF_000186305.1
/**
* Return collection of igv track config object, organized by "group*
*/
#getTracksConfigs(group) {
#getTracksConfigs(filter) {
return this.trackStanzas.filter(t => {
return t.getProperty("visibility") !== "hide" &&
Hub.supportedTypes.has(t.format) &&
!Hub.filterTracks.has(t.name) &&
t.hasProperty("bigDataUrl") &&
("all" === group || group === t.getProperty("group"))

(!filter || !Hub.filterTracks.has(t.name) &&
t.hasProperty("bigDataUrl"))
})
.map(t => this.#getTrackConfig(t))
}
Expand Down Expand Up @@ -353,9 +386,9 @@ class Stanza {
* @param url
* @returns {Promise<*[]>}
*/
async function loadStanzas(options) {
async function loadStanzas(url, options) {

const data = await igvxhr.loadString(options.url)
const data = await igvxhr.loadString(url)
const lines = data.split(/\n|\r\n|\r/g)

const nodes = []
Expand Down
47 changes: 47 additions & 0 deletions test/testHubs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import "./utils/mockObjects.js"
import {assert} from 'chai'
import Hub from "../js/ucsc/ucscHub.js"
import Trix from "../js/bigwig/trix.js"
import BWReader from "../js/bigwig/bwReader.js"
import BPTree from "../js/bigwig/bpTree.js"
import {isString} from "../node_modules/igv-utils/src/stringUtils.js"


suite("hub.txt", function () {


test("genome", async function () {

const hub = await Hub.loadHub("test/data/hubs/hub.txt")
assert.ok(hub.hub)
assert.ok(hub.genomeStanza)
assert.equal(22, hub.trackStanzas.length)

const genomeConfig = hub.getGenomeConfig()
//const genome = await Genome.loadGenome(genomeConfig)

assert.ok(genomeConfig)
assert.equal("GCF_000186305.1", genomeConfig.id)
assert.equal("Python bivittatus", genomeConfig.name)
assert.ok(genomeConfig.twoBitBptURL)
assert.ok(genomeConfig.twoBitURL)
assert.ok(genomeConfig.chromAliasBbURL)
assert.ok(genomeConfig.cytobandBbURL)
})

test("track configs", async function () {

const hub = await Hub.loadHub("test/data/hubs/hub.txt")
assert.ok(hub.hub)
assert.ok(hub.genomeStanza)
assert.equal(22, hub.trackStanzas.length)

const trackConfigs = hub.getTrackConfigurations()

assert.ok(trackConfigs.length > 0)

})


})

25 changes: 0 additions & 25 deletions test/testUCSC.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,9 @@ import {assert} from 'chai'
import Hub from "../js/ucsc/ucscHub.js"
import Trix from "../js/bigwig/trix.js"
import BWReader from "../js/bigwig/bwReader.js"
import BPTree from "../js/bigwig/bpTree.js"
import {isString} from "../node_modules/igv-utils/src/stringUtils.js"


suite("ucsc utilities", function () {


test("hub.txt", async function () {

this.timeout(200000)

const hub = await Hub.loadHub({url: "test/data/hubs/hub.txt"})
assert.ok(hub.hub)
assert.ok(hub.genomeStanza)
assert.equal(22, hub.trackStanzas.length)

const genomeConfig = hub.getGenomeConfig()
//const genome = await Genome.loadGenome(genomeConfig)

assert.ok(genomeConfig)
assert.equal("GCF_000186305.1", genomeConfig.id)
assert.equal("Python bivittatus", genomeConfig.name)
assert.ok(genomeConfig.twoBitBptURL)
assert.ok(genomeConfig.twoBitURL)
assert.ok(genomeConfig.chromAliasBbURL)
assert.ok(genomeConfig.cytobandBbURL)
})

test("trix", async function () {

this.timeout(200000)
Expand Down