Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Display interpretation instead of ClinVar ID #3566

Merged
merged 1 commit into from
Jan 27, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions end-to-end-test/remote/specs/core/mutationTable.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -168,20 +168,20 @@ describe('Mutation Table', function() {
);
});

it('should show the ClinVar id after adding the ClinVar column', () => {
it('should show the ClinVar interpretation after adding the ClinVar column', () => {
// click on column button
browser.click('button*=Columns');
// scroll down to activated "ClinVar" selection
browser.scroll(1000, 1000);
// click "clinvar"
browser.click('//*[text()="ClinVar ID"]');
browser.click('//*[text()="ClinVar"]');
let res;
browser.waitUntil(
() => {
res = executeInBrowser(
() => $('[data-test="clinvar-data"]').length
);
return res == 25;
return res === 25;
},
60000,
`Failed: There's 25 clinvar rows in table (${res} found)`
Expand Down
56 changes: 0 additions & 56 deletions packages/react-mutation-mapper/src/component/clinvar/ClinVarId.tsx

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
import {
DefaultTooltip,
pluralize,
TruncatedText,
} from 'cbioportal-frontend-commons';
import { getClinVarId } from 'cbioportal-utils';
import { ClinVar, MyVariantInfo } from 'genome-nexus-ts-api-client';
import _ from 'lodash';
import * as React from 'react';

export type ClinVarSummaryProps = {
myVariantInfo?: MyVariantInfo;
};

export enum ClinVarOrigin {
GERMLINE = 'germline',
SOMATIC = 'somatic',
}

export type RcvData = {
origin: string;
evidences: {
clinicalSignificance: string;
count: number;
}[];
};

export type RcvCountMap = {
[origin: string]: { [clinicalSignificance: string]: number };
};

export function getRcvCountMap(clinVar: ClinVar): RcvCountMap {
const filteredRcv = clinVar.rcv.filter(
rcv =>
rcv.origin === ClinVarOrigin.GERMLINE ||
rcv.origin === ClinVarOrigin.SOMATIC
);

// first map by origin, then count evidence number for each origin group
const rcvMap = _.groupBy(filteredRcv, d => d.origin);

return _.mapValues(rcvMap, rcvs =>
_.countBy(rcvs, rcv => rcv.clinicalSignificance)
);
}

export function getRcvData(rcvCountMap: RcvCountMap): RcvData[] {
return _.map(rcvCountMap, (clinicalSignificanceCountMap, origin) => ({
origin,
evidences: _.map(
clinicalSignificanceCountMap,
(count, clinicalSignificance) => ({ clinicalSignificance, count })
),
}));
}

export function formatClinicalSignificanceText(rcvData: RcvData[]) {
return _.uniq(
_.flatten(
rcvData.map(d => d.evidences.map(e => e.clinicalSignificance))
)
).join(', ');
}

export const ClinVarRcvInterpretation = (props: {
rcvData: RcvData[];
className?: string;
}) => {
return (
<div className={props.className}>
{props.rcvData.map(d => (
<div key={d.origin}>
<strong>{`${_.upperFirst(d.origin)}: `}</strong>
{d.evidences
.map(
e =>
`${e.clinicalSignificance} (${
e.count
} ${pluralize('evidence', e.count)})`
)
.join(', ')}
</div>
))}
</div>
);
};

const NoClinVarData = () => {
return (
<DefaultTooltip
placement="topLeft"
overlay={<span>Variant has no ClinVar data.</span>}
>
<span
style={{
height: '100%',
width: '100%',
display: 'block',
overflow: 'hidden',
}}
>
&nbsp;
</span>
</DefaultTooltip>
);
};

const ClinVarSummary = (props: ClinVarSummaryProps) => {
const clinVar = props.myVariantInfo
? props.myVariantInfo.clinVar
: undefined;

if (!clinVar) {
return <NoClinVarData />;
} else {
const clinVarId = getClinVarId(props.myVariantInfo);
const clinVarLink = `https://www.ncbi.nlm.nih.gov/clinvar/variation/${clinVarId}/`;
const rcvData = getRcvData(getRcvCountMap(clinVar));

return (
<TruncatedText
maxLength={30}
text={
rcvData.length > 0
? formatClinicalSignificanceText(rcvData)
: 'Unknown'
}
addTooltip="always"
tooltip={
<div style={{ maxWidth: 300 }}>
<ClinVarRcvInterpretation rcvData={rcvData} />
<div>
(ClinVar ID:{' '}
<a href={clinVarLink} target="_blank">
{clinVarId}
</a>
)
</div>
</div>
}
/>
);
}
};

export default ClinVarSummary;
38 changes: 17 additions & 21 deletions packages/react-mutation-mapper/src/component/column/ClinVar.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import autobind from 'autobind-decorator';
import { getClinVarId } from 'cbioportal-utils';
import { MyVariantInfo } from 'genome-nexus-ts-api-client';
import { observer } from 'mobx-react';
import * as React from 'react';

import { defaultSortMethod } from 'cbioportal-utils';
import ClinVarId from '../clinvar/ClinVarId';
import ClinVarSummary, {
formatClinicalSignificanceText,
getRcvCountMap,
getRcvData,
} from '../clinvar/ClinVarSummary';
import {
MyVariantInfoProps,
renderMyVariantInfoContent,
Expand All @@ -17,28 +18,23 @@ export function download(myVariantInfo?: MyVariantInfo): string {
return value ? value.toString() : '';
}

export function sortValue(myVariantInfo?: MyVariantInfo): number | null {
const id = getClinVarId(myVariantInfo);
export function sortValue(myVariantInfo?: MyVariantInfo): string | null {
alisman marked this conversation as resolved.
Show resolved Hide resolved
const rcvData =
myVariantInfo && myVariantInfo.clinVar
? getRcvData(getRcvCountMap(myVariantInfo.clinVar))
: undefined;

return id ? parseInt(id, 10) : null;
return rcvData ? formatClinicalSignificanceText(rcvData) : null;
}

export function clinVarSortMethod(a: MyVariantInfo, b: MyVariantInfo) {
return defaultSortMethod(sortValue(a), sortValue(b));
}

@observer
export default class ClinVar extends React.Component<MyVariantInfoProps, {}> {
public static defaultProps: Partial<MyVariantInfoProps> = {
className: 'pull-right mr-1',
};
const ClinVar = (props: MyVariantInfoProps) => {
return renderMyVariantInfoContent(props, (myVariantInfo: MyVariantInfo) => (
<ClinVarSummary myVariantInfo={myVariantInfo} />
));
};

public render() {
return renderMyVariantInfoContent(this.props, this.getContent);
}

@autobind
public getContent(myVariantInfo: MyVariantInfo) {
return <ClinVarId myVariantInfo={myVariantInfo} />;
}
}
export default ClinVar;
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export type MyVariantInfoProps = {
indexedVariantAnnotations?: RemoteData<
{ [genomicLocation: string]: VariantAnnotation } | undefined
>;
indexedMyVariantInfoAnnotations: RemoteData<
indexedMyVariantInfoAnnotations?: RemoteData<
{ [genomicLocation: string]: MyVariantInfo } | undefined
>;
className?: string;
Expand All @@ -28,7 +28,7 @@ export function renderMyVariantInfoContent(
) => JSX.Element
) {
let content;
const status = props.indexedMyVariantInfoAnnotations.status;
const status = props.indexedMyVariantInfoAnnotations?.status || 'complete';
const variantAnnotation = props.indexedVariantAnnotations
? getVariantAnnotation(
props.mutation,
Expand All @@ -37,7 +37,7 @@ export function renderMyVariantInfoContent(
: undefined;
const myVariantInfo = getMyVariantInfoAnnotation(
props.mutation,
props.indexedMyVariantInfoAnnotations.result
props.indexedMyVariantInfoAnnotations?.result
);

if (status === 'pending') {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export enum MutationColumn {
HGVSG = 'hgvsg',
HGVSC = 'hgvsc',
GNOMAD = 'gnomad',
CLINVAR = 'clinVarId',
CLINVAR = 'clinVar',
DBSNP = 'dbsnp',
SIGNAL = 'signal',
}
Expand All @@ -48,7 +48,7 @@ export enum MutationColumnName {
HGVSG = 'HGVSg',
HGVSC = 'HGVSc',
GNOMAD = 'gnomAD',
CLINVAR = 'ClinVar ID',
CLINVAR = 'ClinVar',
DBSNP = 'dbSNP',
SIGNAL = 'SIGNAL',
}
Expand Down Expand Up @@ -181,7 +181,7 @@ export const MUTATION_COLUMN_HEADERS = {
[MutationColumn.CLINVAR]: (
<ColumnHeader
headerContent={
<span className="pull-right mr-3">
<span className="pull-left">
{MutationColumnName.CLINVAR}{' '}
<i className="fa fa-info-circle" />
</span>
Expand Down
9 changes: 8 additions & 1 deletion packages/react-mutation-mapper/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,14 @@ export {
download as civicDownload,
sortValue as civicSortValue,
} from './component/civic/Civic';
export { default as ClinVarId } from './component/clinvar/ClinVarId';
export {
default as ClinVarSummary,
ClinVarRcvInterpretation,
getRcvCountMap,
getRcvData,
RcvCountMap,
RcvData,
} from './component/clinvar/ClinVarSummary';
export {
AnnotationProps,
default as Annotation,
Expand Down
Loading