UNPKG

@jbrowse/plugin-wiggle

Version:

JBrowse 2 wiggle adapters, tracks, etc.

143 lines (142 loc) 5.34 kB
import { BaseFeatureDataAdapter } from '@jbrowse/core/data_adapters/BaseAdapter'; import { aggregateQuantitativeStats, blankStats, } from '@jbrowse/core/data_adapters/BaseAdapter/stats'; import { SimpleFeature, max, min } from '@jbrowse/core/util'; import { ObservableCreate } from '@jbrowse/core/util/rxjs'; import { merge } from 'rxjs'; import { map } from 'rxjs/operators'; function getFilename(uri) { const filename = uri.slice(uri.lastIndexOf('/') + 1); return filename.slice(0, filename.lastIndexOf('.')); } function getFilenameFromAdapterConfig(config) { try { if (config.type === 'BigWigAdapter' && config.bigWigLocation) { const location = config.bigWigLocation; if ('uri' in location && location.uri) { return getFilename(location.uri); } if ('localPath' in location && location.localPath) { return getFilename(location.localPath); } if ('blob' in location && location.blob) { const blob = location.blob; return blob.name ? getFilename(blob.name) : undefined; } } return undefined; } catch (e) { return undefined; } } export default class MultiWiggleAdapter extends BaseFeatureDataAdapter { static capabilities = [ 'hasResolution', 'hasLocalStats', 'hasGlobalStats', ]; adaptersP; async getAdapters() { if (!this.adaptersP) { this.adaptersP = this.getAdaptersImpl(); } return this.adaptersP; } async getAdaptersImpl() { const getSubAdapter = this.getSubAdapter; if (!getSubAdapter) { throw new Error('no getSubAdapter available'); } let subConfs = this.getConf('subadapters'); if (!subConfs?.length) { const entries = this.getConf('bigWigs'); subConfs = entries.map(entry => ({ type: 'BigWigAdapter', source: getFilename(entry), bigWigLocation: { uri: entry, }, })); } return Promise.all(subConfs.map(async (conf) => { const dataAdapter = (await getSubAdapter(conf)) .dataAdapter; const source = conf.source || conf.name || getFilenameFromAdapterConfig(conf) || dataAdapter.id; return { ...conf, dataAdapter, source, }; })); } async getRefNames(opts) { const adapters = await this.getAdapters(); const allNames = await Promise.all(adapters.map(a => a.dataAdapter.getRefNames(opts))); return [...new Set(allNames.flat())]; } async getGlobalStats(opts) { const adapters = await this.getAdapters(); const stats = (await Promise.all(adapters.map(adp => adp.dataAdapter.getGlobalStats?.(opts)))).filter(f => !!f); return { scoreMin: min(stats.map(s => s.scoreMin)), scoreMax: max(stats.map(s => s.scoreMax)), }; } getFeatures(region, opts = {}) { return ObservableCreate(async (observer) => { let adapters = await this.getAdapters(); if (opts.sources?.length) { const sourceNames = new Set(opts.sources.map(s => s.name)); adapters = adapters.filter(adp => sourceNames.has(adp.source)); } merge(...adapters.map(adp => { const { source, dataAdapter } = adp; return dataAdapter.getFeatures(region, opts).pipe(map(f => { if (f.get('source')) { return f; } const data = f.toJSON(); data.uniqueId = `${source}-${f.id()}`; data.source = source; return new SimpleFeature(data); })); })).subscribe(observer); }, opts.stopToken); } async getRegionQuantitativeStats(region, opts) { const adapters = await this.getAdapters(); const allStats = await Promise.all(adapters.map(async (adp) => { const { dataAdapter } = adp; return dataAdapter.getRegionQuantitativeStats(region, opts); })); return aggregateQuantitativeStats(allStats.filter(Boolean)); } async getMultiRegionFeatureDensityStats(_regions) { return { featureDensity: 0, }; } async getMultiRegionQuantitativeStats(regions = [], opts = {}) { if (!regions.length) { return blankStats(); } const adapters = await this.getAdapters(); const allStats = await Promise.all(adapters.map(async (adp) => { const { dataAdapter } = adp; return dataAdapter.getMultiRegionQuantitativeStats(regions, opts); })); return aggregateQuantitativeStats(allStats.filter(Boolean)); } async getSources(_regions) { const adapters = await this.getAdapters(); return adapters.map(({ type, bigWigLocation, dataAdapter, ...rest }) => { return { ...rest, name: rest.source, }; }); } }