import * as React from 'react'; import { observer } from 'mobx-react'; import { action, computed, observable, makeObservable } from 'mobx'; import MobxPromise from 'mobxpromise'; import { Nav, NavItem } from 'react-bootstrap'; import { ResultsViewPageStore } from '../ResultsViewPageStore'; import { ResultsViewTab } from '../ResultsViewPageHelpers'; import { CopyNumberSeg, Gene } from 'cbioportal-ts-api-client'; import IntegrativeGenomicsViewer from 'shared/components/igv/IntegrativeGenomicsViewer'; import CNSegmentsDownloader from 'shared/components/cnSegments/CNSegmentsDownloader'; import WindowStore from 'shared/components/window/WindowStore'; import { WHOLE_GENOME, calcIgvTrackHeight, defaultSegmentTrackProps, generateSegmentFeatures, } from 'shared/lib/IGVUtils'; import LoadingIndicator from 'shared/components/loadingIndicator/LoadingIndicator'; import { default as ProgressIndicator, IProgressIndicatorItem, } from 'shared/components/progressIndicator/ProgressIndicator'; import { remoteData } from 'cbioportal-frontend-commons'; import CaseFilterWarning from 'shared/components/banners/CaseFilterWarning'; @observer export default class CNSegments extends React.Component< { store: ResultsViewPageStore; sampleThreshold?: number }, {} > { @observable renderingComplete = false; @observable.ref selectedLocus: string; @observable segmentTrackMaxHeight: number | undefined; public static defaultProps = { sampleThreshold: 20000, }; constructor(props: { store: ResultsViewPageStore }) { super(props); makeObservable(this); this.segmentTrackMaxHeight = WindowStore.size.height * 0.7; } @computed get segmentTrackHeight() { return calcIgvTrackHeight(this.features, this.segmentTrackMaxHeight); } @computed get activeLocus(): string { let locus = this.selectedLocus; if (!locus) { locus = this.props.store.genes.result ? this.props.store.genes.result[0].hugoGeneSymbol : WHOLE_GENOME; } return locus; } @computed get features() { const segments: CopyNumberSeg[] = this.activePromise ? this.activePromise.result || [] : []; return generateSegmentFeatures(segments); } readonly chromosome = remoteData({ await: () => [this.props.store.hugoGeneSymbolToReferenceGene], invoke: () => { return Promise.resolve( this.props.store.hugoGeneSymbolToReferenceGene.result![ this.activeLocus ].chromosome ); }, }); @computed get filename() { return `${this.props.store.downloadFilenamePrefix}segments.seg`; } @computed get isHidden() { return this.isLoading || !this.renderingComplete; } @computed get isSampleCountWithinThreshold() { return ( !this.props.store.filteredSamples.result || !this.props.sampleThreshold || this.props.store.filteredSamples.result.length <= this.props.sampleThreshold ); } @computed get tooManySamplesForWholeGenome() { return ( this.activeLocus === WHOLE_GENOME && !this.isSampleCountWithinThreshold ); } @computed get isLoading() { if (this.tooManySamplesForWholeGenome) { return false; } else { return this.activePromise ? this.activePromise.isPending : true; } } @computed get activePromise() { if (this.activeLocus === WHOLE_GENOME) { return this.props.store.filteredSamples.result && this.isSampleCountWithinThreshold ? this.props.store.cnSegments : undefined; } else if ( this.props.store.cnSegmentsByChromosome.result && this.chromosome ) { return this.props.store.cnSegmentsByChromosome.result[ this.chromosome.result! ]; } else { return undefined; } } @computed get indicatorPromises() { const promises: MobxPromise[] = [ this.props.store.studies, this.props.store.genes, ]; if (this.activeLocus !== WHOLE_GENOME) { promises.push(this.props.store.cnSegmentsByChromosome); } if (this.activePromise) { promises.push(this.activePromise); } return promises; } @computed get progressItems(): IProgressIndicatorItem[] { return [ { label: 'Loading copy number segments data...', promises: this.indicatorPromises, }, { label: 'Rendering', }, ]; } public render() { return (
this.progressItems} show={this.isHidden} sequential={true} />
{this.tooManySamplesForWholeGenome && ( Too many samples ({`>${this.props.sampleThreshold}`}) for the whole genome view. Try to select a different sample list. )}
); } @action.bound private onTabSelect(id: any) { this.selectedLocus = id; } @action.bound private onIgvRenderingStart() { // we would like to keep the loader icon in the rendering state until initial IGV rendering is complete this.renderingComplete = false; } @action.bound private onIgvRenderingComplete() { this.renderingComplete = true; } }