Skip to content

Commit

Permalink
Merge pull request #3558 from broadinstitute/display-color-for-in-silico
Browse files Browse the repository at this point in the history
New in-silico thresholds and colors.
  • Loading branch information
ShifaSZ authored Aug 22, 2023
2 parents 60cc895 + dea5ab2 commit f065c72
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 36 deletions.
53 changes: 31 additions & 22 deletions ui/shared/components/panel/variants/Predictions.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { getGenesById } from 'redux/selectors'
import { PREDICTOR_FIELDS, getVariantMainGeneId } from 'shared/utils/constants'
import { snakecaseToTitlecase } from 'shared/utils/stringUtils'
import { HorizontalSpacer } from '../../Spacers'
import { ButtonLink } from '../../StyledComponents'
import { ButtonLink, ColoredIcon } from '../../StyledComponents'

const PredictionValue = styled.span`
margin-left: 5px;
Expand All @@ -19,8 +19,10 @@ const PredictionValue = styled.span`

const NUM_TO_SHOW_ABOVE_THE_FOLD = 6 // how many predictors to show immediately

const PRED_COLOR_MAP = ['green', 'olive', 'grey', 'yellow', 'red', '#8b0000']

const predictionFieldValue = (
predictions, { field, dangerThreshold, warningThreshold, indicatorMap, infoField, infoTitle },
predictions, { field, thresholds, indicatorMap, infoField, infoTitle },
) => {
let value = predictions[field]
if (value === null || value === undefined) {
Expand All @@ -29,39 +31,47 @@ const predictionFieldValue = (

const infoValue = predictions[infoField]

if (dangerThreshold) {
value = parseFloat(value).toPrecision(2)
let color = 'green'
if (value >= dangerThreshold) {
color = 'red'
} else if (value >= warningThreshold) {
color = 'yellow'
}
return { value, color, infoValue, infoTitle, dangerThreshold, warningThreshold }
if (thresholds) {
value = parseFloat(value).toPrecision(3)
const color = PRED_COLOR_MAP.find(
(clr, i) => (thresholds[i - 1] || thresholds[i]) &&
(thresholds[i - 1] === undefined || value >= thresholds[i - 1]) &&
(thresholds[i] === undefined || value < thresholds[i]),
)
return { value, color, infoValue, infoTitle, thresholds }
}

return indicatorMap[value[0]] || indicatorMap[value]
}

const coloredIcon = color => React.createElement(color.startsWith('#') ? ColoredIcon : Icon, { name: 'circle', size: 'small', color })

const Prediction = (
{ field, fieldTitle, value, color, infoValue, infoTitle, warningThreshold, dangerThreshold, href },
{ field, fieldTitle, value, color, infoValue, infoTitle, thresholds, href },
) => {
const indicator = infoValue ? (
<Popup
header={infoTitle}
content={infoValue}
trigger={<Icon name="question circle" size="small" color={color} />}
/>
) : <Icon name="circle" size="small" color={color} />
) : coloredIcon(color)
const fieldName = fieldTitle || snakecaseToTitlecase(field)
const fieldDisplay = dangerThreshold ? (
const fieldDisplay = thresholds ? (
<Popup
header={`${fieldName} Color Ranges`}
content={
<div>
<div>{`Red > ${dangerThreshold}`}</div>
{warningThreshold < dangerThreshold && <div>{`Yellow > ${warningThreshold}`}</div>}
</div>
PRED_COLOR_MAP.map((c, i) => {
if (thresholds[i] === undefined && thresholds[i - 1] === undefined) {
return null
}
return (
<div key={c}>
{coloredIcon(c)}
{thresholds[i] === undefined ? ` >= ${thresholds[i - 1]}` : ` < ${thresholds[i]}`}
</div>
)
})
}
trigger={<span>{fieldName}</span>}
/>
Expand All @@ -85,8 +95,7 @@ Prediction.propTypes = {
infoTitle: PropTypes.string,
fieldTitle: PropTypes.string,
color: PropTypes.string,
warningThreshold: PropTypes.number,
dangerThreshold: PropTypes.number,
thresholds: PropTypes.arrayOf(PropTypes.number),
href: PropTypes.string,
}

Expand Down Expand Up @@ -116,8 +125,8 @@ class Predictions extends React.PureComponent {
if (gene && gene.primateAi) {
genePredictors.primate_ai = {
field: 'primate_ai',
warningThreshold: gene.primateAi.percentile25,
dangerThreshold: gene.primateAi.percentile75,
thresholds: [undefined, undefined, gene.primateAi.percentile25.toPrecision(3),
gene.primateAi.percentile75.toPrecision(3), undefined],
}
}

Expand Down
32 changes: 18 additions & 14 deletions ui/shared/utils/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -1317,36 +1317,40 @@ export const NO_SV_IN_SILICO_GROUPS = [MISSENSE_IN_SILICO_GROUP, CODING_IN_SILIC
export const SPLICE_AI_FIELD = 'splice_ai'

export const PREDICTOR_FIELDS = [
{ field: 'cadd', group: CODING_IN_SILICO_GROUP, warningThreshold: 10, dangerThreshold: 20, min: 1, max: 99 },
{ field: 'revel', group: MISSENSE_IN_SILICO_GROUP, warningThreshold: 0.5, dangerThreshold: 0.75 },
{ field: 'primate_ai', group: MISSENSE_IN_SILICO_GROUP, warningThreshold: 0.5, dangerThreshold: 0.7 },
{ field: 'mpc', group: MISSENSE_IN_SILICO_GROUP, warningThreshold: 1, dangerThreshold: 2, max: 5 },
{ field: 'cadd', group: CODING_IN_SILICO_GROUP, thresholds: [0.151, 22.8, 25.3, 28.1, undefined], min: 1, max: 99 },
{ field: 'revel', group: MISSENSE_IN_SILICO_GROUP, thresholds: [0.0161, 0.291, 0.644, 0.773, 0.932] },
{ field: 'primate_ai', group: MISSENSE_IN_SILICO_GROUP, thresholds: [undefined, 0.484, 0.79, 0.867, undefined] },
{ field: 'mpc', group: MISSENSE_IN_SILICO_GROUP, thresholds: [undefined, undefined, 1.36, 1.828, undefined], max: 5 },
{
field: SPLICE_AI_FIELD,
group: SPLICING_IN_SILICO_GROUP,
warningThreshold: 0.5,
dangerThreshold: 0.8,
thresholds: [undefined, undefined, 0.5, 0.8, undefined],
infoField: 'splice_ai_consequence',
infoTitle: 'Predicted Consequence',
fieldTitle: 'SpliceAI',
getHref: ({ chrom, pos, ref, alt, genomeVersion }) => (
`https://spliceailookup.broadinstitute.org/#variant=${chrom}-${pos}-${ref}-${alt}&hg=${genomeVersion}&distance=1000&mask=1`
),
},
{ field: 'eigen', group: CODING_IN_SILICO_GROUP, warningThreshold: 1, dangerThreshold: 2, max: 99 },
{ field: 'dann', displayOnly: true, warningThreshold: 0.93, dangerThreshold: 0.96 },
{ field: 'strvctvre', group: SV_IN_SILICO_GROUP, warningThreshold: 0.5, dangerThreshold: 0.75 },
{ field: 'eigen', group: CODING_IN_SILICO_GROUP, thresholds: [undefined, undefined, 1, 2, undefined], max: 99 },
{ field: 'dann', displayOnly: true, thresholds: [undefined, undefined, 0.93, 0.96, undefined] },
{ field: 'strvctvre', group: SV_IN_SILICO_GROUP, thresholds: [undefined, undefined, 0.5, 0.75, undefined] },
{ field: 'polyphen', group: MISSENSE_IN_SILICO_GROUP, indicatorMap: POLYPHEN_MAP },
{ field: 'sift', group: MISSENSE_IN_SILICO_GROUP, indicatorMap: INDICATOR_MAP },
{ field: 'mut_taster', group: MISSENSE_IN_SILICO_GROUP, indicatorMap: MUTTASTER_MAP },
{ field: 'fathmm', group: MISSENSE_IN_SILICO_GROUP, indicatorMap: FATHMM_MAP },
{ field: 'vest', warningThreshold: 0.5, dangerThreshold: 0.764 },
{ field: 'mut_pred', warningThreshold: 0.392, dangerThreshold: 0.737 },
{ field: 'apogee', warningThreshold: 0.5, dangerThreshold: 0.5 },
{ field: 'gnomad_noncoding', fieldTitle: 'gnomAD Constraint', displayOnly: true, warningThreshold: 2.18, dangerThreshold: 4 },
{ field: 'vest', thresholds: [undefined, 0.45, 0.764, 0.861, 0.965] },
{ field: 'mut_pred', thresholds: [0.0101, 0.392, 0.737, 0.829, 0.932] },
{ field: 'apogee', thresholds: [undefined, undefined, 0.5, 0.5, undefined] },
{
field: 'gnomad_noncoding',
fieldTitle: 'gnomAD Constraint',
displayOnly: true,
thresholds: [undefined, undefined, 2.18, 4, undefined],
},
{ field: 'haplogroup_defining', indicatorMap: { Y: { color: 'green', value: '' } } },
{ field: 'mitotip', indicatorMap: MITOTIP_MAP },
{ field: 'hmtvar', warningThreshold: 0.35, dangerThreshold: 0.35 },
{ field: 'hmtvar', thresholds: [undefined, undefined, 0.35, 0.35, undefined] },
]

export const getVariantMainGeneId = ({ transcripts = {}, mainTranscriptId, selectedMainTranscriptId }) => {
Expand Down

0 comments on commit f065c72

Please sign in to comment.