@jbrowse/plugin-wiggle
Version:
JBrowse 2 wiggle adapters, tracks, etc.
143 lines (142 loc) • 5.34 kB
JavaScript
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,
};
});
}
}