taxonium-component
Version:
React component for exploring large phylogenetic trees in the browser
344 lines (343 loc) • 11.3 kB
JavaScript
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