diff --git a/dev/ucsc/genomes.html b/dev/ucsc/genomes.html new file mode 100644 index 000000000..53c99d0ce --- /dev/null +++ b/dev/ucsc/genomes.html @@ -0,0 +1,49 @@ + + + + twobit + + + + + + +
+ + +
+ + + + + + diff --git a/js/bigwig/bwReader.js b/js/bigwig/bwReader.js index edba6dd67..ebd6117b5 100644 --- a/js/bigwig/bwReader.js +++ b/js/bigwig/bwReader.js @@ -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++) { @@ -393,11 +394,7 @@ class BWReader { if (header.extensionOffset > 0) { await this.loadExtendedHeader(header.extensionOffset) } - - this.setDefaultVisibilityWindow(header) - - - return this.header + return this.header } } @@ -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 @@ -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() @@ -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}) diff --git a/js/bigwig/bwSource.js b/js/bigwig/bwSource.js index 8c8577c75..7b153374f 100755 --- a/js/bigwig/bwSource.js +++ b/js/bigwig/bwSource.js @@ -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) { diff --git a/js/browser.js b/js/browser.js index 88b23d65f..b130a0036 100755 --- a/js/browser.js +++ b/js/browser.js @@ -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) diff --git a/js/genome/chromAliasBB.js b/js/genome/chromAliasBB.js index d3ff4cce6..dfa14442f 100644 --- a/js/genome/chromAliasBB.js +++ b/js/genome/chromAliasBB.js @@ -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 { @@ -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 {*} @@ -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} @@ -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} */ diff --git a/js/genome/chromAliasDefaults.js b/js/genome/chromAliasDefaults.js new file mode 100644 index 000000000..b6294df71 --- /dev/null +++ b/js/genome/chromAliasDefaults.js @@ -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 diff --git a/js/genome/chromAliasFile.js b/js/genome/chromAliasFile.js index fdb7ef49b..4a80ada14 100644 --- a/js/genome/chromAliasFile.js +++ b/js/genome/chromAliasFile.js @@ -32,6 +32,18 @@ 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() { @@ -39,17 +51,18 @@ class ChromAliasFile { 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] diff --git a/js/genome/fasta.js b/js/genome/fasta.js index 4e4aa6b42..df8f589af 100644 --- a/js/genome/fasta.js +++ b/js/genome/fasta.js @@ -5,7 +5,7 @@ import ChromSizes from "./chromSizes.js" import Twobit from "./twobit.js" import CachedSequence from "./cachedSequence.js" -async function loadFasta(reference) { +async function loadSequence(reference) { let fasta if ("chromsizes" === reference.format) { @@ -21,4 +21,4 @@ async function loadFasta(reference) { return fasta } -export {loadFasta} +export {loadSequence} diff --git a/js/genome/genome.js b/js/genome/genome.js index 7002766d0..8f52e9af9 100644 --- a/js/genome/genome.js +++ b/js/genome/genome.js @@ -1,12 +1,13 @@ import {StringUtils} from "../../node_modules/igv-utils/src/index.js" import Chromosome from "./chromosome.js" -import {loadFasta} from "./fasta.js" +import {loadSequence} from "./fasta.js" import ChromAliasBB from "./chromAliasBB.js" import ChromAliasFile from "./chromAliasFile.js" import CytobandFileBB from "./cytobandFileBB.js" import CytobandFile from "./cytobandFile.js" import {loadChromSizes} from "./chromSizes.js" +import ChromAliasDefaults from "./chromAliasDefaults.js" /** * The Genome class represents an assembly and consists of the following elements @@ -18,6 +19,8 @@ import {loadChromSizes} from "./chromSizes.js" class Genome { + #wgChromosomeNames + static async createGenome(options) { const genome = new Genome(options) @@ -37,16 +40,16 @@ class Genome { const config = this.config - this.sequence = await loadFasta(config) + this.sequence = await loadSequence(config) if (config.chromSizes) { // a chromSizes file is neccessary for 2bit sequences for whole-genome view or chromosome pulldown this.chromosomes = await loadChromSizes(config.chromSizes) } else { + // if the sequence defines chromosomes use them (fasta does, 2bit does not) this.chromosomes = this.sequence.chromosomes || new Map() // This might be undefined, depending on sequence type } - // For backward compatibility if (this.chromosomes.size > 0) { this.chromosomeNames = Array.from(this.chromosomes.keys()) } @@ -55,6 +58,8 @@ class Genome { this.chromAlias = new ChromAliasBB(config.chromAliasBbURL, Object.assign({}, config), this) } else if (config.aliasURL) { this.chromAlias = new ChromAliasFile(config.aliasURL, Object.assign({}, config), this) + } else { + this.chromAlias = new ChromAliasDefaults(this.id, this.chromosomeNames); } if (config.cytobandBbURL) { @@ -67,19 +72,19 @@ class Genome { // Set chromosome order for WG view and chromosome pulldown. If chromosome order is not specified sort if (config.chromosomeOrder) { if (Array.isArray(config.chromosomeOrder)) { - this.wgChromosomeNames = config.chromosomeOrder + this.#wgChromosomeNames = config.chromosomeOrder } else { - this.wgChromosomeNames = config.chromosomeOrder.split(',').map(nm => nm.trim()) + this.#wgChromosomeNames = config.chromosomeOrder.split(',').map(nm => nm.trim()) } } else { - this.wgChromosomeNames = trimSmallChromosomes(this.chromosomes) + this.#wgChromosomeNames = trimSmallChromosomes(this.chromosomes) } } // Optionally create the psuedo chromosome "all" to support whole genome view - this.wholeGenomeView = config.wholeGenomeView !== false && this.wgChromosomeNames && this.chromosomes.size > 1 + this.wholeGenomeView = config.wholeGenomeView !== false && this.#wgChromosomeNames && this.chromosomes.size > 1 if (this.wholeGenomeView) { - const l = this.wgChromosomeNames.reduce((accumulator, currentValue) => accumulator += this.chromosomes.get(currentValue).bpLength, 0) + const l = this.#wgChromosomeNames.reduce((accumulator, currentValue) => accumulator += this.chromosomes.get(currentValue).bpLength, 0) this.chromosomes.set("all", new Chromosome("all", 0, l)) } } @@ -114,8 +119,7 @@ class Genome { if (this.showWholeGenomeView() && this.chromosomes.has("all")) { return "all" } else { - return this.sequence.getFirstChromosomeName() - + return this.chromosomeNames[0] } } @@ -160,14 +164,12 @@ class Genome { return this.chromosomes.get(chr) } - async getAliasRecord(chr) { if (this.chromAlias) { return this.chromAlias.search(chr) } } - getCytobands(chr) { if (this.cytobandSource) { const chrName = this.getChromosomeName(chr) @@ -179,6 +181,10 @@ class Genome { return this.chromosomes } + get wgChromosomeNames() { + return this.#wgChromosomeNames.slice() + } + /** * Return the genome coordinate in kb for the give chromosome and position. * NOTE: This might return undefined if the chr is filtered from whole genome view. @@ -202,7 +208,7 @@ class Genome { let lastChr = undefined let lastCoord = 0 - for (let name of this.wgChromosomeNames) { + for (let name of this.#wgChromosomeNames) { const cumulativeOffset = this.cumulativeOffsets[name] if (cumulativeOffset > genomeCoordinate) { @@ -214,7 +220,7 @@ class Genome { } // If we get here off the end - return {chr: this.wgChromosomeNames[this.wgChromosomeNames.length - 1], position: 0} + return {chr: this.#wgChromosomeNames[this.#wgChromosomeNames.length - 1], position: 0} }; @@ -234,15 +240,11 @@ class Genome { function computeCumulativeOffsets() { - let self = this let acc = {} let offset = 0 - for (let name of self.wgChromosomeNames) { - + for (let name of this.#wgChromosomeNames) { acc[name] = Math.floor(offset) - - const chromosome = self.getChromosome(name) - + const chromosome = this.getChromosome(name) offset += chromosome.bpLength } @@ -257,7 +259,7 @@ class Genome { if (!this.bpLength) { let bpLength = 0 - for (let cname of this.wgChromosomeNames) { + for (let cname of this.#wgChromosomeNames) { let c = this.chromosomes.get(cname) bpLength += c.bpLength } @@ -271,13 +273,6 @@ class Genome { return this.sequence.getSequence(chr, start, end) } - constructWG(config) { - - // Compute psuedo-chromosome "all" - const l = this.wgChromosomeNames.reduce((accumulator, currentValue) => accumulator += this.chromosomes.get(currentValue).bpLength, 0) - this.chromosomes.set("all", new Chromosome("all", 0, l)) - } - } /** diff --git a/js/sequenceTrack.js b/js/sequenceTrack.js index cc17e0977..d697e2bd0 100755 --- a/js/sequenceTrack.js +++ b/js/sequenceTrack.js @@ -26,7 +26,7 @@ import IGVGraphics from "./igv-canvas.js" import {isSecureContext} from "./util/igvUtils.js" import {reverseComplementSequence} from "./util/sequenceUtils.js" -import {loadFasta} from "./genome/fasta.js" +import {loadSequence} from "./genome/fasta.js" import {defaultNucleotideColors} from "./util/nucleotideColors.js"; const defaultSequenceTrackOrder = Number.MIN_SAFE_INTEGER @@ -441,7 +441,7 @@ class WrappedFasta { } async init() { - this.fasta = await loadFasta(this.config) + this.fasta = await loadSequence(this.config) this.chrNameMap = new Map() for(let name of this.fasta.chromosomeNames) { this.chrNameMap.set(this.genome.getChromosomeName(name), name) diff --git a/test/testChromAlias.js b/test/testChromAlias.js index d14bde29b..b57554fb4 100644 --- a/test/testChromAlias.js +++ b/test/testChromAlias.js @@ -2,6 +2,8 @@ import "./utils/mockObjects.js" import ChromAliasFile from "../js/genome/chromAliasFile.js" import BWReader from "../js/bigwig/bwReader.js" import {assert} from "chai" +import ChromAliasDefaults from "../js/genome/chromAliasDefaults.js" +import ChromAliasBB from "../js/genome/chromAliasBB.js" suite("chromAlias", function () { @@ -9,7 +11,10 @@ suite("chromAlias", function () { const genome = { chromosomes: new Map([ ["NC_007194.1", {name: "NC_007194.1", bpLength: 1}], - ]) + ]), + getChromosomeName: function (ignore) { + return "NC_007194.1" + } } /** @@ -35,6 +40,22 @@ suite("chromAlias", function () { assert.equal(chromAliasRecord.genbank, "CM000169.1") assert.equal(chromAliasRecord.ncbi, "1") assert.equal(chromAliasRecord.ucsc, "chr1") + + assert.equal(chromAlias.getChromosomeAlias("NC_007194.1", "genbank"), "CM000169.1") + }) + + test("test chromAlias.bb", async function () { + + const url = "test/data/genomes/GCF_000002655.1.chromAlias.bb" + + const chromAlias = new ChromAliasBB(url, {}, genome) + const chromAliasRecord = await chromAlias.search("1") + assert.equal(chromAliasRecord.chr, "NC_007194.1") + assert.equal(chromAliasRecord.genbank, "CM000169.1") + assert.equal(chromAliasRecord.ncbi, "1") + assert.equal(chromAliasRecord.ucsc, "chr1") + + assert.equal(chromAlias.getChromosomeAlias("NC_007194.1", "genbank"), "CM000169.1") }) test("test chromalias bb extra index search", async function () { @@ -55,4 +76,42 @@ suite("chromAlias", function () { const f2 = await bbReader.search(ucscName) assert.equal(ucscName, f2.ucsc) }) + + + test("test defaults", async function () { + + const genomeID = "hg*" + + // NCBI convention + let chrNames = [] + for (let i = 1; i < 25; i++) { + chrNames.push(i.toString()) + } + chrNames.push("MT") + + let chromAlias = new ChromAliasDefaults(genomeID, chrNames) + let chromAliasRecord = await chromAlias.search("chr1") + assert.equal(chromAliasRecord.chr, "1") + assert.equal(chromAlias.getChromosomeName("chrX"), "23") + assert.equal(chromAlias.getChromosomeName("chrM"), "MT") + + // UCSC convention + chrNames = [] + for (let i = 1; i < 23; i++) { + chrNames.push("chr" + i) + chrNames.push("chrX") + chrNames.push("chrY") + chrNames.push("chrM") + } + + chromAlias = new ChromAliasDefaults(genomeID, chrNames) + chromAliasRecord = await chromAlias.search("1") + assert.equal(chromAliasRecord.chr, "chr1") + assert.equal(chromAlias.getChromosomeName("23"), "chrX") + assert.equal(chromAlias.getChromosomeName("MT"), "chrM") + + // Defaults don't support name sets, + assert.equal(chromAlias.getChromosomeAlias("NC_007194.1", "genbank"), "NC_007194.1") + + }) }) diff --git a/test/testCytobands.js b/test/testCytobands.js index ecbe2fe6e..a5b3ea774 100644 --- a/test/testCytobands.js +++ b/test/testCytobands.js @@ -28,15 +28,5 @@ suite("test cytobands", function () { }) - test("test cytoband bigbed remote", async function () { - const url = "https://hgdownload.soe.ucsc.edu/hubs/GCA/009/914/755/GCA_009914755.4/bbi/GCA_009914755.4_T2T-CHM13v2.0.cytoBandMapped/cytoBandMapped.bb" - const src = new CytobandFileBB(url) - - const cytobands = await src.getCytobands("chr1") // "CP068269.2 - const last = cytobands[cytobands.length-1]; - assert.equal(248387328, last.end) - - }) - //CP068269.2 }) diff --git a/test/testFasta.js b/test/testFasta.js index 642613941..2a65b0844 100644 --- a/test/testFasta.js +++ b/test/testFasta.js @@ -1,5 +1,5 @@ import "./utils/mockObjects.js" -import {loadFasta} from "../js/genome/fasta.js" +import {loadSequence} from "../js/genome/fasta.js" import {assert} from 'chai' suite("testFasta", function () { @@ -29,7 +29,7 @@ suite("testFasta", function () { this.timeout(100000) - const fasta = await loadFasta({ + const fasta = await loadSequence({ fastaURL: "https://www.dropbox.com/s/bpf7g2ynx8qep73/chr22.fa?dl=0", indexURL: "https://www.dropbox.com/s/1jx9327vjkd87w5/chr22.fa.fai?dl=0" } @@ -76,7 +76,7 @@ suite("testFasta", function () { // >chr1:1000001-1000025 // GGGCACAGCCTCACCCAGGAAAGCA - const fasta = await loadFasta({ + const fasta = await loadSequence({ fastaURL: "test/data/fasta/sliced.fasta", indexed: false }) @@ -115,7 +115,7 @@ suite("testFasta", function () { // >chr1:1000001-1000025 @len=249250621 // GGGCACAGCCTCACCCAGGAAAGCA - const fasta = await loadFasta({ + const fasta = await loadSequence({ fastaURL: "test/data/fasta/sliced2.fasta", indexed: false }) @@ -157,7 +157,7 @@ suite("testFasta", function () { const expectedSequence = "CGGGGAGAGAGAGAGAGCGAGCCAGGTTCAGGTCCAGGGAGGAGAGAGACAGCGCGCGCGAGGCGGAGACCTGGAGGGAGAGGAGCTGCGGAGAGGGGTTAGGCGGGGAGGGAGAGAGCCAGGTTCAGGTCCAGGGAGGAGAGAGACAGCGCGCGCGAGGCGGAGACCTGGAGGGAGAGGAGCTGCGGAGAGGGGTTAGGCGGGGAGAGAGAGAGCGAGCCAGGTTCAGGTCCAGGGAGGAGAGAGACAGCGCGCGCGAGGCGGAGACCTGGAGGGAGAGGAGCTGCGGAGAGGGGTTAGGCGGGGAGGGAGAGAGACAGCGCGCGCGAGGCGGAGACCTGGAGGGAGAGGAGCTGCGGAGAGGGGTTAGGCGGCGGGAGGCCCGGGAGCGTTACATGTGTGTGGACTCGGGGAGGGCGGCGGGGGGCCGCTCCTCGGGGCCGTCTGCCTGCAGGAAGGAGTCCACGGACTTGCTGCTGAGGCGGAAGGGCATCAGGCGGCAGAAGGTGCCGGGAGAGTAGGGAATCTGCGTGCGGGCCCTCTGCGAGGGGACCACCGTCTCCCCGGGAGACAGCCAGGGCGGCAGCCTGGCCAGGAGGCTGCGGTCCAGGGCCTCGTCCGGAGAAAACACAGGGTTGTCAATTCCTAGGAGAGAGGGCAGCGGCTAGTCAGCCTTCGGAGAGCCCCACGGCGGCAGGGGAGACCTCGCCGGGGCCGTCACCTGCTGGGTGCCTTGGAAAGTTAGGGTCACCGGGAAGGTTAGGGTCACGTGCCTTTCAGGTTGCGGGCCCTTCCCCCACATCCATGACCCCACACGCCACAGGCAGCACAGGTAACGTCTCGCTTCCCTCAAGACATACCCCACCTGCTCCCTGCCCGGCCCACGTCTCCCCGGACAGCAGCCTCCGAGTTGGTTGAGGGGGCACTCAGTGGGTGCCAAGCAGGGCCCTTGAGAACCCACAGGAGACCCCACCCCcccaggtcccagtgcccctggtccaa" const dataUri = "data:application/gzip;base64,H4sIANLFrF8C/71SO07FMBDsuQudn16gQFpN4QvMBSIXoUa5v9iZtRNqJLCVF3u9nl/ex/j8ery3Z2vb9tqej7a9vaDniB8TehC9k/71OmurAWqpmUW4DtAt7tB9zgOBk9V3d/whwb+6+D0KCgeoBXSAYK+ZILyoZrdWyZNG6ig3FLQe8ZhLNuHrNC+XLAOFoxBeuKLbUyctOIzYLVjaamvhIWRTYom2eyyJYSlVEItBZuzWTFQMORAup8hUFJSn68sUlABkx6ic+Yk5sOj6ShtloxJx/BJid1SWadWx12mvNO7KbKy/yW3dPiVUHigi70Rm9ZLmBSMql16XZEnZcF6xHvgl9vJw5egQ7RJKWoLJilz4UrXMRPSZJtwSgakllrwcY4z9OE6/ziNf4/R2378BIJQ+9/4DAAA=" - const fasta = await loadFasta({ + const fasta = await loadSequence({ fastaURL: dataUri })