UNPKG

@jbrowse/core

Version:

JBrowse 2 core libraries used by plugins

116 lines (115 loc) 4.79 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.BaseFeatureDataAdapter = void 0; const rxjs_1 = require("rxjs"); const operators_1 = require("rxjs/operators"); const BaseAdapter_1 = require("./BaseAdapter"); const util_1 = require("../../util"); const rxjs_2 = require("../../util/rxjs"); const stats_1 = require("../../util/stats"); const stopToken_1 = require("../../util/stopToken"); class BaseFeatureDataAdapter extends BaseAdapter_1.BaseAdapter { async getHeader(_opts) { return null; } async getMetadata(_opts) { return null; } getFeaturesInRegion(region, opts = {}) { return (0, rxjs_2.ObservableCreate)(async (observer) => { const hasData = await this.hasDataForRefName(region.refName, opts); (0, stopToken_1.checkStopToken)(opts.stopToken); if (!hasData) { observer.complete(); } else { this.getFeatures(region, opts).subscribe(observer); } }); } getFeaturesInMultipleRegions(regions, opts = {}) { return (0, rxjs_1.merge)(...regions.map(region => this.getFeaturesInRegion(region, opts))); } async hasDataForRefName(refName, opts = {}) { const refNames = await this.getRefNames(opts); return refNames.includes(refName); } async getRegionQuantitativeStats(region, opts) { const feats = this.getFeatures(region, opts); return (0, stats_1.scoresToStats)(region, feats); } async getMultiRegionQuantitativeStats(regions = [], opts) { if (!regions.length) { return (0, stats_1.blankStats)(); } const feats = await Promise.all(regions.map(region => this.getRegionQuantitativeStats(region, opts))); const scoreMax = (0, util_1.max)(feats.map(a => a.scoreMax)); const scoreMin = (0, util_1.min)(feats.map(a => a.scoreMin)); const scoreSum = (0, util_1.sum)(feats.map(a => a.scoreSum)); const scoreSumSquares = (0, util_1.sum)(feats.map(a => a.scoreSumSquares)); const featureCount = (0, util_1.sum)(feats.map(a => a.featureCount)); const basesCovered = (0, util_1.sum)(feats.map(a => a.basesCovered)); return (0, stats_1.rectifyStats)({ scoreMin, scoreMax, featureCount, basesCovered, scoreSumSquares, scoreSum, }); } getRegionFeatureDensityStats(region, opts) { let lastTime = +Date.now(); const statsFromInterval = async (length, expansionTime) => { const { start, end } = region; const sampleCenter = start * 0.75 + end * 0.25; const features = await (0, rxjs_1.firstValueFrom)(this.getFeatures({ ...region, start: Math.max(0, Math.round(sampleCenter - length / 2)), end: Math.min(Math.round(sampleCenter + length / 2), end), }, opts).pipe((0, operators_1.toArray)())); return maybeRecordStats({ interval: length, statsSampleFeatures: features.length, expansionTime, stats: { featureDensity: features.length / length, }, }); }; const maybeRecordStats = async ({ interval, stats, statsSampleFeatures, expansionTime, }) => { const refLen = region.end - region.start; if (statsSampleFeatures >= 70 || interval * 2 > refLen) { return stats; } else if (expansionTime <= 5000) { const currTime = +Date.now(); expansionTime += currTime - lastTime; lastTime = currTime; return statsFromInterval(interval * 2, expansionTime); } else { console.warn("Stats estimation reached timeout, or didn't get enough features"); return { featureDensity: Number.POSITIVE_INFINITY }; } }; return statsFromInterval(1000, 0); } async getMultiRegionFeatureDensityStats(regions, opts) { if (!regions.length) { throw new Error('No regions supplied'); } return this.getRegionFeatureDensityStats(regions[0], opts); } async getSources(regions) { const features = await (0, rxjs_1.firstValueFrom)(this.getFeaturesInMultipleRegions(regions).pipe((0, operators_1.toArray)())); const sources = new Set(); for (const f of features) { sources.add(f.get('source')); } return [...sources].map(source => ({ name: source, })); } } exports.BaseFeatureDataAdapter = BaseFeatureDataAdapter;