import * as React from 'react'; import _ from 'lodash'; import { observer } from 'mobx-react'; import { action, computed, makeObservable, observable } from 'mobx'; import { Collapse } from 'react-collapse'; import { Column } from 'react-table'; import { DefaultTooltip, EllipsisTextTooltip, } from 'cbioportal-frontend-commons'; import { compareByPtmTypePriority, ptmColor, MobxCache, Mutation, PostTranslationalModification, } from 'cbioportal-utils'; import MutationMapperStore from '../../model/MutationMapperStore'; import PtmAnnotationTable from '../ptm/PtmAnnotationTable'; import { default as Track, TrackProps } from './Track'; import { TrackItemSpec } from './TrackItem'; import styles from './ptmTrackStyles.module.scss'; type PtmTrackProps = TrackProps & { store: MutationMapperStore; pubMedCache?: MobxCache; ensemblTranscriptId?: string; subTrackMargin?: number; dataSource?: string; dataSourceUrl?: string; ptmTooltipColumnOverrides?: { [id: string]: Partial }; collapsed?: boolean; }; export const PtmTooltip: React.FunctionComponent<{ ptms: PostTranslationalModification[]; pubMedCache?: MobxCache; columnOverrides?: { [id: string]: Partial }; }> = props => { return ( ); }; export function ptmInfoTooltip( transcriptId?: string, dataSource?: string, dataSourceUrl?: string ) { let dataSourceDiv = null; if (dataSource) { dataSourceDiv = (
Data Source:{' '} {dataSourceUrl ? ( {dataSource} ) : ( dataSource )}
); } return (

Displays all Post Translational Modifications (PTMs) available {transcriptId && ( for the Ensembl transcript {transcriptId} )} .

PTM types and corresponding color codes are as follows:

  • Phosphorylation
  • Acetylation
  • Ubiquitination
  • Methylation
  • Multiple Type: Sites with more than one PTM type
  • Other: All other PTM types

{dataSourceDiv}
); } function filterPtmsBySource( ptms: PostTranslationalModification[], source?: string ): PostTranslationalModification[] { return source ? ptms.filter(ptm => ptm.source === source) : ptms; } @observer export default class PtmTrack extends React.Component { constructor(props: any) { super(props); makeObservable(this); } public static defaultProps = { subTrackMargin: 25, }; @observable private expanded = !this.props.collapsed; @computed get ptmSpecs(): TrackItemSpec[] { const ptmDataByProteinPosStart = this.props.store .ptmDataByProteinPosStart.result; if (ptmDataByProteinPosStart && !_.isEmpty(ptmDataByProteinPosStart)) { return _.reduce( ptmDataByProteinPosStart, this.ptmDataToTrackItemSpecsReducer, [] ); } else { return []; } } @computed get ptmSubSpecs(): { title: string; specs: TrackItemSpec[] }[] { const ptmDataByTypeAndProteinPosStart = this.props.store .ptmDataByTypeAndProteinPosStart.result; if ( ptmDataByTypeAndProteinPosStart && !_.isEmpty(ptmDataByTypeAndProteinPosStart) ) { return _.keys(ptmDataByTypeAndProteinPosStart) .sort(compareByPtmTypePriority) .map(type => ({ title: type, specs: _.reduce( ptmDataByTypeAndProteinPosStart[type], this.ptmDataToTrackItemSpecsReducer, [] ), })) .filter(s => !_.isEmpty(s.specs)); } else { return []; } } @computed get mainTrackTitle() { return ( {this.expander} ptmInfoTooltip( this.props.ensemblTranscriptId, this.props.dataSource, this.props.dataSourceUrl ) } destroyTooltipOnHide={true} > PTM{' '} {this.props.dataSource ? `(${this.props.dataSource})` : 'Sites'}{' '} ); } @computed get expander(): JSX.Element | null { const className = this.hasSubTracks ? this.mainTrackHidden ? 'fa fa-caret-down' : 'fa fa-caret-right' : null; if (className) { return ( ); } return null; } @computed get subTrackMargin() { return ( this.props.subTrackMargin || PtmTrack.defaultProps.subTrackMargin ); } @computed get subTrackTitleWidth() { return this.props.xOffset ? this.props.xOffset - this.subTrackMargin : 0; } @computed get subTracks() { return this.hasSubTracks ? this.ptmSubSpecs.map((item, index) => ( } width={this.props.width} proteinLength={this.props.proteinLength} trackItems={item.specs} idClassPrefix={`ptm-${index}-`} isSubTrack={true} /> )) : null; } @computed get mainTrackHidden() { return this.expanded && this.hasSubTracks; } @computed get hasSubTracks() { return this.ptmSubSpecs.length > 0; } public render() { return ( {this.subTracks} ); } private ptmDataToTrackItemSpecsReducer = ( acc: TrackItemSpec[], ptmData: PostTranslationalModification[], position: string ): TrackItemSpec[] => { const ptms = Number(position) >= 0 ? filterPtmsBySource(ptmData, this.props.dataSource) : []; if (!_.isEmpty(ptms)) { acc.push({ startCodon: Number(position), color: ptmColor(ptms), tooltip: ( ), }); } return acc; }; @action.bound private handleToggleExpand() { this.expanded = !this.expanded; } }