Skip to content

Commit

Permalink
Hub2 (#1738)
Browse files Browse the repository at this point in the history
* misc bug fixes

* hub updates

* fix unit test
  • Loading branch information
jrobinso authored Dec 1, 2023
1 parent 846c4e0 commit 0ea57ce
Show file tree
Hide file tree
Showing 17 changed files with 335 additions and 91 deletions.
49 changes: 49 additions & 0 deletions dev/ucsc/genomes.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>twobit</title>
</head>

<body>

<select id="select">
<option value=""></option>
<option value="gorGor4">gorGor4</option>
<option value="gorGor6">gorGor6</option>
</select>
<button id="load-genome">Load genome</button>
<br>


<div id="igvDiv" style="padding-top: 50px;padding-bottom: 20px; height: auto"></div>

<script type="module">

import igv from "../../js/index.js"
import Hub from "../../js/ucsc/ucscHub.js"


const igvConfig = {
genome: "gorGor4",
listeners: {
'genomechange': ({genome, trackConfigurations}) => {
console.log('genomechange')
console.log(genome)
console.log(trackConfigurations)
}
}
}


const browser = await igv.createBrowser(document.getElementById('igvDiv'), igvConfig)

document.getElementById("load-genome").addEventListener("click", async () => {
await browser.loadGenome(document.getElementById("select").value)
})


</script>

</body>

</html>
4 changes: 2 additions & 2 deletions dev/ucsc/hub.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
</option>
<option value="https://hgdownload.soe.ucsc.edu/hubs/GCF/013/103/735/GCF_013103735.1/hub.txt">24 large chromosomes
</option>
<option value="https://hgdownload.soe.ucsc.edu/hubs/GCA/009/914/755/GCA_009914755.4/hub.txt">T2T</option>
<option value="">T2T</option>
</select>

<label>
Expand All @@ -43,7 +43,7 @@
includeTracks: true
}

const hub = await Hub.loadHub("https://hgdownload.soe.ucsc.edu/hubs/GCA/009/914/755/GCA_009914755.4/hub.txt", hubOptions)
const hub = await Hub.loadHub("", hubOptions)

const igvConfig = {
reference: hub.getGenomeConfig(),
Expand Down
19 changes: 3 additions & 16 deletions js/bigwig/bwReader.js
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,7 @@ class BWReader {
const nZooms = header.nZoomLevels
binaryParser = new BinaryParser(new DataView(data), this.littleEndian)

// Load zoom headers, store in order of decreasing reduction level (increasing resolution)
this.zoomLevelHeaders = []
this.firstZoomDataOffset = Number.MAX_SAFE_INTEGER
for (let i = 1; i <= nZooms; i++) {
Expand Down Expand Up @@ -393,11 +394,7 @@ class BWReader {
if (header.extensionOffset > 0) {
await this.loadExtendedHeader(header.extensionOffset)
}

this.setDefaultVisibilityWindow(header)


return this.header
return this.header
}
}

Expand Down Expand Up @@ -478,16 +475,6 @@ class BWReader {
}
}

setDefaultVisibilityWindow(header) {
if (this.type === "bigwig") {
this.visibilityWindow = -1
} else {
this.visibilityWindow = -1
// bigbed -- todo

}
}

/**
* Directly load features given a file offset and size. Added to support search index.
* @param offset
Expand Down Expand Up @@ -660,7 +647,6 @@ function decodeZoomData(data, chrIdx1, bpStart, chrIdx2, bpEnd, featureArray, ch

while (binaryParser.remLength() >= minSize) {
const chromId = binaryParser.getInt()
const chr = chrDict[chromId]
const chromStart = binaryParser.getInt()
const chromEnd = binaryParser.getInt()
const validCount = binaryParser.getInt()
Expand All @@ -685,6 +671,7 @@ function decodeZoomData(data, chrIdx1, bpStart, chrIdx2, bpEnd, featureArray, ch


if (Number.isFinite(value)) {
const chr = chrDict[chromId]
featureArray.push({chr: chr, start: chromStart, end: chromEnd, value: value})


Expand Down
11 changes: 4 additions & 7 deletions js/bigwig/bwSource.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,16 +56,13 @@ class BWSource {
return this.reader.loadHeader()
}

getDefaultRange() {
if (this.reader.totalSummary !== undefined) {
return this.reader.totalSummary.defaultRange
async defaultVisibilityWindow() {
if (this.reader.type === "bigwig") {
return -1
} else {
return undefined
return this.reader.featureDensity ? Math.floor(10000 / this.reader.featureDensity) : -1
}
}

async defaultVisibilityWindow() {
return Math.floor(10000 / this.reader.featureDensity)
}

async getWGValues(windowFunction) {
Expand Down
3 changes: 2 additions & 1 deletion js/bigwig/trix.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,8 @@ export default class Trix {
const indexes = await this.getIndex(opts)
for (let i = 0; i < indexes.length; i++) {
const [key, value] = indexes[i]
const trimmedKey = key.slice(0, searchWord.length)
const trimmedEnd = Math.min(key.length, searchWord.length)
const trimmedKey = key.slice(0, trimmedEnd)
if (trimmedKey < searchWord) {
start = value
end = value + 65536
Expand Down
4 changes: 3 additions & 1 deletion js/browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -764,8 +764,10 @@ class Browser {
if (idOrConfig.url && StringUtils.isString(idOrConfig.url) && idOrConfig.url.endsWith("/hub.txt")) {
const hub = await Hub.loadHub(idOrConfig.url, idOrConfig)
genomeConfig = hub.getGenomeConfig("genes")
} else if (StringUtils.isString(idOrConfig)) {
genomeConfig = await GenomeUtils.expandReference(this.alert, idOrConfig)
} else {
genomeConfig = idOrConfig //await GenomeUtils.expandReference(this.alert, idOrConfig)
genomeConfig = idOrConfig
}

await this.loadReference(genomeConfig)
Expand Down
17 changes: 10 additions & 7 deletions js/genome/chromAliasBB.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import BWReader from "../bigwig/bwReader.js"

/**
* Represenets a UCSC bigbed alias file
* Chromosome alias source backed by a UCSC bigbed file
*
*
* @param aliasURL
* @param config
* @returns {Promise<*[]>}
*/
import {isNumber, buildOptions} from "../util/igvUtils.js"
import {igvxhr, StringUtils} from "../../node_modules/igv-utils/src/index.js"
import BWSource from "../bigwig/bwSource.js"
import BWReader from "../bigwig/bwReader.js"

class ChromAliasBB {

Expand All @@ -22,7 +20,9 @@ class ChromAliasBB {
}

/**
* Return the canonical chromosome name for the alias. If none found return the alias
* Return the canonical chromosome name for the alias. If none found return the alias.
*
* Note this will only work if a "search" for ths chromosome has been performed previously.
*
* @param alias
* @returns {*}
Expand All @@ -33,6 +33,9 @@ class ChromAliasBB {

/**
* Return an alternate chromosome name (alias). If not exists, return chr
*
* Note this will only work if a "search" for ths chromosome has been performed previously.
*
* @param chr
* @param nameSet -- The name set, e.g. "ucsc"
* @returns {*|undefined}
Expand All @@ -44,7 +47,7 @@ class ChromAliasBB {
}

/**
* Search for chromosome alias bed record. If found, catch results in the alias -> chr map
* Search for chromosome alias bed record. If found, cache results in the alias -> chr map
* @param alias
* @returns {Promise<any>}
*/
Expand Down
138 changes: 138 additions & 0 deletions js/genome/chromAliasDefaults.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
/**
* Default chromosome aliases, mostly 1<->chr1 etc. Used if chrom alias file is not supplied.
*
*/
import {isNumber, buildOptions} from "../util/igvUtils.js"
import {igvxhr, StringUtils} from "../../node_modules/igv-utils/src/index.js"

class ChromAliasDefaults {

aliasRecordCache = new Map()

constructor(id, chromosomeNames) {
this.init(id, chromosomeNames)
}

/**
* Return the canonical chromosome name for the alias. If none found return the alias
*
* @param alias
* @returns {*}
*/
getChromosomeName(alias) {
return this.aliasRecordCache.has(alias) ? this.aliasRecordCache.get(alias).chr : alias
}

/**
* Return an alternate chromosome name (alias).
*
* @param chr
* @param nameSet -- The name set, e.g. "ucsc"
* @returns {*|undefined}
*/
getChromosomeAlias(chr, nameSet)
{
const aliasRecord = this.aliasRecordCache.get(chr)
return aliasRecord ? aliasRecord[nameSet] || chr : chr
}

init(id, chromosomeNames) {

const aliasRecords = []
for (let name of chromosomeNames) {

let skipRest = false
const record = {chr: name}
aliasRecords.push(record)

if (name.startsWith("gi|")) {
// NCBI
const alias = ChromAliasDefaults.getNCBIName(name)
record["ncbi-gi-versioned"] = alias

// Also strip version number out, if present
const dotIndex = alias.lastIndexOf('.')
if (dotIndex > 0) {
const alias = alias.substring(0, dotIndex)
record["ncbi-gi"] = alias
}
} else {
// Special cases for human and mouse
if (id.startsWith("hg") || id.startsWith("GRCh") || id === "1kg_ref" || id === "b37") {
switch (name) {
case "23":
record["ucsc"] = "chrX"
skipRest = true
break
case "24":
record["ucsc"] = "chrY"
skipRest = true
break
case "chrX":
record["ncbi"] = "23"
skipRest = true
break
case "chrY":
record["ncbi"] = "24"
skipRest = true
break
}
} else if (id.startsWith("mm") || id.startsWith("GRCm") || id.startsWith("rheMac")) {
switch (name) {
case "21":
record["ucsc"] = "chrX"
skipRest = true
break
case "22":
record["ucsc"] = "chrY"
skipRest = true
break
case "chrX":
record["ncbi"] = "21"
skipRest = true
break
case "chrY":
record["ncbi"] = "22"
skipRest = true
break
}
}
if (skipRest) continue

//
if (name === "chrM") {
record["ncbi"] = "MT"
} else if (name === "MT") {
record["ucsc"] = "chrM"
} else if (name.toLowerCase().startsWith("chr")) {
record["ncbi"] = name.substring(3)
} else if (Number.isInteger(Number(name))) {
record["ucsc"] = "chr" + name
}
}
}

for (let rec of aliasRecords) {
for (let a of Object.values(rec)) {
this.aliasRecordCache.set(a, rec)
}
}
}

search(alias) {
return this.aliasRecordCache.get(alias)

}

/**
* Extract the user friendly name from an NCBI accession
* example: gi|125745044|ref|NC_002229.3| => NC_002229.3
*/
static getNCBIName(name) {
const tokens = name.split("\\|")
return tokens[tokens.length - 1]
}

}

export default ChromAliasDefaults
19 changes: 16 additions & 3 deletions js/genome/chromAliasFile.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,24 +32,37 @@ class ChromAliasFile {
return this.aliasRecordCache.has(alias) ? this.aliasRecordCache.get(alias).chr : alias
}

/**
* Return an alternate chromosome name (alias). If not exists, return chr
* @param chr
* @param nameSet -- The name set, e.g. "ucsc"
* @returns {*|undefined}
*/
getChromosomeAlias(chr, nameSet)
{
const aliasRecord = this.aliasRecordCache.get(chr)
return aliasRecord ? aliasRecord[nameSet] || chr : chr
}


async loadAliases() {

const data = await igvxhr.loadString(this.aliasURL, buildOptions(this.config))
const lines = StringUtils.splitLines(data)
const firstLine = lines[0]
if (firstLine.startsWith("#")) {
this.headings = firstLine.split("\t").map(h => h.trim())
this.headings = firstLine.substring(1).split("\t").map(h => h.trim())
this.altNameSets = this.headings.slice(1)
}

const chromosomeNameSet = this.genome.chromosomes ?
new Set(this.genome.chromosomes.keys()) : new Set()
const chromosomeNameSet = this.genome.chromosomeNames ?
new Set(this.genome.chromosomeNames) : new Set()

for (let line of lines) {
if (!line.startsWith("#") && line.length > 0) {
const tokens = line.split("\t")

// Find the canonical chromosome
let chr = tokens.find(t => chromosomeNameSet.has(t))
if(!chr) {
chr = tokens[0]
Expand Down
Loading

0 comments on commit 0ea57ce

Please sign in to comment.