UNPKG

@jbrowse/plugin-wiggle

Version:

JBrowse 2 wiggle adapters, tracks, etc.

308 lines (307 loc) 11.5 kB
import { lazy } from 'react'; import { ConfigurationReference, getConf, readConfObject, } from '@jbrowse/core/configuration'; import { getEnv, getSession, isSelectionContainer } from '@jbrowse/core/util'; import { stopStopToken } from '@jbrowse/core/util/stopToken'; import { BaseLinearDisplay } from '@jbrowse/plugin-linear-genome-view'; import { types } from 'mobx-state-tree'; import { getNiceDomain } from '../util'; const SetMinMaxDialog = lazy(() => import('./SetMinMaxDialog')); export default function SharedWiggleMixin(configSchema) { return types .compose(BaseLinearDisplay, types.model({ selectedRendering: types.optional(types.string, ''), resolution: types.optional(types.number, 1), fill: types.maybe(types.boolean), minSize: types.maybe(types.number), color: types.maybe(types.string), posColor: types.maybe(types.string), negColor: types.maybe(types.string), summaryScoreMode: types.maybe(types.string), rendererTypeNameState: types.maybe(types.string), scale: types.maybe(types.string), autoscale: types.maybe(types.string), displayCrossHatches: types.maybe(types.boolean), constraints: types.optional(types.model({ max: types.maybe(types.number), min: types.maybe(types.number), }), {}), configuration: ConfigurationReference(configSchema), })) .volatile(() => ({ message: undefined, stats: undefined, statsFetchInProgress: undefined, })) .actions(self => ({ updateQuantitativeStats(stats) { const { currStatsBpPerPx, scoreMin, scoreMax } = stats; const EPSILON = 0.000001; if (!self.stats || Math.abs(self.stats.scoreMax - scoreMax) > EPSILON || Math.abs(self.stats.scoreMin - scoreMin) > EPSILON) { self.stats = { currStatsBpPerPx, scoreMin, scoreMax, }; } }, setColor(color) { self.color = color; }, setPosColor(color) { self.posColor = color; }, setNegColor(color) { self.negColor = color; }, setStatsLoading(arg) { if (self.statsFetchInProgress) { stopStopToken(self.statsFetchInProgress); } self.statsFetchInProgress = arg; }, selectFeature(feature) { const session = getSession(self); if (isSelectionContainer(session)) { session.setSelection(feature); } }, setResolution(res) { self.resolution = res; }, setFill(fill) { if (fill === 0) { self.fill = true; self.minSize = 0; } else if (fill === 1) { self.fill = false; self.minSize = 1; } else if (fill === 2) { self.fill = false; self.minSize = 2; } }, toggleLogScale() { self.scale = self.scale === 'log' ? 'linear' : 'log'; }, setScaleType(scale) { self.scale = scale; }, setSummaryScoreMode(val) { self.summaryScoreMode = val; }, setAutoscale(val) { self.autoscale = val; }, setMaxScore(val) { self.constraints.max = val; }, setRendererType(val) { self.rendererTypeNameState = val; }, setMinScore(val) { self.constraints.min = val; }, toggleCrossHatches() { self.displayCrossHatches = !self.displayCrossHatches; }, setCrossHatches(cross) { self.displayCrossHatches = cross; }, })) .views(self => ({ get adapterTypeName() { return self.adapterConfig.type; }, get rendererTypeNameSimple() { var _a; return ((_a = self.rendererTypeNameState) !== null && _a !== void 0 ? _a : getConf(self, 'defaultRendering')); }, get filters() { return undefined; }, get scaleType() { var _a; return (_a = self.scale) !== null && _a !== void 0 ? _a : getConf(self, 'scaleType'); }, get maxScore() { var _a; return (_a = self.constraints.max) !== null && _a !== void 0 ? _a : getConf(self, 'maxScore'); }, get minScore() { var _a; return (_a = self.constraints.min) !== null && _a !== void 0 ? _a : getConf(self, 'minScore'); }, })) .views(self => ({ get adapterCapabilities() { const type = self.adapterTypeName; const { pluginManager } = getEnv(self); return pluginManager.getAdapterType(type).adapterCapabilities; }, get rendererConfig() { const { color, displayCrossHatches, fill, minSize, negColor, posColor, summaryScoreMode, scaleType, rendererTypeName, } = self; const configBlob = getConf(self, ['renderers', rendererTypeName]) || {}; return self.rendererType.configSchema.create({ ...configBlob, ...(scaleType ? { scaleType } : {}), ...(fill !== undefined ? { filled: fill } : {}), ...(displayCrossHatches !== undefined ? { displayCrossHatches } : {}), ...(summaryScoreMode !== undefined ? { summaryScoreMode } : {}), ...(color !== undefined ? { color } : {}), ...(negColor !== undefined ? { negColor } : {}), ...(posColor !== undefined ? { posColor } : {}), ...(minSize !== undefined ? { minSize } : {}), }, getEnv(self)); }, get autoscaleType() { var _a; return (_a = self.autoscale) !== null && _a !== void 0 ? _a : getConf(self, 'autoscale'); }, })) .views(self => { let oldDomain = [0, 0]; return { get domain() { const { stats, scaleType, minScore, maxScore } = self; if (!stats) { return undefined; } const ret = getNiceDomain({ domain: [stats.scoreMin, stats.scoreMax], bounds: [minScore, maxScore], scaleType, }); if (scaleType === 'log' && ret[1] === Number.MIN_VALUE) { return [0, Number.MIN_VALUE]; } if (JSON.stringify(oldDomain) !== JSON.stringify(ret)) { oldDomain = ret; } return oldDomain; }, }; }) .views(self => ({ get filled() { var _a; return ((_a = self.fill) !== null && _a !== void 0 ? _a : readConfObject(self.rendererConfig, 'filled')); }, get summaryScoreModeSetting() { var _a; return ((_a = self.summaryScoreMode) !== null && _a !== void 0 ? _a : readConfObject(self.rendererConfig, 'summaryScoreMode')); }, get scaleOpts() { return { domain: self.domain, stats: self.stats, autoscaleType: self.autoscaleType, scaleType: self.scaleType, inverted: getConf(self, 'inverted'), }; }, get canHaveFill() { return self.rendererTypeName === 'XYPlotRenderer'; }, get displayCrossHatchesSetting() { var _a; return ((_a = self.displayCrossHatches) !== null && _a !== void 0 ? _a : readConfObject(self.rendererConfig, 'displayCrossHatches')); }, get hasResolution() { return self.adapterCapabilities.includes('hasResolution'); }, get hasGlobalStats() { return self.adapterCapabilities.includes('hasGlobalStats'); }, })) .views(self => ({ scoreTrackMenuItems() { return [ ...(self.hasResolution ? [ { label: 'Resolution', subMenu: [ { label: 'Finer resolution', onClick: () => { self.setResolution(self.resolution * 5); }, }, { label: 'Coarser resolution', onClick: () => { self.setResolution(self.resolution / 5); }, }, ], }, { label: 'Summary score mode', subMenu: ['min', 'max', 'avg', 'whiskers'].map(elt => ({ label: elt, type: 'radio', checked: self.summaryScoreModeSetting === elt, onClick: () => { self.setSummaryScoreMode(elt); }, })), }, ] : []), { label: self.scaleType === 'log' ? 'Set linear scale' : 'Set log scale', onClick: () => { self.toggleLogScale(); }, }, { label: 'Autoscale type', subMenu: [ ['local', 'Local'], ...(self.hasGlobalStats ? [ ['global', 'Global'], ['globalsd', 'Global ± 3σ'], ] : []), ['localsd', 'Local ± 3σ'], ].map(([val, label]) => ({ label, type: 'radio', checked: self.autoscaleType === val, onClick: () => { self.setAutoscale(val); }, })), }, { label: 'Set min/max score', onClick: () => { getSession(self).queueDialog(handleClose => [ SetMinMaxDialog, { model: self, handleClose, }, ]); }, }, ]; }, })) .actions(self => { const { reload: superReload } = self; return { async reload() { self.setError(); superReload(); }, }; }); }