UNPKG

taxonium-component

Version:

React component for exploring large phylogenetic trees in the browser

326 lines (325 loc) 10.4 kB
import { B as _ } from "./bbi-HvSjvn8K.js"; import { A as T } from "./AbortablePromiseCache-CcuMrnn7.js"; import { Q as z } from "./index-BOYufR2k.js"; import { O as R } from "./Observable-D5EkXphs.js"; import { aV as H, a2 as D, a4 as $, a3 as P, u as k } from "./JBrowsePanel-uJIA-L6s.js"; import { a as j, m as L } from "./merge-BRfM1Dxk.js"; import { B as M, a as q } from "./util-X8nqr6IJ.js"; import { B as G } from "./index-BnQfM3Nw.js"; import { r as J } from "./rxjs-BnZkaVAs.js"; function Y(A) { return A.filter((e) => !!e); } class X extends _ { constructor() { super(...arguments), this.readIndicesCache = new T({ cache: new z({ maxSize: 1 }), fill: (e, t) => this._readIndices({ ...e, signal: t }) }); } readIndices(e = {}) { const { signal: t, ...a } = e; return this.readIndicesCache.get(JSON.stringify(a), e, t); } /* * retrieve unzoomed view for any scale */ async getView(e, t) { return this.getUnzoomedView(t); } /* * parse the bigbed extraIndex fields * * * @return a Promise for an array of Index data structure since there can be * multiple extraIndexes in a bigbed, see bedToBigBed documentation */ async _readIndices(e) { const { extHeaderOffset: t } = await this.getHeader(e), a = await this.bbi.read(64, Number(t)), s = new DataView(a.buffer, a.byteOffset, a.length); let i = 0; i += 2; const p = s.getUint16(i, !0); i += 2; const c = Number(s.getBigUint64(i, !0)); if (i += 8, p === 0) return []; const o = 20, g = o * p, N = await this.bbi.read(g, Number(c)), m = []; for (let y = 0; y < p; y += 1) { const l = N.subarray(y * o), w = new DataView(l.buffer, l.byteOffset, l.length); let n = 0; const f = w.getInt16(n, !0); n += 2; const d = w.getInt16(n, !0); n += 2; const h = Number(w.getBigUint64(n, !0)); n += 12; const S = w.getInt16(n, !0); m.push({ type: f, fieldcount: d, offset: Number(h), field: S }); } return m; } /* * perform a search in the bigbed extraIndex to find which blocks in the * bigbed data to look for the actual feature data * * @param name - the name to search for * * @param opts - a SearchOptions argument with optional signal * * @return a Promise for an array of bigbed block Loc entries */ async searchExtraIndexBlocks(e, t = {}) { const a = await this.readIndices(t); if (a.length === 0) return []; const s = new TextDecoder("utf8"), i = a.map(async (p) => { const { offset: c, field: o } = p, g = await this.bbi.read(32, c, t), N = new DataView(g.buffer, g.byteOffset, g.length); let m = 0; m += 4; const y = N.getInt32(m, !0); m += 4; const l = N.getInt32(m, !0); m += 4; const w = N.getInt32(m, !0); m += 4, m += 8; const n = async (f) => { const d = Number(f), h = 4 + y * (l + w), b = await this.bbi.read(h, d, t), u = new DataView(b.buffer, b.byteOffset, b.length); let r = 0; const E = u.getInt8(r); r += 2; const C = u.getInt16(r, !0); r += 2; const v = []; if (E === 0) { const I = []; for (let x = 0; x < C; x++) { const O = s.decode(b.subarray(r, r + l)).replaceAll("\0", ""); r += l; const V = Number(u.getBigUint64(r, !0)); r += 8, I.push({ key: O, offset: V }); } let B = 0; for (const { key: x, offset: O } of I) { if (e.localeCompare(x) < 0 && B) return n(B); B = O; } return n(B); } else if (E === 1) { for (let I = 0; I < C; I++) { const B = s.decode(b.subarray(r, r + l)).replaceAll("\0", ""); r += l; const x = Number(u.getBigUint64(r, !0)); r += 8; const O = u.getUint32(r, !0); r += 4; const V = u.getUint32(r, !0); r += 4, v.push({ key: B, offset: x, length: O, reserved: V }); } for (const I of v) if (I.key === e) return { ...I, field: o }; return; } }; return n(c + 32); }); return Y(await Promise.all(i)); } /* * retrieve the features from the bigbed data that were found through the * lookup of the extraIndex note that there can be multiple extraIndex, see * the BigBed specification and the -extraIndex argument to bedToBigBed * * @param name - the name to search for * * @param opts - options object with optional AboutSignal * * @return array of Feature */ async searchExtraIndex(e, t = {}) { const a = await this.searchExtraIndexBlocks(e, t); if (a.length === 0) return []; const s = await this.getUnzoomedView(t), i = a.map((c) => new R((o) => { s.readFeatures(o, [c], t).catch((g) => { o.error(g); }); }).pipe(H((o, g) => o.concat(g)), j((o) => { for (const g of o) g.field = c.field; return o; }))); return (await D(L(...i))).filter((c) => { var o; return ((o = c.rest) == null ? void 0 : o.split(" ")[(c.field || 0) - 3]) === e; }); } } class ce extends G.BaseFeatureDataAdapter { async configurePre(e) { const t = this.pluginManager, a = new X({ filehandle: $.openLocation(this.getConf("bigBedLocation"), t) }), s = await a.getHeader(e), i = new M({ autoSql: s.autoSql }); return { bigbed: a, header: s, parser: i }; } async configure(e) { return this.cachedP || (this.cachedP = this.configurePre(e).catch((t) => { throw this.cachedP = void 0, t; })), this.cachedP; } async getRefNames(e) { const { header: t } = await this.configure(e); return Object.keys(t.refsByName); } async getRefNameAliases(e) { const { header: t } = await this.configure(e); return (await Promise.all(Object.keys(t.refsByName).map(async (s) => (await D(this.getFeatures({ assemblyName: "", refName: s, start: 0, end: 1 }).pipe(P())))[0]))).map((s) => s.toJSON()).map((s) => ({ refName: s.ucsc, aliases: [s.ncbi, s.refseq, s.genbank], override: !0 })); } async getData() { const e = await this.getRefNames(), t = []; for (const a of e) { const s = await D(this.getFeatures({ assemblyName: "unknown", refName: a, start: 0, end: Number.MAX_SAFE_INTEGER }).pipe(P())); t.push(s); } return t.flat(); } async getHeader(e) { const { parser: t, header: a } = await this.configure(e), { version: s, fileType: i } = a, { fields: p, ...c } = t.autoSql; return { version: s, fileType: i, autoSql: { ...c }, fields: await this.getMetadata(e) }; } async getMetadata(e) { const { parser: t } = await this.configure(e), { fields: a } = t.autoSql; return Object.fromEntries(a.map(({ name: s, comment: i }) => [s, i])); } async getFeaturesHelper({ query: e, opts: t, observer: a, allowRedispatch: s, originalQuery: i = e }) { var p; const { statusCallback: c = () => { } } = t, o = this.getConf("scoreColumn"), g = this.getConf("aggregateField"), { parser: N, bigbed: m } = await k.updateStatus("Downloading header", c, () => this.configure(t)), y = await k.updateStatus("Downloading features", c, () => m.getFeatures(e.refName, e.start, e.end, { basesPerSpan: e.end - e.start })), l = {}, w = []; if (y.some((n) => n.uniqueId === void 0)) throw new Error("found uniqueId undefined"); for (const n of y) { const f = [ e.refName, `${n.start}`, `${n.end}`, ...((p = n.rest) === null || p === void 0 ? void 0 : p.split(" ")) || [] ], d = N.parseLine(f, { uniqueId: n.uniqueId }), h = d[g], S = h && h !== "none"; S && !l[h] && (l[h] = []); const { uniqueId: b, type: u, chrom: r, chromStart: E, chromEnd: C, description: v, chromStarts: I, blockStarts: B, blockSizes: x, score: O, blockCount: V, thickStart: K, thickEnd: Q, strand: W, ...U } = d, F = q({ ...U, scoreColumn: o, splitLine: f, parser: N, uniqueId: b, start: n.start, end: n.end, refName: e.refName }); S ? (l[h].push(F), w.push(F)) : k.doesIntersect2(F.start, F.end, i.start, i.end) && a.next(new k.SimpleFeature({ id: `${this.id}-${b}`, data: F })); } if (s && w.length) { let n = Number.POSITIVE_INFINITY, f = Number.NEGATIVE_INFINITY; for (const d of w) d.start < n && (n = d.start), d.end > f && (f = d.end); if (f > e.end || n < e.start) { await this.getFeaturesHelper({ query: { ...e, start: n - 5e5, end: f + 5e5 }, opts: t, observer: a, allowRedispatch: !1, originalQuery: e }); return; } } Object.entries(l).map(([n, f]) => { var d, h; const S = k.min(f.map((u) => u.start)), b = k.max(f.map((u) => u.end)); if (k.doesIntersect2(S, b, i.start, i.end)) { const u = f.sort((r, E) => r.uniqueId.localeCompare(E.uniqueId)); a.next(new k.SimpleFeature({ id: `${this.id}-${(d = u[0]) === null || d === void 0 ? void 0 : d.uniqueId}-parent`, data: { type: "gene", subfeatures: u, strand: ((h = u[0]) === null || h === void 0 ? void 0 : h.strand) || 1, name: n, start: S, end: b, refName: e.refName } })); } }), a.complete(); } getFeatures(e, t = {}) { return J.ObservableCreate(async (a) => { try { await this.getFeaturesHelper({ query: { ...e, start: e.start, end: e.end }, opts: t, observer: a, allowRedispatch: !0 }); } catch (s) { a.error(s); } }, t.stopToken); } } export { ce as default }; //# sourceMappingURL=BigBedAdapter-LiCn2BXJ.js.map