Skip to content

Commit

Permalink
Add last updated time and embolden exact matches in cosmic column in …
Browse files Browse the repository at this point in the history
…mutations table (#5103)

* add update time and bold exact protein change matches in cosmic column
* add portal check conditional for last updated string
* add cosmic count check for last updated text
* add exact protein change count in tooltip

---------

Co-authored-by: Bryan Lai <[email protected]>
  • Loading branch information
gblaih and Bryan Lai authored Feb 28, 2025
1 parent 09f46a0 commit 5fb784d
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 40 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
19 changes: 19 additions & 0 deletions src/pages/resultsView/mutation/ResultsViewMutationMapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ export interface IResultsViewMutationMapperProps extends IMutationMapperProps {
enableCustomDriver: boolean;
}

const COSMIC_COUNTS_PUBLIC = 25876;

@observer
export default class ResultsViewMutationMapper extends MutationMapper<
IResultsViewMutationMapperProps
Expand Down Expand Up @@ -196,6 +198,22 @@ export default class ResultsViewMutationMapper extends MutationMapper<
: 'None';
}

@computed get lastUpdatedCosmicText() {
if (this.props.store.cosmicCountsForUpdateCheck.isComplete) {
const cosmicCountsForUpdateCheck = _.sumBy(
this.props.store.cosmicCountsForUpdateCheck.result,
'count'
);
// if counts are less than or equal to 25876 (the count currently in public portal), this means that cosmic was last updated before 2017
if (cosmicCountsForUpdateCheck <= COSMIC_COUNTS_PUBLIC) {
return 'Last Updated: Before 2017';
} else {
return '';
}
}
return '';
}

protected get mutationTableComponent(): JSX.Element | null {
return (
<ResultsViewMutationTable
Expand Down Expand Up @@ -229,6 +247,7 @@ export default class ResultsViewMutationMapper extends MutationMapper<
this.props.store.indexedMyVariantInfoAnnotations
}
cosmicData={this.props.store.cosmicData.result}
lastUpdatedCosmicText={this.lastUpdatedCosmicText}
oncoKbData={this.props.store.oncoKbData}
usingPublicOncoKbInstance={
getServerConfig().show_oncokb &&
Expand Down
11 changes: 11 additions & 0 deletions src/pages/resultsView/mutation/ResultsViewMutationMapperStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ import _ from 'lodash';
import NumericNamespaceColumnFormatter from 'shared/components/namespaceColumns/NumericNamespaceColumnFormatter';
import CategoricalNamespaceColumnFormatter from 'shared/components/namespaceColumns/CategoricalNamespaceColumnFormatter';
import { createNamespaceColumnName } from 'shared/components/namespaceColumns/namespaceColumnsUtils';
import internalClient from 'shared/api/cbioportalInternalClientInstance';

const COSMIC_COUNTS_KEYWORD_FOR_UPDATE_CHECK = 'KRAS G12 missense';

export default class ResultsViewMutationMapperStore extends MutationMapperStore {
constructor(
Expand Down Expand Up @@ -140,6 +143,14 @@ export default class ResultsViewMutationMapperStore extends MutationMapperStore
invoke: () => fetchCosmicData(this.mutationData),
});

// cosmic counts used to check for last cosmic update (using KRAS G12 missense for most common pancan mutation)
readonly cosmicCountsForUpdateCheck = remoteData({
invoke: async () =>
await internalClient.fetchCosmicCountsUsingPOST({
keywords: [COSMIC_COUNTS_KEYWORD_FOR_UPDATE_CHECK],
}),
});

protected getDownloadDataFetcher(): MutationTableDownloadDataFetcher {
return new MutationTableDownloadDataFetcher(
this.mutationData,
Expand Down
88 changes: 54 additions & 34 deletions src/shared/components/cosmic/CosmicMutationTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
// To avoid duplication, it would be nice here to have an extendable interface for LazyMobXTableProps
export interface ICosmicTableProps {
data: CosmicMutation[];
proteinChange: string;
columns?: Array<Column<CosmicMutation>>;
initialSortColumn?: string;
initialSortDirection?: 'asc' | 'desc';
Expand All @@ -28,36 +29,6 @@ export default class CosmicMutationTable extends React.Component<
> {
public static defaultProps = {
data: [],
columns: [
{
name: 'COSMIC ID',
order: 1.0,
render: (d: CosmicMutation) => (
<span>
<a
href={`http://cancer.sanger.ac.uk/cosmic/mutation/overview?id=${d.cosmicMutationId}`}
target="_blank"
>
{d.cosmicMutationId}
</a>
</span>
),
sortBy: (d: CosmicMutation) => d.cosmicMutationId,
},
{
name: 'Protein Change',
order: 2.0,
render: (d: CosmicMutation) => <span>{d.proteinChange}</span>,
sortBy: (d: CosmicMutation) =>
calcProteinChangeSortValue(d.proteinChange),
},
{
name: 'Occurrence',
order: 3.0,
render: (d: CosmicMutation) => <span>{d.count}</span>,
sortBy: (d: CosmicMutation) => d.count,
},
],
initialSortColumn: 'Occurrence',
initialSortDirection: 'desc',
initialItemsPerPage: 10,
Expand All @@ -68,10 +39,61 @@ export default class CosmicMutationTable extends React.Component<
this.state = {};
}

get columns() {
return (
this.props.columns || [
{
name: 'COSMIC ID',
render: (d: CosmicMutation) =>
d.proteinChange === this.props.proteinChange ? (
<b>
<a
href={`http://cancer.sanger.ac.uk/cosmic/mutation/overview?id=${d.cosmicMutationId}`}
target="_blank"
>
{d.cosmicMutationId}
</a>
</b>
) : (
<span>
<a
href={`http://cancer.sanger.ac.uk/cosmic/mutation/overview?id=${d.cosmicMutationId}`}
target="_blank"
>
{d.cosmicMutationId}
</a>
</span>
),
sortBy: (d: CosmicMutation) => d.cosmicMutationId,
},
{
name: 'Protein Change',
render: (d: CosmicMutation) =>
d.proteinChange === this.props.proteinChange ? (
<b>{d.proteinChange}</b>
) : (
<span>{d.proteinChange}</span>
),
sortBy: (d: CosmicMutation) =>
calcProteinChangeSortValue(d.proteinChange),
},
{
name: 'Occurrence',
render: (d: CosmicMutation) =>
d.proteinChange === this.props.proteinChange ? (
<b>{d.count}</b>
) : (
<span>{d.count}</span>
),
sortBy: (d: CosmicMutation) => d.count,
},
]
);
}

public render() {
const {
data,
columns,
initialSortColumn,
initialSortDirection,
initialItemsPerPage,
Expand All @@ -86,9 +108,7 @@ export default class CosmicMutationTable extends React.Component<
<div className="cbioportal-frontend">
<CosmicTable
data={data}
columns={
columns || CosmicMutationTable.defaultProps.columns
}
columns={this.columns}
initialSortColumn={initialSortColumn}
initialSortDirection={initialSortDirection}
initialItemsPerPage={initialItemsPerPage}
Expand Down
7 changes: 6 additions & 1 deletion src/shared/components/mutationTable/MutationTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ export interface IMutationTableProps {
IMyVariantInfoIndex | undefined
>;
cosmicData?: ICosmicData;
lastUpdatedCosmicText?: string;
oncoKbData?: RemoteData<IOncoKbData | Error | undefined>;
oncoKbDataForCancerType?: RemoteData<IOncoKbData | Error | undefined>;
oncoKbDataForUnknownPrimary?: RemoteData<IOncoKbData | Error | undefined>;
Expand Down Expand Up @@ -924,7 +925,11 @@ export default class MutationTable<
this._columns[MutationTableColumnType.COSMIC] = {
name: MutationTableColumnType.COSMIC,
render: (d: Mutation[]) =>
CosmicColumnFormatter.renderFunction(d, this.props.cosmicData),
CosmicColumnFormatter.renderFunction(
d,
this.props.cosmicData,
this.props.lastUpdatedCosmicText
),
sortBy: (d: Mutation[]) =>
CosmicColumnFormatter.getSortValue(d, this.props.cosmicData),
download: (d: Mutation[]) =>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import * as React from 'react';
import { DefaultTooltip } from 'cbioportal-frontend-commons';
import { getProteinPositionFromProteinChange } from 'cbioportal-utils';
import {
calcProteinChangeSortValue,
getProteinPositionFromProteinChange,
} from 'cbioportal-utils';
import _ from 'lodash';
import { Mutation } from 'cbioportal-ts-api-client';
import { CosmicMutation } from 'cbioportal-ts-api-client';
Expand All @@ -9,6 +12,7 @@ import styles from './cosmic.module.scss';
import { ICosmicData } from 'shared/model/Cosmic';
import generalStyles from './styles.module.scss';
import memoize from 'memoize-weak-decorator';
import { Column } from 'shared/components/lazyMobXTable/LazyMobXTable';

export function placeArrow(tooltipEl: any) {
const arrowEl = tooltipEl.querySelector('.rc-tooltip-arrow');
Expand Down Expand Up @@ -107,13 +111,18 @@ export default class CosmicColumnFormatter {
}
}

public static renderFunction(data: Mutation[], cosmicData?: ICosmicData) {
public static renderFunction(
data: Mutation[],
cosmicData?: ICosmicData,
lastUpdatedCosmicText?: string
) {
const cosmic: CosmicMutation[] | null = CosmicColumnFormatter.getData(
data,
cosmicData
);

let value: number = -1;
let exactProteinChangeValue: number;
let display: string = '';
let overlay: (() => JSX.Element) | null = null;
let content: JSX.Element;
Expand All @@ -128,11 +137,37 @@ export default class CosmicColumnFormatter {
0
);

exactProteinChangeValue = _.reduce(
cosmic,
(sum: number, cosmicMutation: CosmicMutation) => {
if (
cosmicMutation.proteinChange === data[0].proteinChange
) {
return sum + cosmicMutation.count;
} else {
return sum;
}
},
0
);

overlay = () => (
<span className={styles['cosmic-table']}>
<b>{value}</b> occurrences of <b>{cosmic[0].keyword}</b>{' '}
mutations in COSMIC
<CosmicMutationTable data={cosmic} />
There are{' '}
<b>
{exactProteinChangeValue} {data[0].gene.hugoGeneSymbol}{' '}
{data[0].proteinChange}
</b>{' '}
and{' '}
<b>
{value} {cosmic[0].keyword} mutations
</b>{' '}
in <b>COSMIC</b>
<CosmicMutationTable
data={cosmic}
proteinChange={data[0].proteinChange}
/>
<b>{lastUpdatedCosmicText}</b>
</span>
);

Expand Down

0 comments on commit 5fb784d

Please sign in to comment.