diff --git a/src/webcomponents/variant/annotation/cellbase-variant-annotation-summary.js b/src/webcomponents/variant/annotation/cellbase-variant-annotation-summary.js index 4e3b9c2d0..7f8ab6303 100644 --- a/src/webcomponents/variant/annotation/cellbase-variant-annotation-summary.js +++ b/src/webcomponents/variant/annotation/cellbase-variant-annotation-summary.js @@ -17,13 +17,12 @@ import {LitElement, html, nothing} from "lit"; import UtilsNew from "../../../core/utils-new.js"; import BioinfoUtils from "../../../core/bioinfo/bioinfo-utils.js"; -import Types from "../../commons/types.js"; export default class CellbaseVariantAnnotationSummary extends LitElement { constructor() { super(); - this._init(); + this.#init(); } createRenderRoot() { @@ -50,27 +49,29 @@ export default class CellbaseVariantAnnotationSummary extends LitElement { }; } - _init() { - this._prefix = UtilsNew.randomString(8); - this.variantAnnotation = {}; + #init() { + this.variantAnnotation = null; + + this._proteinSubScore = null; + this._caddScaled = null; + this._consequenceTypeGene = null; + this._consequenceTypeTranscript = null; + this._consequenceTypeToColor = null; + this._config = this.getDefaultConfig(); } update(changedProperties) { - if (changedProperties.has("variantAnnotation")) { - this.variantAnnotationChanged(); + if (changedProperties.has("consequenceTypes")) { + this.consequenceTypesObserver(); } - if (changedProperties.has("consequenceTypes") || changedProperties.has("proteinSubstitutionScores")) { - this.setColors(); + if (changedProperties.has("variantAnnotation")) { + this.variantAnnotationObserver(); } super.update(changedProperties); } - isTranscriptAvailable(item) { - return item !== ""; - } - - setColors() { + consequenceTypesObserver() { if (this.consequenceTypes) { const consequenceTypeToColor = {}; for (const category of this.consequenceTypes.categories) { @@ -84,253 +85,249 @@ export default class CellbaseVariantAnnotationSummary extends LitElement { } } } - this.consequenceTypeToColor = consequenceTypeToColor; - } - - if (typeof this.proteinSubstitutionScores !== "undefined") { - const pssColor = new Map(); - for (const i in this.proteinSubstitutionScores) { - const obj = this.proteinSubstitutionScores[i]; - Object.keys(obj).forEach(key => { - pssColor.set(key, obj[key]); - }); - } - this.pssColor = pssColor; + this._consequenceTypeToColor = consequenceTypeToColor; } } - variantAnnotationChanged() { - const _this = this; - if (typeof this.variantAnnotation !== "undefined") { - if (UtilsNew.isEmpty(_this.variantAnnotation.reference)) { - _this.variantAnnotation.reference = "-"; - } - - if (UtilsNew.isEmpty(_this.variantAnnotation.alternate)) { - _this.variantAnnotation.alternate = "-"; + variantAnnotationObserver() { + if (this.variantAnnotation) { + if (!this.variantAnnotation.reference) { + this.variantAnnotation.reference = "-"; } - // Consequence type - // Color the consequence type - if (typeof _this.consequenceTypeToColor !== "undefined" && typeof _this.consequenceTypeToColor[_this.variantAnnotation.displayConsequenceType] !== "undefined") { - $("#" + _this._prefix + "CT").css("color", _this.consequenceTypeToColor[_this.variantAnnotation.displayConsequenceType]); + if (!this.variantAnnotation.alternate) { + this.variantAnnotation.alternate = "-"; } // Find the gene and transcript that exhibit the display consequence type - if (typeof _this.variantAnnotation.consequenceTypes !== "undefined") { - for (let i = 0; i < _this.variantAnnotation.consequenceTypes.length; i++) { - for (let j = 0; j < _this.variantAnnotation.consequenceTypes[i].sequenceOntologyTerms.length; j++) { - if (_this.variantAnnotation.displayConsequenceType === _this.variantAnnotation.consequenceTypes[i].sequenceOntologyTerms[j].name) { - _this.ctGene = _this.variantAnnotation.consequenceTypes[i].geneName; - _this.ctTranscript = _this.variantAnnotation.consequenceTypes[i].transcriptId; + this._consequenceTypeGene = null; + this._consequenceTypeTranscript = null; + if (typeof this.variantAnnotation.consequenceTypes !== "undefined") { + for (let i = 0; i < this.variantAnnotation.consequenceTypes.length; i++) { + for (let j = 0; j < this.variantAnnotation.consequenceTypes[i].sequenceOntologyTerms.length; j++) { + if (this.variantAnnotation.displayConsequenceType === this.variantAnnotation.consequenceTypes[i].sequenceOntologyTerms[j].name) { + this._consequenceTypeGene = this.variantAnnotation.consequenceTypes[i].geneName; + this._consequenceTypeTranscript = this.variantAnnotation.consequenceTypes[i].transcriptId; break; } } } } - // PSS + // Protein substitution scores const proteinSubScore = {}; - // debugger - if (typeof _this.variantAnnotation.consequenceTypes !== "undefined") { + + if (typeof this.variantAnnotation.consequenceTypes !== "undefined") { let min = 10; let max = 0; - for (let i = 0; i < _this.variantAnnotation.consequenceTypes.length; i++) { - if (typeof _this.variantAnnotation.consequenceTypes[i].proteinVariantAnnotation !== "undefined") { - const gene = _this.variantAnnotation.consequenceTypes[i].geneName; - const transcript = _this.variantAnnotation.consequenceTypes[i].ensemblTranscriptId; - const scores = _this.variantAnnotation.consequenceTypes[i].proteinVariantAnnotation.substitutionScores; + for (let i = 0; i < this.variantAnnotation.consequenceTypes.length; i++) { + if (typeof this.variantAnnotation.consequenceTypes[i].proteinVariantAnnotation !== "undefined") { + const gene = this.variantAnnotation.consequenceTypes[i].geneName; + const transcript = this.variantAnnotation.consequenceTypes[i].ensemblTranscriptId; + const scores = this.variantAnnotation.consequenceTypes[i].proteinVariantAnnotation.substitutionScores; if (typeof scores !== "undefined") { for (let j = 0; j < scores.length; j++) { if (scores[j].source === "sift" && scores[j].score <= min) { min = scores[j].score; - proteinSubScore.sift = {score: scores[j].score, description: scores[j].description, gene: gene, transcript: transcript}; - // if (typeof _this.pssColor !== "undefined" && typeof _this.pssColor.get(scores[j].description) !== "undefined") { - // $("#" + _this._prefix + "Sift").css("color", _this.pssColor.get(scores[j].description)); - // } + proteinSubScore.sift = { + score: scores[j].score, + description: scores[j].description, + gene: gene, + transcript: transcript, + }; } else if (scores[j].source === "polyphen" && scores[j].score >= max) { max = scores[j].score; - proteinSubScore.polyphen = {score: scores[j].score, description: scores[j].description, gene: gene, transcript: transcript}; - // if (typeof _this.pssColor !== "undefined" && typeof _this.pssColor.get(scores[j].description) !== "undefined") { - // $("#" + _this._prefix + "Polyphen").css("color", _this.pssColor.get(scores[j].description)); - // } + proteinSubScore.polyphen = { + score: scores[j].score, + description: scores[j].description, + gene: gene, + transcript: transcript, + }; } } } } } } - if (Object.keys(proteinSubScore).length === 0 && proteinSubScore.constructor === Object) { + + // Check if SIFT score is not defined + if (typeof proteinSubScore.sift === "undefined") { proteinSubScore.sift = {score: "NA", description: "NA", transcript: ""}; + } + // Check if Polyphen score is not defined + if (typeof proteinSubScore.polyphen === "undefined") { proteinSubScore.polyphen = {score: "NA", description: "NA", transcript: ""}; - $("#" + _this._prefix + "Sift").css("color", "black"); - $("#" + _this._prefix + "Polyphen").css("color", "black"); } - _this.proteinSubScore = proteinSubScore; - // debugger + + // Save the protein substitution scores + this._proteinSubScore = proteinSubScore; + // CADD - if (typeof _this.variantAnnotation.functionalScore !== "undefined") { - for (const i in _this.variantAnnotation.functionalScore) { - const value = Number(_this.variantAnnotation.functionalScore[i].score).toFixed(2); - if (_this.variantAnnotation.functionalScore[i].source === "cadd_scaled") { - if (value > 15) { - $("#" + _this._prefix + "Cadd").css("color", "red"); - _this.caddScaled = value; - } else { - $("#" + _this._prefix + "Cadd").css("color", "black"); - _this.caddScaled = value; - } - } + this._caddScaled = "NA"; // default value + (this.variantAnnotation.functionalScore || []).forEach(functionalScore => { + if (functionalScore?.source === "cadd_scaled") { + this._caddScaled = Number(functionalScore.score).toFixed(2); } - } else { - $("#" + _this._prefix + "Cadd").css("color", "black"); - _this.caddScaled = "NA"; - } - - // this.requestUpdate(); + }); } } + getProteinSubstitutionScoresColor(source, description) { + return this.proteinSubstitutionScores?.style?.[source]?.[description] || "black"; + } + render() { - if (this.variantAnnotation === undefined || this.variantAnnotation === "" || this.proteinSubScore === undefined) { - return; + if (!this.variantAnnotation) { + return nothing; } - const variantRegion = this.variantAnnotation.chromosome + ":" + this.variantAnnotation.start + "-" + this.variantAnnotation.start; - const variantId = this.variantAnnotation.id ? this.variantAnnotation.id : `${this.variantAnnotation.chromosome}:${this.variantAnnotation.start}:${this.variantAnnotation.reference}:${this.variantAnnotation.alternate}`; + return html` `; - } getDefaultConfig() { - return Types.dataFormConfig({ - // title: "Summary", - sections: [{ - title: "General", - elements: [{ - title: "Id", - type: "custom", - display: { - render: data => { - const variantRegion = data.chromosome + ":" + data.start + "-" + data.start; - const variantId = data.id ? data.id : `${data.chromosome}:${data.start}:${data.reference}:${data.alternate}`; - return html ` - - ${variantId} - - `; - } - } - }, - { - title: "HGVS", - type: "custom", - display: { - visible: data => data?.hgvs.length > 0, - render: data => html ` - ${data.hgvs.map(item => html` ${item}
`)} - ` - } - }, - { - title: "Alleles", - type: "custom", - display: { - render: data => html ` - ${data.reference}/${data.alternate} - ` - } - }, - { - title: "Location", - type: "custom", - display: { - render: data => html ` - ${data.chromosome}:${data.start} - ${data.end ? html`
-${data.end}
`: nothing} - ` - } - }, - { - title: "Type", - type: "custom", - field: "type", - display: { - visible: data => !UtilsNew.isEmpty(data.type), - } - }, - { - title: "Ancestral Allele", - field: "ancestralAllele", - display: { - visible: data => !UtilsNew.isEmpty(data.ancestralAllele), - } - }, - { - title: "MAF", - type: "custom", - display: { - visible: data => UtilsNew.isNotEmpty(data.minorAlleleFreq), - render: data => html `${data.minorAlleleFreq} (${data.minorAllele})` - } - }, - { - title: "Most Severe Consequence Type", - type: "custom", - display: { - render: data => html ` - ${data.displayConsequenceType} - ${this.ctGene ? html` - - (Gene : ${this.ctGene}, Transcript : ${this.ctTranscript}) - - ` : nothing } - ` - } - }, - { - title: "Most Severe Deleterious Score", - type: "custom", - display: { - render: data => html ` - - ${this.proteinSubScore.sift.description} - - ${this.isTranscriptAvailable(this.proteinSubScore.sift.transcript) ? html` - (Gene:${this.proteinSubScore.sift.gene}, Transcript: ${this.proteinSubScore.sift.transcript}) - ` : nothing } - ` - } - }, + return { + sections: [ { - title: "Polyphen", - type: "custom", - display: { - render: data => html ` - ${this.proteinSubScore.polyphen.description} - ${this.isTranscriptAvailable(this.proteinSubScore.polyphen.transcript) ? html` - (Gene:${this.proteinSubScore.polyphen.gene}, Transcript: ${this.proteinSubScore.polyphen.transcript}) - ` : nothing} - ` - } + title: "General", + elements: [ + { + title: "Id", + type: "custom", + display: { + render: data => { + const variantRegion = data.chromosome + ":" + data.start + "-" + data.start; + const variantId = data.id ? data.id : `${data.chromosome}:${data.start}:${data.reference}:${data.alternate}`; + const url = BioinfoUtils.getVariantLink(variantId, variantRegion, "ensembl_genome_browser", this.assembly); + return html ` + + ${variantId} + + `; + } + } + }, + { + title: "HGVS", + type: "custom", + display: { + visible: data => data?.hgvs.length > 0, + render: data => { + return data.hgvs.map(item => html`${item}
`); + }, + }, + }, + { + title: "Alleles", + type: "custom", + display: { + render: data => html`${data.reference}/${data.alternate}`, + }, + }, + { + title: "Location", + type: "custom", + display: { + render: data => html`${data.chromosome}:${data.start}${data.end ? html`
-${data.end}
`: nothing}`, + } + }, + { + title: "Type", + type: "custom", + field: "type", + display: { + visible: data => !UtilsNew.isEmpty(data.type), + }, + }, + { + title: "Ancestral Allele", + field: "ancestralAllele", + display: { + visible: data => !UtilsNew.isEmpty(data.ancestralAllele), + }, + }, + { + title: "MAF", + type: "custom", + display: { + visible: data => UtilsNew.isNotEmpty(data.minorAlleleFreq), + render: data => html`${data.minorAlleleFreq} (${data.minorAllele})`, + }, + }, + { + title: "Most Severe Consequence Type", + type: "custom", + display: { + render: data => { + const consequenceTypeColor = this._consequenceTypeToColor?.[data.displayConsequenceType] || "black"; + return html` + + ${data.displayConsequenceType} + + ${this._consequenceTypeGene ? html` + + (Gene : ${this._consequenceTypeGene}, Transcript : ${this._consequenceTypeTranscript}) + + ` : nothing} + `; + }, + }, + }, + { + title: "Most Severe Deleterious Score", + type: "custom", + display: { + render: () => { + const color = this.getProteinSubstitutionScoresColor("sift", this._proteinSubScore.sift.description); + return html` + + ${this._proteinSubScore.sift.description || "-"} + + ${this._proteinSubScore.sift?.transcript ? html` + (Gene:${this._proteinSubScore.sift.gene}, Transcript: ${this._proteinSubScore.sift.transcript}) + ` : nothing } + `; + }, + }, + }, + { + title: "Polyphen", + type: "custom", + display: { + render: () => { + const color = this.getProteinSubstitutionScoresColor("polyphen", this._proteinSubScore.polyphen.description); + return html` + + ${this._proteinSubScore.polyphen.description || "-"} + + ${this._proteinSubScore.polyphen?.transcript ? html` + (Gene:${this._proteinSubScore.polyphen.gene}, Transcript: ${this._proteinSubScore.polyphen.transcript}) + ` : nothing} + `; + }, + }, + }, + { + title: "CADD Scaled", + type: "custom", + display: { + render: () => { + const colorClassName = (this._caddScaled !== "NA" && this._caddScaled > 15) ? "text-danger" : "text-body"; + return html ` + ${this._caddScaled} + `; + }, + }, + }, + ], }, - { - title: "CADD Scaled", - type: "custom", - display: { - render: data => html ` - ${this.caddScaled} - ` - } - } - ] - }] - }); + ], + }; } }