From 8c5865ed2e16e7332e2a4600eeee6b98704c8208 Mon Sep 17 00:00:00 2001 From: prabhat Date: Thu, 9 May 2024 09:44:03 +0100 Subject: [PATCH 01/16] response model changes for around aa scores --- src/types/FunctionalResponse.ts | 3 +-- src/types/MappingResponse.ts | 25 +++++++++++++++++++++++-- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/types/FunctionalResponse.ts b/src/types/FunctionalResponse.ts index d4e18528..1471ac19 100644 --- a/src/types/FunctionalResponse.ts +++ b/src/types/FunctionalResponse.ts @@ -17,7 +17,6 @@ export interface FunctionalResponse { pockets: Array foldxs: Array interactions: Array - conservScore: number } export interface GeneName { @@ -81,7 +80,7 @@ export interface Foldx { position: number wildType: string mutatedType: string - foldxDdq: number + foldxDdg: number plddt: number } diff --git a/src/types/MappingResponse.ts b/src/types/MappingResponse.ts index cb6c4607..3f433372 100644 --- a/src/types/MappingResponse.ts +++ b/src/types/MappingResponse.ts @@ -118,8 +118,10 @@ interface IsoFormMapping { // evolutionalInferenceUri: string; // proteinStructure: Array; proteinStructureUri: string; - eveScore: number; - eveClass: number; + conservScore: ConservScore; + amScore: AMScore; + eveScore: EVEScore; + esmScore: ESMScore; } interface Ensp { ensp: string; @@ -139,4 +141,23 @@ export interface ParsedInput{ inputString: string invalidReason: string } + +export interface ConservScore { + score:number +} + +export interface EVEScore { + score:number + eveClass:string +} + +export interface ESMScore { + score:number +} + +export interface AMScore { + amPathogenicity:number + amClass:string +} + export default MappingResponse; \ No newline at end of file From 6ebe33f13911fb2a567670a8b707def9d698f4c8 Mon Sep 17 00:00:00 2001 From: prabhat Date: Thu, 9 May 2024 15:55:59 +0100 Subject: [PATCH 02/16] new tinygradient dep and rearrange deps list --- package.json | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index ff7fdf53..61f6cbc6 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "version": "0.1.0", "private": false, "devDependencies": { + "@babel/plugin-proposal-private-property-in-object": "7.21.11", "@playwright/test": "1.30.0", "@types/file-saver": "2.0.5", "@types/react": "18.2.74", @@ -17,19 +18,19 @@ "file-saver": "^2.0.5", "pdbe-molstar": "3.1.2", "react": "18.2.0", + "react-cookie-consent": "9.0.0", "react-dom": "18.2.0", "react-dropdown-now": "^6.0.1", + "react-markdown": "^8.0.7", "react-router-dom": "6.22.3", "react-scripts": "4.0.3", + "rehype-raw": "6.1.1", + "remark-gfm": "3.0.1", "simple-react-notifications2": "1.2.17", + "tinygradient": "1.1.5", "typescript": "4.9.5", "uuid": "3.4.0", - "web-vitals": "2.1.4", - "react-markdown": "^8.0.7", - "remark-gfm": "3.0.1", - "rehype-raw": "6.1.1", - "react-cookie-consent": "9.0.0", - "@babel/plugin-proposal-private-property-in-object": "7.21.11" + "web-vitals": "2.1.4" }, "scripts": { "start": "react-scripts start", From e2239eb6822c5e103f81380f20e0a8c35e1f267a Mon Sep 17 00:00:00 2001 From: prabhat Date: Sun, 12 May 2024 22:24:17 +0100 Subject: [PATCH 03/16] new css for new scores and predictions display --- src/styles/base/_variables.scss | 2 - src/styles/search/_ImpactSearchResults.scss | 71 ++++++++------------- src/ui/components/search/PrimaryRow.css | 13 ++++ 3 files changed, 38 insertions(+), 48 deletions(-) create mode 100644 src/ui/components/search/PrimaryRow.css diff --git a/src/styles/base/_variables.scss b/src/styles/base/_variables.scss index cf8a318a..6095eb06 100644 --- a/src/styles/base/_variables.scss +++ b/src/styles/base/_variables.scss @@ -44,8 +44,6 @@ $search-results-badge-border-colour: #333; $search-results-badge-colour: #333; $novel-variant-colour: #f00; $non-coding-variant-colour: #999; -$cadd-score-green-background-colour: #6dab49; -$cadd-score-red-background-colour: #da0f21; $significance-data-block-border-colour: #ddd; $publications-label-background-colour: #ffb100; $input-example-border-colour: #ffb100; diff --git a/src/styles/search/_ImpactSearchResults.scss b/src/styles/search/_ImpactSearchResults.scss index 90996958..fe714503 100644 --- a/src/styles/search/_ImpactSearchResults.scss +++ b/src/styles/search/_ImpactSearchResults.scss @@ -73,14 +73,6 @@ border-style: none; height: 100%; } - - .cadd-score { - width: 2rem; - text-align: center; - display: inline-block; - margin-right: 1rem; - margin-bottom: 0.3rem; - } } .img-table { @@ -443,37 +435,6 @@ vertical-align: top; } - .cadd-score { - padding: 0.3rem 0.4rem; - border-radius: 0.75rem; - font-size: 0.8rem; - font-weight: 700; - - &--DarkGreen { - background-color: DarkGreen; - } - - &--DarkSeaGreen { - color: $white-colour; - background-color: DarkSeaGreen; - } - - &--Gold { - color: $white-colour; - background-color:Gold; - } - - &--DarkOrange { - color: $white-colour; - background-color: DarkOrange; - } - - &--FireBrick { - color: $white-colour; - background-color: FireBrick; - } - } - .expanded-row { background-color: #CDD9E4; } @@ -689,16 +650,29 @@ padding-left: 1rem; } - .eve-benign { - color: blue; + .esm1b-score-grad { + background-color: #460556; + background-image: linear-gradient(to right, #460556 , #218c8f, #f9e725); + width: 8rem; + height: 1.5rem; } - - .eve-pathogenic { - color: red; + .score-label { + text-align: justify; + width: 8rem; + height: 1.5rem; + font-size: 0.7em; + } + .score-label:after { + content: ""; + display: inline-block; + width: 100%; } - .eve-uncertain { - color: lightgrey; + .conserv-score-grad { + background-color: #732faf; + background-image: linear-gradient(to right, #732faf, #194888, #277777, #72cb5d, #bab518, #c46307, #9d0101); + width: 8rem; + height: 1.5rem; } } @@ -776,3 +750,8 @@ .pae-desc { padding-left: 20px; } + +.aa-pred{ + display: grid; + grid-template-columns: 35% 20% auto; +} \ No newline at end of file diff --git a/src/ui/components/search/PrimaryRow.css b/src/ui/components/search/PrimaryRow.css new file mode 100644 index 00000000..bd8b3af4 --- /dev/null +++ b/src/ui/components/search/PrimaryRow.css @@ -0,0 +1,13 @@ +.score-box { + width: 2rem; + text-align: center; + display: inline-block; + padding: 0.1rem 0.2rem; + margin-right: 1rem; + margin-bottom: 0.3rem; + border: none; + border-radius: 0.75rem; + font-size: 0.8rem; + font-weight: 700; + color: white; +} \ No newline at end of file From 8facb61446ce297eb548c7bc6e8da9e0af99507b Mon Sep 17 00:00:00 2001 From: prabhat Date: Sun, 12 May 2024 22:27:26 +0100 Subject: [PATCH 04/16] replaced eve with alphamissense pred in main table --- src/ui/components/search/PrimaryRow.tsx | 30 ++++++++++++++++--------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/src/ui/components/search/PrimaryRow.tsx b/src/ui/components/search/PrimaryRow.tsx index e9b8d56b..38427721 100644 --- a/src/ui/components/search/PrimaryRow.tsx +++ b/src/ui/components/search/PrimaryRow.tsx @@ -2,6 +2,8 @@ import { Fragment, lazy, Suspense } from "react"; import { StringVoidFun } from "../../../constants/CommonTypes"; import { CADD_INFO_URL, CLINVAR_RCV_URL, CLINVAR_VCV_URL, COSMIC_URL, + CADD_INFO_URL, AM_INFO_URL, + CLINVAR_RCV_URL, CLINVAR_VCV_URL, COSMIC_URL, DBSNP_URL, ENSEMBL_CHRM_URL, ENSEMBL_GENE_URL, @@ -12,7 +14,8 @@ import { ALLELE, CONSEQUENCES } from "../../../constants/SearchResultTable"; import { MappingRecord } from "../../../utills/Convertor"; import Spaces from "../../elements/Spaces"; import Tool from "../../elements/Tool"; -import { getCaddCss, getTitle } from "./CaddHelper"; +import {caddScoreAttr} from "./CaddScorePred"; +import {amScoreAttr} from "../function/prediction/AlphaMissensePred"; import { getProteinName } from "./ResultTable"; import ProteinIcon from '../../../images/proteins.svg'; import StructureIcon from '../../../images/structures-3d.svg'; @@ -22,7 +25,6 @@ import { ReactComponent as ChevronDownIcon } from "../../../images/chevron-down. import { ReactComponent as ChevronUpIcon } from "../../../images/chevron-up.svg" import { EmptyElement } from "../../../constants/ConstElement"; import { aaChangeTip, CanonicalIcon } from "./AlternateIsoFormRow"; -import {EveIcon, getEveClassText} from "./EveScore"; import {INPUT_GEN, INPUT_PRO, INPUT_ID, INPUT_CDNA} from "../../../types/MappingResponse"; const StructuralDetail = lazy(() => import(/* webpackChunkName: "StructuralDetail" */ "../structure/StructuralDetail")); @@ -31,8 +33,10 @@ const FunctionalDetail = lazy(() => import(/* webpackChunkName: "FunctionalDetai const getPrimaryRow = (record: MappingRecord, toggleOpenGroup: string, isoFormGroupExpanded: string, toggleIsoFormGroup: StringVoidFun, annotationExpanded: string, toggleAnnotation: StringVoidFun, hasAltIsoForm: boolean, currStyle: object) => { - let caddCss = getCaddCss(record.CADD); - let caddTitle = getTitle(record.CADD); + + const caddAttr = caddScoreAttr(record.cadd) + const amAttr = amScoreAttr(record.amScore?.amClass) + let strand = record.strand ? '(-)' : '(+)'; if (!record.codon) { strand = ''; @@ -105,9 +109,9 @@ const getPrimaryRow = (record: MappingRecord, toggleOpenGroup: string, isoFormGr - + - 9 ? 0 : 2} />{isNaN(parseFloat(record.CADD!)) ? "" : parseFloat(record.CADD!).toFixed(1)} + 9 ? 0 : 2} />{isNaN(parseFloat(record.cadd!)) ? "" : parseFloat(record.cadd!).toFixed(1)} @@ -138,12 +142,16 @@ const getPrimaryRow = (record: MappingRecord, toggleOpenGroup: string, isoFormGr {record.aaPos} {record.aaChange} {record.consequences} - - - - + + + + {record.amScore?.amPathogenicity.toString().substring(0,4)} + + + +
- {!record.canonical && <>

} + {!record.canonical && <>

} {getSignificancesButton(functionalKey, 'FUN', record, annotationExpanded, toggleAnnotation)} {getSignificancesButton(populationKey, 'POP', record, annotationExpanded, toggleAnnotation)} {getSignificancesButton(structuralKey, 'STR', record, annotationExpanded, toggleAnnotation)} From d9f5b83cb19f4f9eb1eb49826a7541bcdc2b753f Mon Sep 17 00:00:00 2001 From: prabhat Date: Sun, 12 May 2024 22:28:25 +0100 Subject: [PATCH 05/16] updated main table header --- src/ui/components/search/ResultTable.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ui/components/search/ResultTable.tsx b/src/ui/components/search/ResultTable.tsx index 692ae15e..4286bd62 100644 --- a/src/ui/components/search/ResultTable.tsx +++ b/src/ui/components/search/ResultTable.tsx @@ -48,7 +48,7 @@ function ResultTable(props: ResultTableProps) { Alt. Gene Codon (strand) - CADD + CADD Isoform @@ -56,7 +56,7 @@ function ResultTable(props: ResultTableProps) { AA pos. AA change Consequence(s) - EVE + AlphaMiss. pred. Click for details From 0b67873ffa0536786ba556447edaa4e9ffae386c Mon Sep 17 00:00:00 2001 From: prabhat Date: Sun, 12 May 2024 22:30:36 +0100 Subject: [PATCH 06/16] changed props, and moved all pred components in separate tsx, simplify and cleanup code --- .../components/function/FunctionalDataRow.tsx | 19 +-- .../components/function/FunctionalDetail.tsx | 11 +- .../function/ResidueRegionTable.tsx | 161 +++++++----------- src/ui/components/search/PrimaryRow.tsx | 5 +- 4 files changed, 74 insertions(+), 122 deletions(-) diff --git a/src/ui/components/function/FunctionalDataRow.tsx b/src/ui/components/function/FunctionalDataRow.tsx index 8ef92ef8..bec548b7 100644 --- a/src/ui/components/function/FunctionalDataRow.tsx +++ b/src/ui/components/function/FunctionalDataRow.tsx @@ -3,20 +3,17 @@ import ProteinFunctionTable from './ProteinFunctionTable'; import GeneAndTranslatedSequenceTable from './GeneAndTranslatedSequenceTable'; import ProteinInformationTable from './ProteinInformationTable'; import ResidueRegionTable from './ResidueRegionTable'; -import { TranslatedSequence } from '../../../utills/Convertor'; +import {MappingRecord} from '../../../utills/Convertor'; import ProteinIcon from '../../../images/proteins.svg'; import {FunctionalResponse} from "../../../types/FunctionalResponse"; interface FunctionalDataRowProps { - apiData: FunctionalResponse - refAA: string - variantAA: string - ensg: string - ensp: Array + functionalData: FunctionalResponse + record: MappingRecord } function FunctionalDataRow(props: FunctionalDataRowProps) { - const { refAA, variantAA, ensg, ensp, apiData } = props; + const { functionalData, record } = props; return ( @@ -24,10 +21,10 @@ function FunctionalDataRow(props: FunctionalDataRowProps) {
protein icon Reference Function
- - - - + + + +
diff --git a/src/ui/components/function/FunctionalDetail.tsx b/src/ui/components/function/FunctionalDetail.tsx index 6d4c9786..cebea13c 100644 --- a/src/ui/components/function/FunctionalDetail.tsx +++ b/src/ui/components/function/FunctionalDetail.tsx @@ -2,21 +2,18 @@ import { useState, useEffect } from 'react'; import NoFunctionalDataRow from './NoFunctionalDataRow'; import FunctionalDataRow from './FunctionalDataRow'; import LoaderRow from '../search/LoaderRow'; -import { TranslatedSequence } from '../../../utills/Convertor'; +import {MappingRecord} from '../../../utills/Convertor'; import {getFunctionalData} from "../../../services/ProtVarService"; import {FunctionalResponse} from "../../../types/FunctionalResponse"; interface FunctionalDetailProps { referenceFunctionUri: string - refAA: string - variantAA: string - ensg: string - ensp: Array + record: MappingRecord } function FunctionalDetail(props: FunctionalDetailProps) { - const { referenceFunctionUri } = props; + const { referenceFunctionUri, record } = props; const [apiData, setApiData] = useState() useEffect(() => { getFunctionalData(referenceFunctionUri).then( @@ -28,7 +25,7 @@ function FunctionalDetail(props: FunctionalDetailProps) { if (!apiData) return else if (apiData.id) - return + return else return ; } diff --git a/src/ui/components/function/ResidueRegionTable.tsx b/src/ui/components/function/ResidueRegionTable.tsx index e8d17c96..91d1c023 100644 --- a/src/ui/components/function/ResidueRegionTable.tsx +++ b/src/ui/components/function/ResidueRegionTable.tsx @@ -1,29 +1,32 @@ -import { useState, Fragment } from "react"; -import { EmptyElement } from "../../../constants/ConstElement"; -import { FEATURES } from "../../../constants/Protein"; +import {useState, Fragment} from "react"; +import {EmptyElement} from "../../../constants/ConstElement"; +import {FEATURES} from "../../../constants/Protein"; import AminoAcidModel from "./AminoAcidModel"; import Evidences from "./Evidences"; -import { ReactComponent as ChevronDownIcon } from "../../../images/chevron-down.svg" -import { v1 as uuidv1 } from 'uuid'; -import { StringVoidFun } from "../../../constants/CommonTypes"; +import {ReactComponent as ChevronDownIcon} from "../../../images/chevron-down.svg" +import {v1 as uuidv1} from 'uuid'; +import {StringVoidFun} from "../../../constants/CommonTypes"; import {aminoAcid3to1Letter, formatRange, getKeyValue} from "../../../utills/Util"; import {FunctionalResponse, Pocket, Foldx, P2PInteraction, ProteinFeature} from "../../../types/FunctionalResponse"; +import {MappingRecord} from "../../../utills/Convertor"; +import {Prediction} from "./prediction/Prediction"; interface ResidueRegionTableProps { - apiData: FunctionalResponse - refAA: string - variantAA: string + functionalData: FunctionalResponse + record: MappingRecord } + function ResidueRegionTable(props: ResidueRegionTableProps) { const [expendedRowKey, setExpendedRowKey] = useState('') + function toggleRow(key: string) { setExpendedRowKey(expendedRowKey === key ? '' : key) } var regions: Array = []; var residues: Array = []; - if (props.apiData.features && props.apiData.features.length > 0) { - props.apiData.features.forEach((feature) => { + if (props.functionalData.features && props.functionalData.features.length > 0) { + props.functionalData.features.forEach((feature) => { if (feature.category !== 'VARIANTS') { if (feature.begin === feature.end) residues.push(feature); @@ -31,46 +34,36 @@ function ResidueRegionTable(props: ResidueRegionTableProps) { regions.push(feature); } }); - const oneLetterVariantAA = aminoAcid3to1Letter(props.variantAA); + const oneLetterVariantAA = aminoAcid3to1Letter(props.record.variantAA!); return - - - - - - - - + + + + + + + +
Variant Residue PositionRegion Containing Variant Position
{getResidues(residues, props.apiData.conservScore, props.apiData.foldxs, props.refAA, props.variantAA, oneLetterVariantAA, expendedRowKey, toggleRow)}{getRegions(regions, props.apiData.accession, props.apiData.pockets, props.apiData.interactions, expendedRowKey, toggleRow)}
Variant Residue PositionRegion Containing Variant Position
{getResidues(residues, props.record, props.functionalData.foldxs, oneLetterVariantAA, expendedRowKey, toggleRow)}{getRegions(regions, props.functionalData.accession, props.functionalData.pockets, props.functionalData.interactions, expendedRowKey, toggleRow)}
} return EmptyElement } -function getResidues(regions: Array, conservScore: number, foldxs: Array, refAA: string, variantAA: string, oneLetterVariantAA: string | null, expendedRowKey: string, toggleRow: StringVoidFun) { - let regionsList: Array = []; + +function getResidues(regions: Array, record: MappingRecord, foldxs: Array, oneLetterVariantAA: string | null, expendedRowKey: string, toggleRow: StringVoidFun) { let counter = 0; let foldxs_ = oneLetterVariantAA ? foldxs.filter(foldx => foldx.mutatedType.toLowerCase() === oneLetterVariantAA) : foldxs - - if (regions.length === 0) { - return <> - - Conservation score: {conservScore}
- - ; - } - - regions.forEach((region) => { - counter = counter + 1; - let key = 'residue-' + counter; - var list = getFeatureList(region, key, expendedRowKey, toggleRow); - regionsList.push(list); - }); return <> - - Conservation score: {conservScore}
- {regionsList} - + { + regions.forEach((region) => { + counter = counter + 1; + let key = 'residue-' + counter; + return getFeatureList(region, key, expendedRowKey, toggleRow); + }) + } + + } @@ -80,14 +73,16 @@ function getRegions(regions: Array, accession: string, pockets: if (regions.length === 0) { return (<> -
) } + +function CaddLegend() { + return ( +
+ CADD phred-like score +
+
+ { + Object.values(CADD_SCORE_ATTR).map((sc: PredAttr) => { + return
+ + + +
{sc.title}
+
; + }) + } +
+
+ ); +} + +function ConservLegend() { + return ( +
+ Residue conservation +
+
+
+
+ +
+
Low High
+
+
+
+
+ ); +} + +function EsmLegend() { + return ( +
+ ESM1b LLR score +
+
+
+
+ +
+
0 -5 -10 -15 -20 -25
+
+
+
+
+ ); +} + +function AlphaMissenseLegend() { + return
+ AlphaMissense score +
+
+ { + Object.values(AM_SCORE_ATTR).map((sc: PredAttr) => { + return
+ + + +
{sc.title}
+
; + }) + } +
+
+
; +} + +function EveLegend() { + return ( +
+ EVE score +
+
+ { + Object.values(EVE_SCORE_ATTR).map((sc: PredAttr) => { + return
+ + + +
{sc.title}
+
; + }) + } +
+
+
+ ); +} + export default LegendModal From 278978cc802a6f0e147240e738c0a673bcd0788f Mon Sep 17 00:00:00 2001 From: prabhat Date: Sun, 12 May 2024 22:34:13 +0100 Subject: [PATCH 11/16] new link to alphamissense source --- src/constants/ExternalUrls.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/constants/ExternalUrls.ts b/src/constants/ExternalUrls.ts index 467ad583..f5134cf7 100644 --- a/src/constants/ExternalUrls.ts +++ b/src/constants/ExternalUrls.ts @@ -11,6 +11,7 @@ export const RHEA_URL = "https://www.rhea-db.org/rhea/"; export const INTACT_URL = "https://www.ebi.ac.uk/intact/search?query=" export const UNIPROT_ACCESSION_URL = "https://www.uniprot.org/uniprot/" export const CADD_INFO_URL = "https://cadd.gs.washington.edu/info" +export const AM_INFO_URL = "https://alphamissense.hegelab.org/" export const VCF_FORMAT_INFO_URL = "https://github.com/ebi-uniprot/protvar-be/blob/main/docs/vcf-format.md" export const DBSNP_URL = "https://www.ncbi.nlm.nih.gov/snp/" export const CLINVAR_RCV_URL = "https://www.ncbi.nlm.nih.gov/clinvar/" From 46f901452af55d4ecc735c42b5b6742fd1bf34ac Mon Sep 17 00:00:00 2001 From: prabhat Date: Sun, 12 May 2024 22:34:46 +0100 Subject: [PATCH 12/16] enforced react strict mode --- src/index.tsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/index.tsx b/src/index.tsx index a2a2b7de..3a6886ab 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,18 +1,18 @@ -import * as React from "react"; -import { createRoot } from "react-dom/client"; +import React from "react"; +import ReactDOM from "react-dom/client"; import { BrowserRouter } from "react-router-dom"; import './styles/index.scss'; import reportWebVitals from './reportWebVitals'; import App from './ui/App'; -const container = document.getElementById('root'); -if (!container) throw new Error('Failed to find the root element'); -const root = createRoot(container); +const root = ReactDOM.createRoot(document.getElementById("root") as HTMLElement); root.render( - - - + + + + + ); // If you want to start measuring performance in your app, pass a function From 957c3540bc837564181491a80a5db1528c925559 Mon Sep 17 00:00:00 2001 From: prabhat Date: Sun, 12 May 2024 22:35:57 +0100 Subject: [PATCH 13/16] model changes for scores --- src/utills/Convertor.ts | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/utills/Convertor.ts b/src/utills/Convertor.ts index ce217f11..9b830bea 100644 --- a/src/utills/Convertor.ts +++ b/src/utills/Convertor.ts @@ -6,7 +6,7 @@ import { INPUT_CDNA, UserInput, GenomicInput, - Message, MappingResponse + Message, MappingResponse, EVEScore, ConservScore, ESMScore, AMScore } from "../types/MappingResponse"; export interface MappingRecord { @@ -23,7 +23,7 @@ export interface MappingRecord { geneName?: string codon?: string strand?: boolean - CADD?: string + cadd?: string // PROTEIN column properties canonical?: boolean // display as can (true) or iso (false) isoform?: string @@ -35,8 +35,10 @@ export interface MappingRecord { variantAA?: string cdsPosition?: number // not displayed or used anywhere consequences?: string - eveScore?: string - eveClass?: number + conservScore?: ConservScore + amScore?: AMScore + eveScore?: EVEScore + esmScore?: ESMScore // ANNOTATIONS column referenceFunctionUri?: string populationObservationsUri?: string @@ -169,8 +171,8 @@ function convertGenInputMappings(originalInput: UserInput, genInput: GenomicInpu record.geneName = gene.geneName; record.codon = isoform.refCodon + '/' + isoform.variantCodon; record.strand = gene.reverseStrand; - if (gene.caddScore === null) record.CADD = '-'; - else record.CADD = gene.caddScore.toString(); + if (gene.caddScore === null) record.cadd = '-'; + else record.cadd = gene.caddScore.toString(); } // PROTEIN record.canonical = isoform.canonical; @@ -183,12 +185,10 @@ function convertGenInputMappings(originalInput: UserInput, genInput: GenomicInpu record.variantAA = isoform.variantAA; record.cdsPosition = isoform.cdsPosition; record.consequences = isoform.consequences; - if (isoform.eveScore !== undefined && isoform.eveScore !== null) { - record.eveScore = isoform.eveScore.toString(); - record.eveClass = isoform.eveClass; - } else { - record.eveScore = '-'; - } + record.conservScore = isoform.conservScore; + record.amScore = isoform.amScore; + record.eveScore = isoform.eveScore; + record.esmScore = isoform.esmScore; // ANNOTATIONS record.referenceFunctionUri = isoform.referenceFunctionUri; record.populationObservationsUri = isoform.populationObservationsUri; From e4c9e0865a047a4275c0c7f3059af77fe8ee09f2 Mon Sep 17 00:00:00 2001 From: prabhat Date: Sun, 12 May 2024 22:36:19 +0100 Subject: [PATCH 14/16] add banner text for score changes --- src/ui/layout/DefaultPageLayout.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ui/layout/DefaultPageLayout.tsx b/src/ui/layout/DefaultPageLayout.tsx index 6f523f23..038b4fbd 100644 --- a/src/ui/layout/DefaultPageLayout.tsx +++ b/src/ui/layout/DefaultPageLayout.tsx @@ -16,7 +16,7 @@ interface DefaultPageLayoutProps { searchResults?: MappingRecord[][][] } -const bannerText = null +const bannerText = "AlphaMissense prediction has replaced EVE score in the main table. You can now find EVE score under Predictions in the Functional Annotations section." function DefaultPageLayout(props: DefaultPageLayoutProps) { const [showBanner, setShowBanner ] = useState(bannerText == null ? false : true); From 96ee37606fadc4c06bb22cc4cab19bff5dfbe2c3 Mon Sep 17 00:00:00 2001 From: prabhat Date: Tue, 14 May 2024 20:49:20 +0100 Subject: [PATCH 15/16] std score colors and ref/info changes --- src/styles/search/_ImpactSearchResults.scss | 26 ++++++- src/ui/App.tsx | 14 +++- src/ui/components/common/Common.tsx | 10 +++ .../components/function/FunctionalDataRow.tsx | 2 +- .../function/ResidueRegionTable.tsx | 67 ++++++++----------- .../function/prediction/AlphaMissensePred.tsx | 24 ++++--- .../function/prediction/ConservPred.tsx | 24 ++++--- .../function/prediction/EsmPred.tsx | 53 +++++++++------ .../function/prediction/EvePred.tsx | 27 +++++--- .../function/prediction/FoldxPred.tsx | 28 +++++--- .../function/prediction/PredConstants.ts | 7 ++ .../function/prediction/Prediction.tsx | 24 ++++--- src/ui/components/search/CaddScorePred.ts | 11 +-- src/ui/components/search/PrimaryRow.tsx | 8 +-- src/ui/components/search/ResultTable.tsx | 10 +-- src/ui/layout/DefaultPageLayout.tsx | 2 +- src/ui/modal/LegendModal.tsx | 48 ++++++++----- src/ui/pages/query/QueryPage.tsx | 8 +-- src/ui/pages/search/SearchResultPage.tsx | 3 +- 19 files changed, 244 insertions(+), 152 deletions(-) create mode 100644 src/ui/components/common/Common.tsx create mode 100644 src/ui/components/function/prediction/PredConstants.ts diff --git a/src/styles/search/_ImpactSearchResults.scss b/src/styles/search/_ImpactSearchResults.scss index fe714503..eb99bbf4 100644 --- a/src/styles/search/_ImpactSearchResults.scss +++ b/src/styles/search/_ImpactSearchResults.scss @@ -652,7 +652,13 @@ .esm1b-score-grad { background-color: #460556; - background-image: linear-gradient(to right, #460556 , #218c8f, #f9e725); + background-image: linear-gradient(to right, #460556, #218c8f, #f9e725); + width: 8rem; + height: 1.5rem; + } + .esm1b-score-grad-std { + background-color: red; + background-image: linear-gradient(to right, blue, lightgray, red); width: 8rem; height: 1.5rem; } @@ -754,4 +760,20 @@ .aa-pred{ display: grid; grid-template-columns: 35% 20% auto; -} \ No newline at end of file +} + +.info { + display: inline-block; + padding-left: 4px; + padding-right: 4px; +} +.info::before { + content: 'i'; + font-style: italic; + vertical-align: super; + font-size: smaller; +} +.info:hover { + cursor: help; +} + diff --git a/src/ui/App.tsx b/src/ui/App.tsx index b3fe8fca..69974522 100644 --- a/src/ui/App.tsx +++ b/src/ui/App.tsx @@ -1,4 +1,4 @@ -import {useState} from "react"; +import React, {createContext, useState} from "react"; import {useNavigate, Route, Routes} from "react-router-dom"; import HomePage from "./pages/home/HomePage"; import SearchResultsPage from "./pages/search/SearchResultPage"; @@ -18,13 +18,19 @@ import DownloadPage from "./pages/download/DownloadPage"; import HelpPage from "./pages/help/HelpPage"; import {FormData, initialFormData} from "../types/FormData"; +export const StdColorContext = createContext(true); export default function App() { + const [stdColor, setStdColor] = useState(true); const [loading, setLoading] = useState(false); const [formData, setFormData] = useState(initialFormData); const [page, setPage] = useState(firstPage(0)); const [searchResults, setSearchResults] = useState([]); const navigate = useNavigate(); + const toggleStdColor = () => { + setStdColor(stdColor ? false : true); + }; + // MappingRecord 3d array -> [][][] list of mappings/genes/isoforms // mappings : [ // ... @@ -152,7 +158,7 @@ export default function App() { .finally(() => setLoading(false)); } - return ( + return ( } /> - } /> + } /> } /> } /> } /> @@ -181,5 +188,6 @@ export default function App() { } /> } /> + ); } diff --git a/src/ui/components/common/Common.tsx b/src/ui/components/common/Common.tsx new file mode 100644 index 00000000..480f083e --- /dev/null +++ b/src/ui/components/common/Common.tsx @@ -0,0 +1,10 @@ +export function Info(props: {text?: string}) { + if (props.text === null) + return <> + return
+} + +export const pubmedRef = (id: number) => { + return ref +} \ No newline at end of file diff --git a/src/ui/components/function/FunctionalDataRow.tsx b/src/ui/components/function/FunctionalDataRow.tsx index bec548b7..7a015b5c 100644 --- a/src/ui/components/function/FunctionalDataRow.tsx +++ b/src/ui/components/function/FunctionalDataRow.tsx @@ -20,7 +20,7 @@ function FunctionalDataRow(props: FunctionalDataRowProps) {
-
protein icon Reference Function
+
protein icon Functional information
diff --git a/src/ui/components/function/ResidueRegionTable.tsx b/src/ui/components/function/ResidueRegionTable.tsx index 91d1c023..d3b1873e 100644 --- a/src/ui/components/function/ResidueRegionTable.tsx +++ b/src/ui/components/function/ResidueRegionTable.tsx @@ -9,7 +9,8 @@ import {StringVoidFun} from "../../../constants/CommonTypes"; import {aminoAcid3to1Letter, formatRange, getKeyValue} from "../../../utills/Util"; import {FunctionalResponse, Pocket, Foldx, P2PInteraction, ProteinFeature} from "../../../types/FunctionalResponse"; import {MappingRecord} from "../../../utills/Convertor"; -import {Prediction} from "./prediction/Prediction"; +import {Prediction, PUBMED_ID} from "./prediction/Prediction"; +import {pubmedRef} from "../common/Common"; interface ResidueRegionTableProps { functionalData: FunctionalResponse @@ -42,8 +43,8 @@ function ResidueRegionTable(props: ResidueRegionTableProps) { Region Containing Variant Position - {getResidues(residues, props.record, props.functionalData.foldxs, oneLetterVariantAA, expendedRowKey, toggleRow)} - {getRegions(regions, props.functionalData.accession, props.functionalData.pockets, props.functionalData.interactions, expendedRowKey, toggleRow)} + {getResidues(residues, props.record, props.functionalData.foldxs, oneLetterVariantAA, expendedRowKey, toggleRow)} + {getRegions(regions, props.functionalData.accession, props.functionalData.pockets, props.functionalData.interactions, expendedRowKey, toggleRow)} @@ -52,14 +53,16 @@ function ResidueRegionTable(props: ResidueRegionTableProps) { } function getResidues(regions: Array, record: MappingRecord, foldxs: Array, oneLetterVariantAA: string | null, expendedRowKey: string, toggleRow: StringVoidFun) { - let counter = 0; let foldxs_ = oneLetterVariantAA ? foldxs.filter(foldx => foldx.mutatedType.toLowerCase() === oneLetterVariantAA) : foldxs return <> + Annotations from UniProt + {regions.length === 0 &&
+ No functional data for the variant position +
+ } { - regions.forEach((region) => { - counter = counter + 1; - let key = 'residue-' + counter; - return getFeatureList(region, key, expendedRowKey, toggleRow); + regions.map((region, idx) => { + return getFeatureList(region, `residue-${idx}`, expendedRowKey, toggleRow); }) } @@ -68,40 +71,26 @@ function getResidues(regions: Array, record: MappingRecord, fold } function getRegions(regions: Array, accession: string, pockets: Array, interactions: Array, expendedRowKey: string, toggleRow: StringVoidFun) { - let regionsList: Array = []; - let counter = 0; - - if (regions.length === 0) { - return (<> - -

- Predictions -
(Source: PubMed ID 15980494)
- - - ); - } - regions.forEach((region) => { - counter = counter + 1; - let key = 'region-' + counter; - var list = getFeatureList(region, key, expendedRowKey, toggleRow); - regionsList.push(list); - }); - return <> - Curated observations from UniProt - {regionsList} -

- Predictions -
(Source: PubMed ID 15980494)
+ return (<> + Annotations from UniProt + {regions.length === 0 &&
+ No functional data for the region +
+ } + { + regions.map((region, idx) => { + return getFeatureList(region, `region-${idx}`, expendedRowKey, toggleRow); + }) + } + { + (pockets.length > 0 || interactions.length >0) && <> + Structure predictions{pubmedRef(PUBMED_ID.INTERFACES)} + + } - + ); } function getFeatureList(feature: ProteinFeature, key: string, expendedRowKey: string, toggleRow: StringVoidFun) { diff --git a/src/ui/components/function/prediction/AlphaMissensePred.tsx b/src/ui/components/function/prediction/AlphaMissensePred.tsx index 73af66fb..ff91d93f 100644 --- a/src/ui/components/function/prediction/AlphaMissensePred.tsx +++ b/src/ui/components/function/prediction/AlphaMissensePred.tsx @@ -1,29 +1,31 @@ import {AMScore} from "../../../../types/MappingResponse"; -import {getPredRef, PredAttr, PUBMED_ID} from "./Prediction"; +import {PredAttr, PUBMED_ID} from "./Prediction"; import Spaces from "../../../elements/Spaces"; +import {STD_BENIGN_COLOR, STD_PATHOGENIC_COLOR, STD_UNCERTAIN_COLOR} from "./PredConstants"; +import {pubmedRef} from "../../common/Common"; export const AM_SCORE_ATTR: {[key: string]: PredAttr} = { - PATHOGENIC: { color: '#ed1e24', title: 'pathogenic' }, - AMBIGUOUS: { color: '#a8a9ad', title: 'ambiguous' }, - BENIGN: { color: '#3853a4', title: 'benign' } + BENIGN: { color: '#3853a4', stdColor: STD_BENIGN_COLOR, title: 'benign' }, + AMBIGUOUS: { color: '#a8a9ad', stdColor: STD_UNCERTAIN_COLOR, title: 'ambiguous' }, + PATHOGENIC: { color: '#ed1e24', stdColor: STD_PATHOGENIC_COLOR, title: 'pathogenic' } } -export const AlphaMissensePred = (props: { am?: AMScore }) => { +export const AlphaMissensePred = (props: { am?: AMScore, stdColor: boolean }) => { if (props.am === undefined || props.am === null) { return <> } return
-
AlphaMissense {getPredRef(PUBMED_ID.AM)}
+
AlphaMissense {pubmedRef(PUBMED_ID.AM)}
{props.am.amPathogenicity}
-
+
} -function AlphaMissensePredIcon(props: { amScore?: AMScore }) { - if (props.amScore) { - let cls = props.amScore.amClass as keyof PredAttr +function AlphaMissensePredIcon(props: { am?: AMScore, stdColor: boolean }) { + if (props.am) { + let cls = props.am.amClass as keyof PredAttr return <> - + {AM_SCORE_ATTR[cls].title} } diff --git a/src/ui/components/function/prediction/ConservPred.tsx b/src/ui/components/function/prediction/ConservPred.tsx index afa390fd..da5ad241 100644 --- a/src/ui/components/function/prediction/ConservPred.tsx +++ b/src/ui/components/function/prediction/ConservPred.tsx @@ -1,16 +1,17 @@ import tinygradient from "tinygradient"; import {ConservScore} from "../../../../types/MappingResponse"; -import {getPredRef, PredAttr, PUBMED_ID} from "./Prediction"; +import {PredAttr, PUBMED_ID} from "./Prediction"; import Spaces from "../../../elements/Spaces"; +import {Info, pubmedRef} from "../../common/Common"; export const CONSERV_SCORE_ATTR: PredAttr[] = [ - {color: '#732faf', title: 'very low' }, - {color: '#194888', title: 'low' }, - {color: '#277777', title: 'fairly low' }, - {color: '#72cb5d', title: 'moderate' }, - {color: '#bab518', title: 'fairly high' }, - {color: '#c46307', title: 'high' }, - {color: '#9d0101', title: 'very high' } + {color: '#732faf', stdColor: '', title: 'very low' }, + {color: '#194888', stdColor: '', title: 'low' }, + {color: '#277777', stdColor: '', title: 'fairly low' }, + {color: '#72cb5d', stdColor: '', title: 'moderate' }, + {color: '#bab518', stdColor: '', title: 'fairly high' }, + {color: '#c46307', stdColor: '', title: 'high' }, + {color: '#9d0101', stdColor: '', title: 'very high' } ] export const CONSERV_COLOUR_GRADIENT = tinygradient(CONSERV_SCORE_ATTR.map(s => s.color)); @@ -20,8 +21,10 @@ export const ConservPred = (props: { conserv?: ConservScore }) => { return <> } return
-
Conservation {getPredRef(PUBMED_ID.CONSERV)}
-
{props.conserv.score}
+
Conservation {pubmedRef(PUBMED_ID.CONSERV)}
+
{props.conserv.score} + +
} @@ -33,6 +36,7 @@ function ConservPredIcon(props: { conservScore?: ConservScore }) { return <> {scoreAttr.title} + } return <> diff --git a/src/ui/components/function/prediction/EsmPred.tsx b/src/ui/components/function/prediction/EsmPred.tsx index 3fae303c..3209525b 100644 --- a/src/ui/components/function/prediction/EsmPred.tsx +++ b/src/ui/components/function/prediction/EsmPred.tsx @@ -1,43 +1,56 @@ import tinygradient from "tinygradient"; import {ESMScore} from "../../../../types/MappingResponse"; -import {getPredRef, PredAttr, PUBMED_ID} from "./Prediction"; +import { + PredAttr, + PUBMED_ID +} from "./Prediction"; import Spaces from "../../../elements/Spaces"; +import {STD_BENIGN_COLOR, STD_PATHOGENIC_COLOR, STD_UNCERTAIN_COLOR} from "./PredConstants"; +import {Info, pubmedRef} from "../../common/Common"; -// James: A score of -7.5 appears to be used for pathogenicity in ESM1b. I am not sure we can say that 0--7.5 is benign though. -// Perhaps just leave those blank for now and just label the ones -7.5 and below. +// likely pathogenic (yellow) -25 <------> 0 likely benign (blue) export const ESM_SCORE_ATTR: PredAttr[] = [ - {color: '#460556', title: 'pathogenic' }, - {color: '#218c8f', title: '' }, - {color: '#f9e725', title: '' } // maybe benign + {color: '#460556', stdColor: STD_BENIGN_COLOR , title: 'benign', info: '-5 to 0 likely benign' }, + {color: '#218c8f', stdColor: STD_UNCERTAIN_COLOR, title: 'uncertain', info: '-10 to -5 uncertain significance' }, + {color: '#f9e725', stdColor: STD_PATHOGENIC_COLOR, title: 'pathogenic', info: '-25 to -10 likely pathogenic' } ] export const ESM_MAX_SCORE = -25 -export const ESM_PATHOGENIC_SCORE = -7.5 -export const ESM_COLOUR_GRADIENT = tinygradient(ESM_SCORE_ATTR.map(s => s.color)); - -export const EsmPred = (props: { esm?: ESMScore }) => { +export const EsmPred = (props: { esm?: ESMScore, stdColor: boolean }) => { if (props.esm === undefined || props.esm === null) { return <> } return
-
ESM-1b {getPredRef(PUBMED_ID.ESM)}
+
ESM-1b {pubmedRef(PUBMED_ID.ESM)}
{props.esm.score}
-
+
} -function EsmPredIcon(props: {esmScore?: ESMScore}) { - if (props.esmScore) { - let title = ''; - if (props.esmScore.score < ESM_PATHOGENIC_SCORE) { - title = ESM_SCORE_ATTR[0].title - } - const colorAtPos = ESM_COLOUR_GRADIENT.rgbAt(props.esmScore.score/ ESM_MAX_SCORE).toHexString() +function EsmPredIcon(props: {esm?: ESMScore, stdColor: boolean }) { + if (props.esm) { + const colorGrad = tinygradient(ESM_SCORE_ATTR.map(s => (props.stdColor ? s.stdColor : s.color))); + const colorAtPos = colorGrad.rgbAt(props.esm.score/ ESM_MAX_SCORE).toHexString() + const esmAttr = esmScoreAttr(props.esm.score) return <> - {title} + {esmAttr && <> + {esmAttr.title} + + } } return <> +} + +function esmScoreAttr(score: number) { + if (score >= -5 && score < 0) { + return ESM_SCORE_ATTR[0] + } else if (score >= -10 && score < -5) { + return ESM_SCORE_ATTR[1] + } else if (score >= -25 && score < -10) { + return ESM_SCORE_ATTR[2] + } + return null } \ No newline at end of file diff --git a/src/ui/components/function/prediction/EvePred.tsx b/src/ui/components/function/prediction/EvePred.tsx index 582aff69..48c2b58e 100644 --- a/src/ui/components/function/prediction/EvePred.tsx +++ b/src/ui/components/function/prediction/EvePred.tsx @@ -1,29 +1,34 @@ import {EVEScore} from "../../../../types/MappingResponse"; -import {getPredRef, PredAttr, PUBMED_ID} from "./Prediction"; +import { + PredAttr, + PUBMED_ID +} from "./Prediction"; import Spaces from "../../../elements/Spaces"; +import {STD_BENIGN_COLOR, STD_PATHOGENIC_COLOR, STD_UNCERTAIN_COLOR} from "./PredConstants"; +import {pubmedRef} from "../../common/Common"; export const EVE_SCORE_ATTR: {[key: string]: PredAttr} = { - PATHOGENIC: { color: 'red', title: 'pathogenic' }, - UNCERTAIN: { color: 'lightgrey', title: 'uncertain' }, - BENIGN: { color: 'blue', title: 'benign' } + BENIGN: { color: 'blue', stdColor: STD_BENIGN_COLOR, title: 'benign' }, + UNCERTAIN: { color: 'lightgrey', stdColor: STD_UNCERTAIN_COLOR, title: 'uncertain' }, + PATHOGENIC: { color: 'red', stdColor: STD_PATHOGENIC_COLOR, title: 'pathogenic' } } -export const EvePred = (props: { eve?: EVEScore }) => { +export const EvePred = (props: { eve?: EVEScore, stdColor: boolean }) => { if (props.eve === undefined || props.eve === null) { return <> } return
-
EVE {getPredRef(PUBMED_ID.EVE)}
+
EVE {pubmedRef(PUBMED_ID.EVE)}
{props.eve.score}
-
+
} -function EvePredIcon(props: { eveScore?: EVEScore }) { - if (props.eveScore) { - let cls = props.eveScore.eveClass as keyof PredAttr +function EvePredIcon(props: { eve?: EVEScore, stdColor: boolean }) { + if (props.eve) { + let cls = props.eve.eveClass as keyof PredAttr return <> - + {EVE_SCORE_ATTR[cls].title} } diff --git a/src/ui/components/function/prediction/FoldxPred.tsx b/src/ui/components/function/prediction/FoldxPred.tsx index eb881741..b0bfce09 100644 --- a/src/ui/components/function/prediction/FoldxPred.tsx +++ b/src/ui/components/function/prediction/FoldxPred.tsx @@ -1,21 +1,33 @@ import {Foldx} from "../../../../types/FunctionalResponse"; import Spaces from "../../../elements/Spaces"; -import {getPredRef, PUBMED_ID} from "./Prediction"; +import {PUBMED_ID} from "./Prediction"; +import {Info, pubmedRef} from "../../common/Common"; export const FoldxPred = (props: { foldxs: Array }) => { if (props.foldxs === null || props.foldxs.length === 0) { return <> } return
- Foldx {getPredRef(PUBMED_ID.FOLDX)}
+
Stability change ΔΔG{pubmedRef(PUBMED_ID.FOLDX)}
ΔΔGpred
-
{props.foldxs[0].foldxDdg}
-
-
-
pLDDT
-
{props.foldxs[0].plddt}
+ destabilising variant.">{props.foldxs[0].foldxDdg} + +
+
+} + +function FoldxPredIcon(props: { foldx?: Foldx }) { + if (props.foldx) { + const color = props.foldx.foldxDdg >= 2 ? 'red' : 'blue' + const text = props.foldx.foldxDdg >= 2 ? 'likely to be destabilising' : 'unlikely to be destabilising' + return <> + + {text} + + + } + return <> } \ No newline at end of file diff --git a/src/ui/components/function/prediction/PredConstants.ts b/src/ui/components/function/prediction/PredConstants.ts new file mode 100644 index 00000000..3c3fc63f --- /dev/null +++ b/src/ui/components/function/prediction/PredConstants.ts @@ -0,0 +1,7 @@ +import tinygradient from "tinygradient"; + +export const STD_BENIGN_COLOR: string = 'blue' +export const STD_UNCERTAIN_COLOR: string = 'lightgray' +export const STD_PATHOGENIC_COLOR: string = 'red' + +export const STD_COLOR_GRADIENT = tinygradient(STD_BENIGN_COLOR, STD_UNCERTAIN_COLOR, STD_PATHOGENIC_COLOR); diff --git a/src/ui/components/function/prediction/Prediction.tsx b/src/ui/components/function/prediction/Prediction.tsx index b0eed0c2..bcd75320 100644 --- a/src/ui/components/function/prediction/Prediction.tsx +++ b/src/ui/components/function/prediction/Prediction.tsx @@ -5,31 +5,33 @@ import {EvePred} from "./EvePred"; import {EsmPred} from "./EsmPred"; import {FoldxPred} from "./FoldxPred"; import {Foldx} from "../../../../types/FunctionalResponse"; +import {useContext} from "react"; +import {StdColorContext} from "../../../App"; export type PredAttr = { title: string, color: string, + stdColor: string, + info?: string } export const PUBMED_ID = { - CONSERV: 31606900, + CONSERV: 11093265, AM: 37733863, EVE: 34707284, ESM: 33876751, FOLDX: 15980494, -} - -export const getPredRef = (id: number) => { - return ref + INTERFACES: 36690744 } export const Prediction = (props: { record: MappingRecord, foldxs: Array }) => { - return <> - Predictions
+ const stdColor = useContext(StdColorContext); + return <>
- - - + Structure predictions
+ Pathogenicity predictions
+ + + } \ No newline at end of file diff --git a/src/ui/components/search/CaddScorePred.ts b/src/ui/components/search/CaddScorePred.ts index bca8f90a..c5f8b4bb 100644 --- a/src/ui/components/search/CaddScorePred.ts +++ b/src/ui/components/search/CaddScorePred.ts @@ -1,11 +1,12 @@ import {PredAttr} from "../function/prediction/Prediction"; +import {STD_COLOR_GRADIENT} from "../function/prediction/PredConstants"; export const CADD_SCORE_ATTR: PredAttr[] = [ - {color: 'DarkGreen', title: '<15.0 Likely benign' }, - {color: 'DarkSeaGreen', title: '15.0-19.9 Potentially deleterious' }, - {color: 'Gold', title: '20.0-24.9 Quite likely deleterious' }, - {color: 'DarkOrange', title: '25.0-29.9 Probably deleterious' }, - {color: 'FireBrick', title: '>29.9 Highly likely deleterious' } + {color: 'DarkGreen', stdColor: STD_COLOR_GRADIENT.rgbAt(0).toHexString(), title: '<15.0 Likely benign' }, + {color: 'DarkSeaGreen', stdColor: STD_COLOR_GRADIENT.rgbAt(0.5).toHexString(), title: '15.0-19.9 Potentially deleterious' }, + {color: 'Gold', stdColor: STD_COLOR_GRADIENT.rgbAt(0.65).toHexString(), title: '20.0-24.9 Quite likely deleterious' }, + {color: 'DarkOrange', stdColor: STD_COLOR_GRADIENT.rgbAt(0.8).toHexString(), title: '25.0-29.9 Probably deleterious' }, + {color: 'FireBrick', stdColor: STD_COLOR_GRADIENT.rgbAt(1).toHexString(), title: '>29.9 Highly likely deleterious' } ] export function caddScoreAttr(cadd?: string) { diff --git a/src/ui/components/search/PrimaryRow.tsx b/src/ui/components/search/PrimaryRow.tsx index 55a1ab7a..f63f7074 100644 --- a/src/ui/components/search/PrimaryRow.tsx +++ b/src/ui/components/search/PrimaryRow.tsx @@ -1,5 +1,5 @@ import './PrimaryRow.css'; -import { Fragment, lazy, Suspense } from "react"; +import {Fragment, lazy, Suspense} from "react"; import { StringVoidFun } from "../../../constants/CommonTypes"; import { CADD_INFO_URL, AM_INFO_URL, @@ -32,7 +32,7 @@ const PopulationDetail = lazy(() => import(/* webpackChunkName: "PopulationDetai const FunctionalDetail = lazy(() => import(/* webpackChunkName: "FunctionalDetail" */ "../function/FunctionalDetail")); const getPrimaryRow = (record: MappingRecord, toggleOpenGroup: string, isoFormGroupExpanded: string, toggleIsoFormGroup: StringVoidFun, - annotationExpanded: string, toggleAnnotation: StringVoidFun, hasAltIsoForm: boolean, currStyle: object) => { + annotationExpanded: string, toggleAnnotation: StringVoidFun, hasAltIsoForm: boolean, currStyle: object, stdColor: boolean) => { const caddAttr = caddScoreAttr(record.cadd) const amAttr = amScoreAttr(record.amScore?.amClass) @@ -109,7 +109,7 @@ const getPrimaryRow = (record: MappingRecord, toggleOpenGroup: string, isoFormGr
- + 9 ? 0 : 2} />{isNaN(parseFloat(record.cadd!)) ? "" : parseFloat(record.cadd!).toFixed(1)} @@ -143,7 +143,7 @@ const getPrimaryRow = (record: MappingRecord, toggleOpenGroup: string, isoFormGr {record.aaChange} {record.consequences} - + {record.amScore?.amPathogenicity.toString().substring(0,4)} diff --git a/src/ui/components/search/ResultTable.tsx b/src/ui/components/search/ResultTable.tsx index 4286bd62..278e918f 100644 --- a/src/ui/components/search/ResultTable.tsx +++ b/src/ui/components/search/ResultTable.tsx @@ -1,4 +1,4 @@ -import { useState } from "react" +import {useContext, useState} from "react" import { StringVoidFun } from "../../../constants/CommonTypes"; import { MappingRecord } from "../../../utills/Convertor"; import AlternateIsoFormRow from "./AlternateIsoFormRow"; @@ -6,6 +6,7 @@ import { GENOMIC_COLS, PROTEIN_COLS } from "../../../constants/SearchResultTable import Tool from "../../elements/Tool"; import getPrimaryRow from "./PrimaryRow"; import MsgRow from "./MsgRow"; +import {StdColorContext} from "../../App"; interface ResultTableProps { mappings: Array>> @@ -20,6 +21,7 @@ export function getProteinName(record: MappingRecord) { } function ResultTable(props: ResultTableProps) { + const stdColor = useContext(StdColorContext); const [isoFormGroupExpanded, setIsoFormGroupExpanded] = useState('') const [annotationExpanded, setAnnotationExpanded] = useState('') @@ -31,7 +33,7 @@ function ResultTable(props: ResultTableProps) { setAnnotationExpanded(annotationExpanded === key ? '' : key); } - const tableRows = getTableRows(props.mappings, isoFormGroupExpanded, toggleIsoFormGroup, annotationExpanded, toggleAnnotation); + const tableRows = getTableRows(props.mappings, isoFormGroupExpanded, toggleIsoFormGroup, annotationExpanded, toggleAnnotation, stdColor); return @@ -67,7 +69,7 @@ function ResultTable(props: ResultTableProps) { } const getTableRows = (mappings: MappingRecord[][][], isoFormGroupExpanded: string, toggleIsoFormGroup: StringVoidFun, - annotationExpanded: string, toggleAnnotation: StringVoidFun) => { + annotationExpanded: string, toggleAnnotation: StringVoidFun, stdColor: boolean) => { const tableRows: Array = []; const rowStyle = { a: {backgroundColor: "#F4F3F3" }, b: {backgroundColor: "#FFFFFF" }} let prevInput = "" @@ -91,7 +93,7 @@ const getTableRows = (mappings: MappingRecord[][][], isoFormGroupExpanded: strin } else tableRows.push(getPrimaryRow(isoform, currentGroup, isoFormGroupExpanded, toggleIsoFormGroup, annotationExpanded, - toggleAnnotation, matchingIsoForms.length > 1, currStyle)) + toggleAnnotation, matchingIsoForms.length > 1, currStyle, stdColor)) else if (currentGroup === isoFormGroupExpanded) tableRows.push() } diff --git a/src/ui/layout/DefaultPageLayout.tsx b/src/ui/layout/DefaultPageLayout.tsx index 038b4fbd..784910dd 100644 --- a/src/ui/layout/DefaultPageLayout.tsx +++ b/src/ui/layout/DefaultPageLayout.tsx @@ -16,7 +16,7 @@ interface DefaultPageLayoutProps { searchResults?: MappingRecord[][][] } -const bannerText = "AlphaMissense prediction has replaced EVE score in the main table. You can now find EVE score under Predictions in the Functional Annotations section." +const bannerText = "AlphaMissense prediction has replaced EVE score in the main table. You can now find EVE score under Predictions in the Functional Information section." function DefaultPageLayout(props: DefaultPageLayoutProps) { const [showBanner, setShowBanner ] = useState(bannerText == null ? false : true); diff --git a/src/ui/modal/LegendModal.tsx b/src/ui/modal/LegendModal.tsx index 82cf8510..d6ab8254 100644 --- a/src/ui/modal/LegendModal.tsx +++ b/src/ui/modal/LegendModal.tsx @@ -1,4 +1,5 @@ -import { useState, useCallback, useRef } from 'react' +import {useState, useCallback, useRef, useContext} from 'react' +import { v1 as uuidv1 } from 'uuid'; import Button from '../elements/form/Button' import Modal from './Modal' import useOnClickOutside from '../../hooks/useOnClickOutside' @@ -7,8 +8,10 @@ import {CADD_SCORE_ATTR} from "../components/search/CaddScorePred"; import {PredAttr} from "../components/function/prediction/Prediction"; import {AM_SCORE_ATTR} from "../components/function/prediction/AlphaMissensePred"; import {EVE_SCORE_ATTR} from "../components/function/prediction/EvePred"; +import {StdColorContext} from "../App"; -function LegendModal() { +function LegendModal(props: {toggleStdColor: () => void}) { + const stdColor = useContext(StdColorContext); const [showModel, setShowModel] = useState(false) const downloadModelDiv = useRef(null) @@ -17,6 +20,7 @@ function LegendModal() { useCallback(() => setShowModel(false), []), ) + return (
- +

- +
-
- +
+
+
+ +
) } -function CaddLegend() { +interface CommonLegendProps { + stdColor: boolean +} + +function CaddLegend(props: CommonLegendProps) { return (
CADD phred-like score @@ -68,9 +82,9 @@ function CaddLegend() {
{ Object.values(CADD_SCORE_ATTR).map((sc: PredAttr) => { - return
+ return
- +
{sc.title}
; @@ -99,7 +113,7 @@ function ConservLegend() { ); } -function EsmLegend() { +function EsmLegend(props: CommonLegendProps) { return (
ESM1b LLR score @@ -108,7 +122,7 @@ function EsmLegend() {
-
+
0 -5 -10 -15 -20 -25
@@ -117,16 +131,16 @@ function EsmLegend() { ); } -function AlphaMissenseLegend() { +function AlphaMissenseLegend(props: CommonLegendProps) { return
AlphaMissense score
{ Object.values(AM_SCORE_ATTR).map((sc: PredAttr) => { - return
+ return
- +
{sc.title}
; @@ -137,7 +151,7 @@ function AlphaMissenseLegend() {
; } -function EveLegend() { +function EveLegend(props: CommonLegendProps) { return (
EVE score @@ -145,9 +159,9 @@ function EveLegend() {
{ Object.values(EVE_SCORE_ATTR).map((sc: PredAttr) => { - return
+ return
- +
{sc.title}
; diff --git a/src/ui/pages/query/QueryPage.tsx b/src/ui/pages/query/QueryPage.tsx index bbc7370e..1774f294 100644 --- a/src/ui/pages/query/QueryPage.tsx +++ b/src/ui/pages/query/QueryPage.tsx @@ -157,7 +157,7 @@ function getInputsFromUrl(location: any): any { return [] } -const QueryPageContent = () => { +const QueryPageContent = (props: {toggleStdColor: () => void}) => { const location = useLocation() const [loaded, setLoaded] = useState(false) const [err, setErr] = useState(false) @@ -190,7 +190,7 @@ const QueryPageContent = () => {
- +
@@ -203,8 +203,8 @@ const QueryPageContent = () => { return <>{loaded ? result : (err ? : )} } -function QueryPage() { - return } /> +function QueryPage(props: {toggleStdColor: () => void}) { + return } /> } export default QueryPage diff --git a/src/ui/pages/search/SearchResultPage.tsx b/src/ui/pages/search/SearchResultPage.tsx index 6505eac1..77806188 100644 --- a/src/ui/pages/search/SearchResultPage.tsx +++ b/src/ui/pages/search/SearchResultPage.tsx @@ -16,6 +16,7 @@ interface SearchResultPageProps { fetchNextPage: NextPageFun rows: MappingRecord[][][] loading: boolean + toggleStdColor: () => void } function SearchResultsPageContent(props: SearchResultPageProps) { @@ -34,7 +35,7 @@ function SearchResultsPageContent(props: SearchResultPageProps) {
- +
From 4cb896e5093981c2492343ec444c1239b63252fe Mon Sep 17 00:00:00 2001 From: prabhat Date: Tue, 14 May 2024 20:53:46 +0100 Subject: [PATCH 16/16] use std colour grad const --- src/ui/components/function/prediction/EsmPred.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ui/components/function/prediction/EsmPred.tsx b/src/ui/components/function/prediction/EsmPred.tsx index 3209525b..3678197f 100644 --- a/src/ui/components/function/prediction/EsmPred.tsx +++ b/src/ui/components/function/prediction/EsmPred.tsx @@ -5,7 +5,7 @@ import { PUBMED_ID } from "./Prediction"; import Spaces from "../../../elements/Spaces"; -import {STD_BENIGN_COLOR, STD_PATHOGENIC_COLOR, STD_UNCERTAIN_COLOR} from "./PredConstants"; +import {STD_BENIGN_COLOR, STD_COLOR_GRADIENT, STD_PATHOGENIC_COLOR, STD_UNCERTAIN_COLOR} from "./PredConstants"; import {Info, pubmedRef} from "../../common/Common"; // likely pathogenic (yellow) -25 <------> 0 likely benign (blue) @@ -17,6 +17,8 @@ export const ESM_SCORE_ATTR: PredAttr[] = [ export const ESM_MAX_SCORE = -25 +export const ESM_COLOR_GRADIENT = tinygradient(ESM_SCORE_ATTR.map(s => s.color)); + export const EsmPred = (props: { esm?: ESMScore, stdColor: boolean }) => { if (props.esm === undefined || props.esm === null) { return <> @@ -30,7 +32,7 @@ export const EsmPred = (props: { esm?: ESMScore, stdColor: boolean }) => { function EsmPredIcon(props: {esm?: ESMScore, stdColor: boolean }) { if (props.esm) { - const colorGrad = tinygradient(ESM_SCORE_ATTR.map(s => (props.stdColor ? s.stdColor : s.color))); + const colorGrad = props.stdColor ? STD_COLOR_GRADIENT : ESM_COLOR_GRADIENT; const colorAtPos = colorGrad.rgbAt(props.esm.score/ ESM_MAX_SCORE).toHexString() const esmAttr = esmScoreAttr(props.esm.score) return <>