From 0cd2e89f17132628d05a523a4d28211e43e4a439 Mon Sep 17 00:00:00 2001 From: Shifa Zhang Date: Wed, 16 Aug 2023 14:52:40 -0400 Subject: [PATCH 1/7] First draft for the new in-silico thresholds. --- .../components/panel/variants/Predictions.jsx | 43 ++++++------ ui/shared/utils/constants.js | 68 ++++++++++++++----- 2 files changed, 74 insertions(+), 37 deletions(-) diff --git a/ui/shared/components/panel/variants/Predictions.jsx b/ui/shared/components/panel/variants/Predictions.jsx index c4dcd7e5d9..300a1671d9 100644 --- a/ui/shared/components/panel/variants/Predictions.jsx +++ b/ui/shared/components/panel/variants/Predictions.jsx @@ -5,7 +5,7 @@ import { connect } from 'react-redux' import { Icon, Transition, Popup } from 'semantic-ui-react' import { getGenesById } from 'redux/selectors' -import { PREDICTOR_FIELDS, getVariantMainGeneId } from 'shared/utils/constants' +import { PREDICTOR_FIELDS, getPredictColor, getVariantMainGeneId } from 'shared/utils/constants' import { snakecaseToTitlecase } from 'shared/utils/stringUtils' import { HorizontalSpacer } from '../../Spacers' import { ButtonLink } from '../../StyledComponents' @@ -20,7 +20,7 @@ const PredictionValue = styled.span` const NUM_TO_SHOW_ABOVE_THE_FOLD = 6 // how many predictors to show immediately const predictionFieldValue = ( - predictions, { field, dangerThreshold, warningThreshold, indicatorMap, infoField, infoTitle }, + predictions, { field, pathHigher, thresholds, indicatorMap, infoField, infoTitle }, ) => { let value = predictions[field] if (value === null || value === undefined) { @@ -29,22 +29,19 @@ 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 = getPredictColor(value, pathHigher, thresholds) + return { value, color, infoValue, infoTitle, pathHigher, thresholds } } return indicatorMap[value[0]] || indicatorMap[value] } +const PATHOGENIC_COLORS = ['green', 'light green', 'grey', 'yellow', 'red', 'dark red'] + const Prediction = ( - { field, fieldTitle, value, color, infoValue, infoTitle, warningThreshold, dangerThreshold, href }, + { field, fieldTitle, value, color, infoValue, infoTitle, pathHigher, thresholds, href }, ) => { const indicator = infoValue ? ( ) : const fieldName = fieldTitle || snakecaseToTitlecase(field) - const fieldDisplay = dangerThreshold ? ( + const fieldDisplay = thresholds ? ( -
{`Red > ${dangerThreshold}`}
- {warningThreshold < dangerThreshold &&
{`Yellow > ${warningThreshold}`}
} + {thresholds.map((th, i) => { + if (!th) { + return null + } + const t = pathHigher ? th : -1 * th + if (i < 3) { + return
{`${PATHOGENIC_COLORS[i]} ${pathHigher ? '<' : '>'}= ${t}`}
+ } + return
{`${PATHOGENIC_COLORS[i]} ${pathHigher ? '>' : '<'}= ${t}`}
+ }).filter(e => !!e)} } trigger={{fieldName}} @@ -85,8 +90,8 @@ Prediction.propTypes = { infoTitle: PropTypes.string, fieldTitle: PropTypes.string, color: PropTypes.string, - warningThreshold: PropTypes.number, - dangerThreshold: PropTypes.number, + pathHigher: PropTypes.bool, + thresholds: PropTypes.arrayOf(PropTypes.number), href: PropTypes.string, } @@ -116,8 +121,8 @@ class Predictions extends React.PureComponent { if (gene && gene.primateAi) { genePredictors.primate_ai = { field: 'primate_ai', - warningThreshold: gene.primateAi.percentile25, - dangerThreshold: gene.primateAi.percentile75, + pathHigher: gene.primateAi.percentile75 >= gene.primateAi.percentile25, + thresholds: [null, null, gene.primateAi.percentile25, gene.primateAi.percentile75, null], } } diff --git a/ui/shared/utils/constants.js b/ui/shared/utils/constants.js index 709b72b471..644941f16a 100644 --- a/ui/shared/utils/constants.js +++ b/ui/shared/utils/constants.js @@ -1316,16 +1316,37 @@ export const SV_IN_SILICO_GROUP = 'Structural' export const NO_SV_IN_SILICO_GROUPS = [MISSENSE_IN_SILICO_GROUP, CODING_IN_SILICO_GROUP] export const SPLICE_AI_FIELD = 'splice_ai' +const PRED_COLOR_MAP = ['green', '#90ee90', 'grey', 'yellow', 'red', '#8b0000'] + +export const getPredictColor = (value, pathHigher, thresholds) => { + let colorIndex = 0 + const v = pathHigher ? value : -1 * value + if (v <= thresholds[1]) { + if (v > thresholds[0]) { + colorIndex = 1 + } + } else { + colorIndex = 5 + if (v < thresholds[2]) { + colorIndex = 2 + } else if (v < thresholds[3]) { + colorIndex = 3 + } else if (v < thresholds[4]) { + colorIndex = 4 + } + } + return PRED_COLOR_MAP[colorIndex] +} + 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.15, 22.7, 25.3, 28.1, null], min: 1, max: 99 }, + { field: 'revel', group: MISSENSE_IN_SILICO_GROUP, thresholds: [0.016, 0.29, 0.644, 0.773, 0.932] }, + { field: 'primate_ai', group: MISSENSE_IN_SILICO_GROUP, thresholds: [null, 0.483, 0.79, 0.867, null] }, + { field: 'mpc', group: MISSENSE_IN_SILICO_GROUP, thresholds: [null, null, 1.36, 1.828, null], max: 5 }, { field: SPLICE_AI_FIELD, group: SPLICING_IN_SILICO_GROUP, - warningThreshold: 0.5, - dangerThreshold: 0.8, + thresholds: [null, null, 0.5, 0.8, null], infoField: 'splice_ai_consequence', infoTitle: 'Predicted Consequence', fieldTitle: 'SpliceAI', @@ -1333,21 +1354,32 @@ export const PREDICTOR_FIELDS = [ `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: 'polyphen', group: MISSENSE_IN_SILICO_GROUP, indicatorMap: POLYPHEN_MAP }, - { field: 'sift', group: MISSENSE_IN_SILICO_GROUP, indicatorMap: INDICATOR_MAP }, + { field: 'eigen', group: CODING_IN_SILICO_GROUP, thresholds: [null, null, 1, 2, null], max: 99 }, + { field: 'dann', displayOnly: true, thresholds: [null, null, 0.93, 0.96, null] }, + { field: 'strvctvre', group: SV_IN_SILICO_GROUP, thresholds: [null, null, 0.5, 0.75, null] }, + { field: 'polyphen', group: MISSENSE_IN_SILICO_GROUP, thresholds: [null, 0.113, 0.978, 0.999, null], indicatorMap: POLYPHEN_MAP }, + { field: 'sift', group: MISSENSE_IN_SILICO_GROUP, thresholds: [null, 0.08, 0.001, 0, null], 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: 'fathmm', group: MISSENSE_IN_SILICO_GROUP, thresholds: [null, 3.32, -4.14, -5.04, null], indicatorMap: FATHMM_MAP }, + { field: 'vest', thresholds: [null, 0.449, 0.764, 0.861, 0.965] }, + { field: 'mut_pred', thresholds: [0.01, 0.391, 0.737, 0.829, 0.932] }, + { field: 'apogee', thresholds: [null, null, 0.5, 0.5, null] }, + { field: 'gnomad_noncoding', fieldTitle: 'gnomAD Constraint', displayOnly: true, thresholds: [null, null, 2.18, 4, null], warningThreshold: 2.18, dangerThreshold: 4 }, { field: 'haplogroup_defining', indicatorMap: { Y: { color: 'green', value: '' } } }, { field: 'mitotip', indicatorMap: MITOTIP_MAP }, - { field: 'hmtvar', warningThreshold: 0.35, dangerThreshold: 0.35 }, -] + { field: 'hmtvar', thresholds: [null, null, 0.35, 0.35, null] }, +].map(({ thresholds, ...pred }) => { + if (!thresholds) { + return pred + } + const noneNullThresholds = thresholds.filter(t => t) + const pathHigher = noneNullThresholds[1] >= noneNullThresholds[0] + return { + ...pred, + pathHigher, + thresholds: pathHigher ? thresholds : thresholds.map(t => (t === null ? null : -1 * t)), + } +}) export const getVariantMainGeneId = ({ transcripts = {}, mainTranscriptId, selectedMainTranscriptId }) => { if (selectedMainTranscriptId || mainTranscriptId) { From 78fc0b721843909f6776d5c1b56b558d123c3578 Mon Sep 17 00:00:00 2001 From: Shifa Zhang Date: Thu, 17 Aug 2023 16:32:18 -0400 Subject: [PATCH 2/7] Update per review. --- .../components/panel/variants/Predictions.jsx | 69 +++++++++++++------ ui/shared/utils/constants.js | 68 ++++++------------ 2 files changed, 69 insertions(+), 68 deletions(-) diff --git a/ui/shared/components/panel/variants/Predictions.jsx b/ui/shared/components/panel/variants/Predictions.jsx index 300a1671d9..fd60ceefc7 100644 --- a/ui/shared/components/panel/variants/Predictions.jsx +++ b/ui/shared/components/panel/variants/Predictions.jsx @@ -5,10 +5,10 @@ import { connect } from 'react-redux' import { Icon, Transition, Popup } from 'semantic-ui-react' import { getGenesById } from 'redux/selectors' -import { PREDICTOR_FIELDS, getPredictColor, getVariantMainGeneId } from 'shared/utils/constants' +import { PREDICTOR_FIELDS, PRED_COLOR_MAP, 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; @@ -19,8 +19,27 @@ const PredictionValue = styled.span` const NUM_TO_SHOW_ABOVE_THE_FOLD = 6 // how many predictors to show immediately +const comparePathScores = (value, i, thresholds) => { + if (i < 2) { // Benign thresholds + if (i === 0) { + return value <= thresholds[0] + } + return (thresholds[0] === undefined || value > thresholds[0]) && value <= thresholds[1] + } + + if (i === 2) { // Grey area + return (thresholds[1] === undefined || value > thresholds[1]) && value < thresholds[2] + } + + // Pathogenic thresholds + if (i === 5) { + return true + } + return value >= thresholds[i - 1] && (thresholds[i] === undefined || value < thresholds[i]) +} + const predictionFieldValue = ( - predictions, { field, pathHigher, thresholds, indicatorMap, infoField, infoTitle }, + predictions, { field, thresholds, indicatorMap, infoField, infoTitle }, ) => { let value = predictions[field] if (value === null || value === undefined) { @@ -31,17 +50,17 @@ const predictionFieldValue = ( if (thresholds) { value = parseFloat(value).toPrecision(3) - const color = getPredictColor(value, pathHigher, thresholds) - return { value, color, infoValue, infoTitle, pathHigher, thresholds } + const color = PRED_COLOR_MAP.find((clr, i) => comparePathScores(value, i, thresholds)) + return { value, color, infoValue, infoTitle, thresholds } } return indicatorMap[value[0]] || indicatorMap[value] } -const PATHOGENIC_COLORS = ['green', 'light green', 'grey', 'yellow', 'red', 'dark red'] +const coloredIcon = color => const Prediction = ( - { field, fieldTitle, value, color, infoValue, infoTitle, pathHigher, thresholds, href }, + { field, fieldTitle, value, color, infoValue, infoTitle, thresholds, href }, ) => { const indicator = infoValue ? ( } /> - ) : + ) : coloredIcon(color) const fieldName = fieldTitle || snakecaseToTitlecase(field) const fieldDisplay = thresholds ? ( - {thresholds.map((th, i) => { - if (!th) { - return null - } - const t = pathHigher ? th : -1 * th - if (i < 3) { - return
{`${PATHOGENIC_COLORS[i]} ${pathHigher ? '<' : '>'}= ${t}`}
- } - return
{`${PATHOGENIC_COLORS[i]} ${pathHigher ? '>' : '<'}= ${t}`}
- }).filter(e => !!e)} + {[0, 1].map(i => thresholds[i] !== undefined && ( +
+ {coloredIcon(PRED_COLOR_MAP[i])} + {i > 0 && thresholds[i - 1] !== undefined && ` > ${thresholds[i - 1]} and`} + {` <= ${thresholds[i]}`} +
+ ))} +
+ {coloredIcon(PRED_COLOR_MAP[2])} + {thresholds[1] === undefined ? '' : ` > ${thresholds[1]} and`} + {` < ${thresholds[2]}`} +
+ {[2, 3, 4].map(i => thresholds[i] !== undefined && ( +
+ {coloredIcon(PRED_COLOR_MAP[i + 1])} + {` >= ${thresholds[i]}`} + {i < 4 && thresholds[i + 1] !== undefined && ` and < ${thresholds[i + 1]}`} +
+ ))} } trigger={{fieldName}} @@ -90,7 +118,6 @@ Prediction.propTypes = { infoTitle: PropTypes.string, fieldTitle: PropTypes.string, color: PropTypes.string, - pathHigher: PropTypes.bool, thresholds: PropTypes.arrayOf(PropTypes.number), href: PropTypes.string, } @@ -121,8 +148,8 @@ class Predictions extends React.PureComponent { if (gene && gene.primateAi) { genePredictors.primate_ai = { field: 'primate_ai', - pathHigher: gene.primateAi.percentile75 >= gene.primateAi.percentile25, - thresholds: [null, null, gene.primateAi.percentile25, gene.primateAi.percentile75, null], + thresholds: [undefined, undefined, gene.primateAi.percentile25.toPrecision(3), + gene.primateAi.percentile75.toPrecision(3), undefined], } } diff --git a/ui/shared/utils/constants.js b/ui/shared/utils/constants.js index 644941f16a..7b87421bfe 100644 --- a/ui/shared/utils/constants.js +++ b/ui/shared/utils/constants.js @@ -1316,37 +1316,17 @@ export const SV_IN_SILICO_GROUP = 'Structural' export const NO_SV_IN_SILICO_GROUPS = [MISSENSE_IN_SILICO_GROUP, CODING_IN_SILICO_GROUP] export const SPLICE_AI_FIELD = 'splice_ai' -const PRED_COLOR_MAP = ['green', '#90ee90', 'grey', 'yellow', 'red', '#8b0000'] - -export const getPredictColor = (value, pathHigher, thresholds) => { - let colorIndex = 0 - const v = pathHigher ? value : -1 * value - if (v <= thresholds[1]) { - if (v > thresholds[0]) { - colorIndex = 1 - } - } else { - colorIndex = 5 - if (v < thresholds[2]) { - colorIndex = 2 - } else if (v < thresholds[3]) { - colorIndex = 3 - } else if (v < thresholds[4]) { - colorIndex = 4 - } - } - return PRED_COLOR_MAP[colorIndex] -} +export const PRED_COLOR_MAP = ['green', '#90ee90', 'grey', 'yellow', 'red', '#8b0000'] export const PREDICTOR_FIELDS = [ - { field: 'cadd', group: CODING_IN_SILICO_GROUP, thresholds: [0.15, 22.7, 25.3, 28.1, null], min: 1, max: 99 }, + { field: 'cadd', group: CODING_IN_SILICO_GROUP, thresholds: [0.15, 22.7, 25.3, 28.1, undefined], min: 1, max: 99 }, { field: 'revel', group: MISSENSE_IN_SILICO_GROUP, thresholds: [0.016, 0.29, 0.644, 0.773, 0.932] }, - { field: 'primate_ai', group: MISSENSE_IN_SILICO_GROUP, thresholds: [null, 0.483, 0.79, 0.867, null] }, - { field: 'mpc', group: MISSENSE_IN_SILICO_GROUP, thresholds: [null, null, 1.36, 1.828, null], max: 5 }, + { field: 'primate_ai', group: MISSENSE_IN_SILICO_GROUP, thresholds: [undefined, 0.483, 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, - thresholds: [null, null, 0.5, 0.8, null], + thresholds: [undefined, undefined, 0.5, 0.8, undefined], infoField: 'splice_ai_consequence', infoTitle: 'Predicted Consequence', fieldTitle: 'SpliceAI', @@ -1354,32 +1334,26 @@ export const PREDICTOR_FIELDS = [ `https://spliceailookup.broadinstitute.org/#variant=${chrom}-${pos}-${ref}-${alt}&hg=${genomeVersion}&distance=1000&mask=1` ), }, - { field: 'eigen', group: CODING_IN_SILICO_GROUP, thresholds: [null, null, 1, 2, null], max: 99 }, - { field: 'dann', displayOnly: true, thresholds: [null, null, 0.93, 0.96, null] }, - { field: 'strvctvre', group: SV_IN_SILICO_GROUP, thresholds: [null, null, 0.5, 0.75, null] }, - { field: 'polyphen', group: MISSENSE_IN_SILICO_GROUP, thresholds: [null, 0.113, 0.978, 0.999, null], indicatorMap: POLYPHEN_MAP }, - { field: 'sift', group: MISSENSE_IN_SILICO_GROUP, thresholds: [null, 0.08, 0.001, 0, null], indicatorMap: INDICATOR_MAP }, + { 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, thresholds: [null, 3.32, -4.14, -5.04, null], indicatorMap: FATHMM_MAP }, - { field: 'vest', thresholds: [null, 0.449, 0.764, 0.861, 0.965] }, + { field: 'fathmm', group: MISSENSE_IN_SILICO_GROUP, indicatorMap: FATHMM_MAP }, + { field: 'vest', thresholds: [undefined, 0.449, 0.764, 0.861, 0.965] }, { field: 'mut_pred', thresholds: [0.01, 0.391, 0.737, 0.829, 0.932] }, - { field: 'apogee', thresholds: [null, null, 0.5, 0.5, null] }, - { field: 'gnomad_noncoding', fieldTitle: 'gnomAD Constraint', displayOnly: true, thresholds: [null, null, 2.18, 4, null], warningThreshold: 2.18, dangerThreshold: 4 }, + { 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', thresholds: [null, null, 0.35, 0.35, null] }, -].map(({ thresholds, ...pred }) => { - if (!thresholds) { - return pred - } - const noneNullThresholds = thresholds.filter(t => t) - const pathHigher = noneNullThresholds[1] >= noneNullThresholds[0] - return { - ...pred, - pathHigher, - thresholds: pathHigher ? thresholds : thresholds.map(t => (t === null ? null : -1 * t)), - } -}) + { field: 'hmtvar', thresholds: [undefined, undefined, 0.35, 0.35, undefined] }, +] export const getVariantMainGeneId = ({ transcripts = {}, mainTranscriptId, selectedMainTranscriptId }) => { if (selectedMainTranscriptId || mainTranscriptId) { From 0cbc4af350974ba2415636c553d7e3ff8f2f27f3 Mon Sep 17 00:00:00 2001 From: Shifa Zhang Date: Fri, 18 Aug 2023 14:06:24 -0400 Subject: [PATCH 3/7] Update the threshold search and popup info. --- .../components/panel/variants/Predictions.jsx | 58 ++++++------------- ui/shared/utils/constants.js | 12 ++-- 2 files changed, 23 insertions(+), 47 deletions(-) diff --git a/ui/shared/components/panel/variants/Predictions.jsx b/ui/shared/components/panel/variants/Predictions.jsx index fd60ceefc7..b569b56c0a 100644 --- a/ui/shared/components/panel/variants/Predictions.jsx +++ b/ui/shared/components/panel/variants/Predictions.jsx @@ -19,25 +19,6 @@ const PredictionValue = styled.span` const NUM_TO_SHOW_ABOVE_THE_FOLD = 6 // how many predictors to show immediately -const comparePathScores = (value, i, thresholds) => { - if (i < 2) { // Benign thresholds - if (i === 0) { - return value <= thresholds[0] - } - return (thresholds[0] === undefined || value > thresholds[0]) && value <= thresholds[1] - } - - if (i === 2) { // Grey area - return (thresholds[1] === undefined || value > thresholds[1]) && value < thresholds[2] - } - - // Pathogenic thresholds - if (i === 5) { - return true - } - return value >= thresholds[i - 1] && (thresholds[i] === undefined || value < thresholds[i]) -} - const predictionFieldValue = ( predictions, { field, thresholds, indicatorMap, infoField, infoTitle }, ) => { @@ -50,14 +31,19 @@ const predictionFieldValue = ( if (thresholds) { value = parseFloat(value).toPrecision(3) - const color = PRED_COLOR_MAP.find((clr, i) => comparePathScores(value, i, thresholds)) + const color = PRED_COLOR_MAP.find( + (clr, i) => (thresholds[i - 1] || thresholds[i - 1]) && + (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 => +const coloredIcon = color => (color === 'darkred' ? : +) const Prediction = ( { field, fieldTitle, value, color, infoValue, infoTitle, thresholds, href }, @@ -74,27 +60,17 @@ const Prediction = ( - {[0, 1].map(i => thresholds[i] !== undefined && ( -
- {coloredIcon(PRED_COLOR_MAP[i])} - {i > 0 && thresholds[i - 1] !== undefined && ` > ${thresholds[i - 1]} and`} - {` <= ${thresholds[i]}`} -
- ))} -
- {coloredIcon(PRED_COLOR_MAP[2])} - {thresholds[1] === undefined ? '' : ` > ${thresholds[1]} and`} - {` < ${thresholds[2]}`} -
- {[2, 3, 4].map(i => thresholds[i] !== undefined && ( -
- {coloredIcon(PRED_COLOR_MAP[i + 1])} - {` >= ${thresholds[i]}`} - {i < 4 && thresholds[i + 1] !== undefined && ` and < ${thresholds[i + 1]}`} + PRED_COLOR_MAP.map((c, i) => { + if (thresholds[i] === undefined && thresholds[i - 1] === undefined) { + return null + } + return ( +
+ {coloredIcon(c)} + {thresholds[i] === undefined ? ` >= ${thresholds[i - 1]}` : ` < ${thresholds[i]}`}
- ))} -
+ ) + }) } trigger={{fieldName}} /> diff --git a/ui/shared/utils/constants.js b/ui/shared/utils/constants.js index 7b87421bfe..675ea87708 100644 --- a/ui/shared/utils/constants.js +++ b/ui/shared/utils/constants.js @@ -1316,12 +1316,12 @@ export const SV_IN_SILICO_GROUP = 'Structural' export const NO_SV_IN_SILICO_GROUPS = [MISSENSE_IN_SILICO_GROUP, CODING_IN_SILICO_GROUP] export const SPLICE_AI_FIELD = 'splice_ai' -export const PRED_COLOR_MAP = ['green', '#90ee90', 'grey', 'yellow', 'red', '#8b0000'] +export const PRED_COLOR_MAP = ['green', 'olive', 'grey', 'yellow', 'red', 'darkred'] export const PREDICTOR_FIELDS = [ - { field: 'cadd', group: CODING_IN_SILICO_GROUP, thresholds: [0.15, 22.7, 25.3, 28.1, undefined], min: 1, max: 99 }, - { field: 'revel', group: MISSENSE_IN_SILICO_GROUP, thresholds: [0.016, 0.29, 0.644, 0.773, 0.932] }, - { field: 'primate_ai', group: MISSENSE_IN_SILICO_GROUP, thresholds: [undefined, 0.483, 0.79, 0.867, undefined] }, + { 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, @@ -1341,8 +1341,8 @@ export const PREDICTOR_FIELDS = [ { 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', thresholds: [undefined, 0.449, 0.764, 0.861, 0.965] }, - { field: 'mut_pred', thresholds: [0.01, 0.391, 0.737, 0.829, 0.932] }, + { field: 'vest', thresholds: [undefined, 0.450, 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', From 9d755dbb6ef868d8615136402d567cea4b85276b Mon Sep 17 00:00:00 2001 From: Shifa Zhang Date: Mon, 21 Aug 2023 15:35:26 -0400 Subject: [PATCH 4/7] Update per review. --- ui/shared/components/panel/variants/Predictions.jsx | 5 ++--- ui/shared/utils/constants.js | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/ui/shared/components/panel/variants/Predictions.jsx b/ui/shared/components/panel/variants/Predictions.jsx index b569b56c0a..3b80cb6842 100644 --- a/ui/shared/components/panel/variants/Predictions.jsx +++ b/ui/shared/components/panel/variants/Predictions.jsx @@ -32,7 +32,7 @@ const predictionFieldValue = ( if (thresholds) { value = parseFloat(value).toPrecision(3) const color = PRED_COLOR_MAP.find( - (clr, i) => (thresholds[i - 1] || thresholds[i - 1]) && + (clr, i) => (thresholds[i - 1] || thresholds[i]) && (thresholds[i - 1] === undefined || value >= thresholds[i - 1]) && (thresholds[i] === undefined || value < thresholds[i]), ) @@ -42,8 +42,7 @@ const predictionFieldValue = ( return indicatorMap[value[0]] || indicatorMap[value] } -const coloredIcon = color => (color === 'darkred' ? : -) +const coloredIcon = color => React.createElement(color.startsWith('#') ? ColoredIcon : Icon, { name: 'circle', size: 'small', color }) const Prediction = ( { field, fieldTitle, value, color, infoValue, infoTitle, thresholds, href }, diff --git a/ui/shared/utils/constants.js b/ui/shared/utils/constants.js index 675ea87708..1323503fd2 100644 --- a/ui/shared/utils/constants.js +++ b/ui/shared/utils/constants.js @@ -1316,7 +1316,7 @@ export const SV_IN_SILICO_GROUP = 'Structural' export const NO_SV_IN_SILICO_GROUPS = [MISSENSE_IN_SILICO_GROUP, CODING_IN_SILICO_GROUP] export const SPLICE_AI_FIELD = 'splice_ai' -export const PRED_COLOR_MAP = ['green', 'olive', 'grey', 'yellow', 'red', 'darkred'] +export const PRED_COLOR_MAP = ['green', 'olive', 'grey', 'yellow', 'red', '#8b0000'] export const PREDICTOR_FIELDS = [ { field: 'cadd', group: CODING_IN_SILICO_GROUP, thresholds: [0.151, 22.8, 25.3, 28.1, undefined], min: 1, max: 99 }, From 09f7036b7f032492aa8e726bbfc552086040a97e Mon Sep 17 00:00:00 2001 From: Shifa Zhang Date: Tue, 22 Aug 2023 09:27:50 -0400 Subject: [PATCH 5/7] Move color map definition. --- ui/shared/components/panel/variants/Predictions.jsx | 4 +++- ui/shared/utils/constants.js | 2 -- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ui/shared/components/panel/variants/Predictions.jsx b/ui/shared/components/panel/variants/Predictions.jsx index 3b80cb6842..395bb5b0e5 100644 --- a/ui/shared/components/panel/variants/Predictions.jsx +++ b/ui/shared/components/panel/variants/Predictions.jsx @@ -5,7 +5,7 @@ import { connect } from 'react-redux' import { Icon, Transition, Popup } from 'semantic-ui-react' import { getGenesById } from 'redux/selectors' -import { PREDICTOR_FIELDS, PRED_COLOR_MAP, getVariantMainGeneId } from 'shared/utils/constants' +import { PREDICTOR_FIELDS, getVariantMainGeneId } from 'shared/utils/constants' import { snakecaseToTitlecase } from 'shared/utils/stringUtils' import { HorizontalSpacer } from '../../Spacers' import { ButtonLink, ColoredIcon } from '../../StyledComponents' @@ -19,6 +19,8 @@ const PredictionValue = styled.span` const NUM_TO_SHOW_ABOVE_THE_FOLD = 6 // how many predictors to show immediately +export const PRED_COLOR_MAP = ['green', 'olive', 'grey', 'yellow', 'red', '#8b0000'] + const predictionFieldValue = ( predictions, { field, thresholds, indicatorMap, infoField, infoTitle }, ) => { diff --git a/ui/shared/utils/constants.js b/ui/shared/utils/constants.js index 1323503fd2..caf2f5919f 100644 --- a/ui/shared/utils/constants.js +++ b/ui/shared/utils/constants.js @@ -1316,8 +1316,6 @@ export const SV_IN_SILICO_GROUP = 'Structural' export const NO_SV_IN_SILICO_GROUPS = [MISSENSE_IN_SILICO_GROUP, CODING_IN_SILICO_GROUP] export const SPLICE_AI_FIELD = 'splice_ai' -export const PRED_COLOR_MAP = ['green', 'olive', 'grey', 'yellow', 'red', '#8b0000'] - export const PREDICTOR_FIELDS = [ { 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] }, From c6e60a241f6e4442d0fb050e803d9b205bd16eb5 Mon Sep 17 00:00:00 2001 From: Shifa Zhang Date: Tue, 22 Aug 2023 09:47:43 -0400 Subject: [PATCH 6/7] Fix codacy. --- ui/shared/utils/constants.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/shared/utils/constants.js b/ui/shared/utils/constants.js index caf2f5919f..9334446cab 100644 --- a/ui/shared/utils/constants.js +++ b/ui/shared/utils/constants.js @@ -1339,7 +1339,7 @@ export const PREDICTOR_FIELDS = [ { 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', thresholds: [undefined, 0.450, 0.764, 0.861, 0.965] }, + { 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] }, { From dea5ab2da1fff967e089dde0e33827802101c5a3 Mon Sep 17 00:00:00 2001 From: Shifa Zhang Date: Tue, 22 Aug 2023 10:28:08 -0400 Subject: [PATCH 7/7] Remove unnecessary export. --- ui/shared/components/panel/variants/Predictions.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/shared/components/panel/variants/Predictions.jsx b/ui/shared/components/panel/variants/Predictions.jsx index 395bb5b0e5..7899621545 100644 --- a/ui/shared/components/panel/variants/Predictions.jsx +++ b/ui/shared/components/panel/variants/Predictions.jsx @@ -19,7 +19,7 @@ const PredictionValue = styled.span` const NUM_TO_SHOW_ABOVE_THE_FOLD = 6 // how many predictors to show immediately -export const PRED_COLOR_MAP = ['green', 'olive', 'grey', 'yellow', 'red', '#8b0000'] +const PRED_COLOR_MAP = ['green', 'olive', 'grey', 'yellow', 'red', '#8b0000'] const predictionFieldValue = ( predictions, { field, thresholds, indicatorMap, infoField, infoTitle },