UNPKG

taxonium-component

Version:

React component for exploring large phylogenetic trees in the browser

344 lines (343 loc) 11.3 kB
import { B as _ } from "./bbi-Bgo-D0LY.js"; import { A as T } from "./AbortablePromiseCache-CcuMrnn7.js"; import { Q as $ } from "./remoteFile-H_6BTCFF.js"; import { O as z } from "./Observable-bHPg1QB7.js"; import { aH as H, $ as P, a1 as R, a0 as D, u as I } from "./JBrowsePanel-BNE3gNW1.js"; import { a as j, m as L } from "./merge-BKxtGK-k.js"; import { B as M, a as q } from "./util-DIF6WZFN.js"; import { B as G } from "./index-CpJXUZUB.js"; import { r as J } from "./rxjs-L4bS73F7.js"; function Y(v) { return v.filter((e) => !!e); } class X extends _ { constructor() { super(...arguments), this.readIndicesCache = new T({ cache: new $({ maxSize: 1 }), fill: (e, t) => this._readIndices({ ...e, signal: t }) }); } readIndices(e = {}) { const { signal: t, ...s } = e; return this.readIndicesCache.get(JSON.stringify(s), 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), s = await this.bbi.read(64, Number(t)), n = new DataView(s.buffer, s.byteOffset, s.length); let i = 0; i += 2; const p = n.getUint16(i, !0); i += 2; const d = Number(n.getBigUint64(i, !0)); if (i += 8, p === 0) return []; const o = 20, u = o * p, x = await this.bbi.read(u, Number(d)), l = []; for (let S = 0; S < p; S += 1) { const g = x.subarray(S * o), N = new DataView(g.buffer, g.byteOffset, g.length); let r = 0; const c = N.getInt16(r, !0); r += 2; const f = N.getInt16(r, !0); r += 2; const m = Number(N.getBigUint64(r, !0)); r += 12; const k = N.getInt16(r, !0); l.push({ type: c, fieldcount: f, offset: Number(m), field: k }); } return l; } /* * 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 s = await this.readIndices(t); if (s.length === 0) return []; const n = new TextDecoder("utf8"), i = s.map(async (p) => { const { offset: d, field: o } = p, u = await this.bbi.read(32, d, t), x = new DataView(u.buffer, u.byteOffset, u.length); let l = 0; l += 4; const S = x.getInt32(l, !0); l += 4; const g = x.getInt32(l, !0); l += 4; const N = x.getInt32(l, !0); l += 4, l += 8; const r = async (c) => { const f = Number(c), m = 4 + S * (g + N), b = await this.bbi.read(m, f, t), y = new DataView(b.buffer, b.byteOffset, b.length); let a = 0; const h = y.getInt8(a); a += 2; const B = y.getInt16(a, !0); a += 2; const F = []; if (h === 0) { const w = []; for (let E = 0; E < B; E++) { const A = n.decode(b.subarray(a, a + g)).replaceAll("\0", ""); a += g; const C = Number(y.getBigUint64(a, !0)); a += 8, w.push({ key: A, offset: C }); } let O = 0; for (const { key: E, offset: A } of w) { if (e.localeCompare(E) < 0 && O) return r(O); O = A; } return r(O); } else if (h === 1) { for (let w = 0; w < B; w++) { const O = n.decode(b.subarray(a, a + g)).replaceAll("\0", ""); a += g; const E = Number(y.getBigUint64(a, !0)); a += 8; const A = y.getUint32(a, !0); a += 4; const C = y.getUint32(a, !0); a += 4, F.push({ key: O, offset: E, length: A, reserved: C }); } for (const w of F) if (w.key === e) return { ...w, field: o }; return; } }; return r(d + 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 s = await this.searchExtraIndexBlocks(e, t); if (s.length === 0) return []; const n = await this.getUnzoomedView(t), i = s.map((d) => new z((o) => { n.readFeatures(o, [d], t).catch((u) => { o.error(u); }); }).pipe(H((o, u) => o.concat(u)), j((o) => { for (const u of o) u.field = d.field; return o; }))); return (await P(L(...i))).filter((d) => { var o; return ((o = d.rest) == null ? void 0 : o.split(" ")[(d.field || 0) - 3]) === e; }); } } class ce extends G.BaseFeatureDataAdapter { async configurePre(e) { const t = this.pluginManager, s = new X({ filehandle: R.openLocation(this.getConf("bigBedLocation"), t) }), n = await s.getHeader(e), i = new M({ autoSql: n.autoSql }); return { bigbed: s, header: n, 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 (n) => (await P(this.getFeatures({ assemblyName: "", refName: n, start: 0, end: 1 }).pipe(D())))[0]))).map((n) => n.toJSON()).map((n) => ({ refName: n.ucsc, aliases: [n.ncbi, n.refseq, n.genbank], override: !0 })); } async getData() { const e = await this.getRefNames(), t = []; for (const s of e) { const n = await P(this.getFeatures({ assemblyName: "unknown", refName: s, start: 0, end: Number.MAX_SAFE_INTEGER }).pipe(D())); t.push(n); } return t.flat(); } async getHeader(e) { const { parser: t, header: s } = await this.configure(e), { version: n, fileType: i } = s, { fields: p, ...d } = t.autoSql; return { version: n, fileType: i, autoSql: d, fields: await this.getMetadata(e) }; } async getMetadata(e) { const { parser: t } = await this.configure(e), { fields: s } = t.autoSql; return Object.fromEntries(s.map(({ name: n, comment: i }) => [n, i])); } async getFeaturesHelper({ query: e, opts: t, observer: s, allowRedispatch: n, originalQuery: i = e }) { const { statusCallback: p = () => { } } = t, d = this.getConf("scoreColumn"), o = this.getConf("aggregateField"), { parser: u, bigbed: x } = await I.updateStatus("Downloading header", p, () => this.configure(t)), l = await I.updateStatus("Downloading features", p, () => x.getFeatures(e.refName, e.start, e.end, { basesPerSpan: e.end - e.start })); await I.updateStatus("Processing features", p, async () => { var S; const g = {}, N = []; if (l.some((r) => r.uniqueId === void 0)) throw new Error("found uniqueId undefined"); for (const r of l) { const c = [ e.refName, `${r.start}`, `${r.end}`, ...((S = r.rest) === null || S === void 0 ? void 0 : S.split(" ")) || [] ], f = u.parseLine(c, { uniqueId: r.uniqueId }), m = f[o], k = m && m !== "none"; k && !g[m] && (g[m] = []); const { uniqueId: b, type: y, chrom: a, chromStart: h, chromEnd: B, description: F, chromStarts: w, blockStarts: O, blockSizes: E, score: A, blockCount: C, thickStart: K, thickEnd: Q, strand: W, ...U } = f, V = q({ ...U, scoreColumn: d, splitLine: c, parser: u, uniqueId: b, start: r.start, end: r.end, refName: e.refName }); k ? (g[m].push(V), N.push(V)) : I.doesIntersect2(V.start, V.end, i.start, i.end) && s.next(new I.SimpleFeature({ id: `${this.id}-${b}`, data: V })); } if (n && N.length) { let r = Number.POSITIVE_INFINITY, c = Number.NEGATIVE_INFINITY; for (const f of N) f.start < r && (r = f.start), f.end > c && (c = f.end); if (c > e.end || r < e.start) { await this.getFeaturesHelper({ query: { ...e, start: r - 5e5, end: c + 5e5 }, opts: t, observer: s, allowRedispatch: !1, originalQuery: e }); return; } } Object.entries(g).map(([r, c]) => { var f, m, k; const b = I.min(c.map((a) => a.start)), y = I.max(c.map((a) => a.end)); if (I.doesIntersect2(b, y, i.start, i.end)) { const a = c.sort((h, B) => h.uniqueId.localeCompare(B.uniqueId)); if (a.some((h, B) => a.some((F, w) => B !== w && I.doesIntersect2(h.start, h.end, F.start, F.end)))) s.next(new I.SimpleFeature({ id: `${this.id}-${(f = a[0]) === null || f === void 0 ? void 0 : f.uniqueId}-parent`, data: { type: "gene", subfeatures: a, strand: ((m = a[0]) === null || m === void 0 ? void 0 : m.strand) || 1, name: r, start: b, end: y, refName: e.refName } })); else for (const h of a) s.next(new I.SimpleFeature({ id: `${this.id}-${h.uniqueId}-parent`, data: { type: "gene", subfeatures: [h], strand: ((k = a[0]) === null || k === void 0 ? void 0 : k.strand) || 1, name: r, start: h.start, end: h.end, refName: e.refName } })); } }); }), s.complete(); } getFeatures(e, t = {}) { return J.ObservableCreate(async (s) => { try { await this.getFeaturesHelper({ query: { ...e, start: e.start, end: e.end }, opts: t, observer: s, allowRedispatch: !0 }); } catch (n) { s.error(n); } }, t.stopToken); } } export { ce as default }; //# sourceMappingURL=BigBedAdapter-DyrJgn2D.js.map