From 8ac991137769c9315fd4e304cb3725ad9619ec82 Mon Sep 17 00:00:00 2001 From: Maiykol <hartung.michael@outlook.com> Date: Sun, 20 Jun 2021 17:53:44 +0200 Subject: [PATCH] support for ensg numbers; dealing with multiple ensg numbers refering to the same entrez ID --- .../analysis-panel.component.ts | 21 +++++++++++--- .../info-tile/info-tile.component.html | 12 ++++++++ .../info-tile/info-tile.component.ts | 4 +++ .../query-tile/query-tile.component.ts | 2 +- src/app/interfaces.ts | 20 ++++++++++++- src/app/main-network.ts | 28 +++++++++++-------- .../explorer-page/explorer-page.component.ts | 6 ++-- src/index.html | 21 +++++++------- 8 files changed, 85 insertions(+), 29 deletions(-) diff --git a/src/app/components/analysis-panel/analysis-panel.component.ts b/src/app/components/analysis-panel/analysis-panel.component.ts index d353ebf5..8327f8a0 100644 --- a/src/app/components/analysis-panel/analysis-panel.component.ts +++ b/src/app/components/analysis-panel/analysis-panel.component.ts @@ -20,6 +20,7 @@ import { WrapperType, getWrapperFromNode, getWrapperFromDrug, + getWrapperFromCustom, getNodeIdsFromPDI, getNodeIdsFromPPI, getProteinNodeId, @@ -386,6 +387,13 @@ export class AnalysisPanelComponent implements OnInit, OnChanges { } } + + /** + * Maps analysis result returned from database to valid Vis.js network input + * + * @param result + * @returns + */ public createNetwork(result: any): { edges: any[], nodes: any[] } { const config = result.parameters.config; @@ -405,12 +413,19 @@ export class AnalysisPanelComponent implements OnInit, OnChanges { const wrappers: { [key: string]: Wrapper } = {}; for (const node of network.nodes) { // backend converts object keys to PascalCase: p_123 --> p123 - const nodeObjectKey = node.split('_').join('') + const nodeObjectKey = node.split('_').join(''); + console.log(nodeObjectKey) if (nodeTypes[nodeObjectKey] === 'protein') { + // node is protein from database, has been mapped on init to backend protein from backend + // or was found during analysis this.proteins.push(details[nodeObjectKey]); wrappers[node] = getWrapperFromNode(details[nodeObjectKey]); } else if (nodeTypes[nodeObjectKey] === 'drug') { + // node is drug, was found during analysis wrappers[node] = getWrapperFromDrug(details[nodeObjectKey]); + } else { + // node is custom input from user, could not be mapped to backend protein + wrappers[node] = getWrapperFromCustom(details[nodeObjectKey]); } nodes.push(this.mapNode(config, wrappers[node], isSeed[nodeObjectKey], scores[nodeObjectKey])); } @@ -425,15 +440,13 @@ export class AnalysisPanelComponent implements OnInit, OnChanges { private mapNode(config: IConfig, wrapper: Wrapper, isSeed?: boolean, score?: number): any { // const node = NetworkSettings.getNodeStyle(nodeType, isSeed, this.analysis.inSelection(wrapper)); - console.log(wrapper) let group = this.inferNodeGroup(wrapper); if (typeof group === 'undefined' || typeof config.nodeGroups[group] === 'undefined') { group = 'default'; } - console.log(group) const node = JSON.parse(JSON.stringify(config.nodeGroups[group])); node.id = wrapper.id; - node.label = wrapper.data.name; + node.label = wrapper.data.symbol; node.nodeType = group; node.isSeed = isSeed; node.wrapper = wrapper; diff --git a/src/app/components/info-tile/info-tile.component.html b/src/app/components/info-tile/info-tile.component.html index 8e6fbef5..73c8bf37 100644 --- a/src/app/components/info-tile/info-tile.component.html +++ b/src/app/components/info-tile/info-tile.component.html @@ -4,6 +4,10 @@ <b><span>Name:</span></b> <span class="is-capitalized"> {{ wrapper.data.name }}</span> </p> + <p *ngIf="wrapper.data.symbol" [ngClass]="{'text-normal':smallStyle}"> + <b><span>Symbol:</span></b> + <span class="is-capitalized"> {{ wrapper.data.symbol }}</span> + </p> <p *ngIf="wrapper.type" [ngClass]="{'text-normal':smallStyle}"> <b><span>Type:</span></b> <span class="is-capitalized"> {{ wrapper.type }}</span> @@ -24,6 +28,14 @@ <span class="is-capitalized"> {{ wrapper.data.uniprotAc }}</span> </a> </p> + <p *ngIf="wrapper.data.ensg" [ngClass]="{'text-normal':smallStyle}"> + <b><span>Ensembl:</span></b> + <a + *ngFor="let ensg of wrapper.data.ensg" + href="https://www.ensembl.org/Homo_sapiens/Gene/Summary?g={{ ensg }}" target="_blank"> + <span class="is-capitalized"> {{ ensg }}</span> + </a> + </p> </div> diff --git a/src/app/components/info-tile/info-tile.component.ts b/src/app/components/info-tile/info-tile.component.ts index 44bd205e..aff398c2 100644 --- a/src/app/components/info-tile/info-tile.component.ts +++ b/src/app/components/info-tile/info-tile.component.ts @@ -18,6 +18,10 @@ export class InfoTileComponent implements OnInit { ngOnInit(): void { } + public print(x) { + console.log(x) + } + public beautify(url: string): string { if (url.startsWith('https://')) { url = url.substr('https://'.length); diff --git a/src/app/components/query-tile/query-tile.component.ts b/src/app/components/query-tile/query-tile.component.ts index effd4a12..9dfbdaa7 100644 --- a/src/app/components/query-tile/query-tile.component.ts +++ b/src/app/components/query-tile/query-tile.component.ts @@ -15,7 +15,7 @@ export class QueryTileComponent { querySearch(term: string, item: Wrapper) { term = term.toLowerCase(); const data = item.data as Node; - return data.name.toLowerCase().indexOf(term) > -1 || item.type.toLowerCase().indexOf(term) > -1; + return data.symbol.toLowerCase().indexOf(term) > -1 || item.type.toLowerCase().indexOf(term) > -1; } select(item) { diff --git a/src/app/interfaces.ts b/src/app/interfaces.ts index ed9d700d..56f66073 100644 --- a/src/app/interfaces.ts +++ b/src/app/interfaces.ts @@ -2,9 +2,11 @@ import {AlgorithmType, QuickAlgorithmType} from './services/analysis/analysis.se export interface Node { name: string; + symbol: string; id: string; netexId?: string; uniprotAc?: string; + ensg?: Array<string>; group?: string; color?: string; shape?: string; @@ -115,6 +117,17 @@ export function getId(gene: Node) { return `${gene.id}`; } +export function getWrapperFromCustom(gene: Node): Wrapper { + /** + * Constructs wrapper interface for gene + */ + return { + id: getNodeId(gene), + nodeId: getNodeId(gene), + type: 'custom', + data: gene, + }; +} export function getWrapperFromNode(gene: Node): Wrapper { /** @@ -138,7 +151,10 @@ export function getWrapperFromDrug(drug: Drug): Wrapper { }; } -export type WrapperType = 'protein' | 'drug'; +// protein = node that exists as protein in backend +// drug = drug from backend, found in analysis +// custom = custom node from user that could not be mapped to protein +export type WrapperType = 'protein' | 'drug' | 'custom'; export type EdgeType = 'protein-protein' | 'protein-drug'; export interface Wrapper { @@ -148,7 +164,9 @@ export interface Wrapper { data: { id: string; name: string; + symbol?: string; netexId?: string; + ensg?: Array<string>; shape?: string; color?: string; interactions?: any; diff --git a/src/app/main-network.ts b/src/app/main-network.ts index 1d827e18..63d349fb 100644 --- a/src/app/main-network.ts +++ b/src/app/main-network.ts @@ -51,7 +51,17 @@ export class ProteinNetwork { if (typeof group === 'undefined' || typeof config.nodeGroups[group] === 'undefined') { group = 'default'; } - const node = JSON.parse(JSON.stringify(config.nodeGroups[group])); + let node = JSON.parse(JSON.stringify(config.nodeGroups[group])); + + // node.name is actually group name since it comes from the group configuration + // this property is already stored in the wrapper object + // instead, node.name should reflect the actual node name + // "node.name = customNode.name"; + // update the node with custom node properties, including values fetched from backend + node = { + ... node, + ... customNode + } // label is only used for network visualization let nodeLabel = customNode.name; @@ -59,20 +69,16 @@ export class ProteinNetwork { nodeLabel = customNode.userId; } - // node.name is actually group name since it comes from the group configuration - // this property is already stored in the wrapper object - // instead, node.name should reflect the actual node name - node.name = customNode.name; - if (node.image) { node.shape = 'image'; } node.label = nodeLabel; - node.id = customNode.id; - node.x = customNode.x; - node.y = customNode.y; - node.uniprotAc = customNode.uniprotAc; - node.netexId = customNode.netexId; + // node.id = customNode.id; + // node.x = customNode.x; + // node.y = customNode.y; + // node.uniprotAc = customNode.uniprotAc; + // node.netexId = customNode.netexId; + // node.ensg = customNode.ensg; // console.log(node) return node; } diff --git a/src/app/pages/explorer-page/explorer-page.component.ts b/src/app/pages/explorer-page/explorer-page.component.ts index 4dbbdb5c..81f1d903 100644 --- a/src/app/pages/explorer-page/explorer-page.component.ts +++ b/src/app/pages/explorer-page/explorer-page.component.ts @@ -74,7 +74,7 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit { document.getElementById('main-column').classList.add('rightgone'); } } - + console.log(key) this.myConfig[key] = configObj[key]; } } @@ -193,7 +193,8 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit { } async ngAfterViewInit() { - this.createNetwork(); + // TODO find out if this had a function? we were loading the network twice + // this.createNetwork(); if (this.onload) { // tslint:disable-next-line:no-eval @@ -211,6 +212,7 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit { } private async getNetwork() { + const network = JSON.parse(this.networkJSON); // map data to nodes in backend diff --git a/src/index.html b/src/index.html index 30c069b4..65f8f542 100644 --- a/src/index.html +++ b/src/index.html @@ -39,12 +39,18 @@ <network-expander id="netexp1" config='{ "nodeGroups": {"0.5": {"type": "gene", "color": "rgb(204, 255, 51)", "name": "0.5", "shape": "circle"}, "1.5": {"type": "gene", "color": "rgb(102, 255, 51)", "name": "1.5", "shape": "circle"}, "2.0": {"type": "gene", "color": "rgb(51, 204, 51)", "name": "2.0", "shape": "circle"}, "-2.0": {"type": "gene", "color": "rgb(255, 0, 0)", "name": "-2.0", "shape": "circle"}}, - "edgeGroups": {"custom": {"color": "black", "name": "Custom Group"}}, "idientifier": "hugo", + "edgeGroups": {"custom": {"color": "black", "name": "Custom Group"}}, + "identifier": "ensg", "legendUrl": "https://exbio.wzw.tum.de/covex/assets/leg1.png" }' - network= '{"nodes": [{"Name": "SFTPD", "d": 2.1770573418095793, "color": "rgb(51, 204, 51)", "type": "square", "label": "SFTPD", "x": -0.31956085006193347, "y": -0.7406466643934345, "size": 10, "id": "SFTPD", "group": 1.5, "name": "SFTPD"}, {"Name": "FGG", "d": 3.0919984753400342, "color": "rgb(51, 204, 51)", "type": "square", "label": "FGG", "x": 0.07173702374771213, "y": -0.5272230319152038, "size": 10, "id": "FGG", "group": 1.5, "name": "FGG"}, {"Name": "FGB", "d": 1.7586794205006901, "color": "rgb(51, 204, 51)", "type": "square", "label": "FGB", "x": 0.1862980578421022, "y": -0.5379861465902673, "size": 10, "id": "FGB", "group": 1.5, "name": "FGB"}, {"Name": "CFI", "d": 1.6225326254583097, "color": "rgb(51, 204, 51)", "type": "square", "label": "CFI", "x": 0.6812917849238023, "y": -0.2648075564231581, "size": 10, "id": "CFI", "group": 1.5, "name": "CFI"}, {"Name": "C5", "d": 1.9059032485708656, "color": "rgb(51, 204, 51)", "type": "square", "label": "C5", "x": 0.20310846566736865, "y": -0.14000473240635625, "size": 10, "id": "C5", "group": 1.5, "name": "C5"}, {"Name": "C3", "d": 1.2907638114922122, "color": "rgb(102, 255, 51)", "type": "square", "label": "C3", "x": 0.41046161409628396, "y": -0.22972594268593455, "size": 10, "id": "C3", "group": 1.5, "name": "C3"}, {"Name": "C4BPA", "d": 2.8208380551350274, "color": "rgb(51, 204, 51)", "type": "square", "label": "C4BPA", "x": 0.32691273713760793, "y": -0.44002575152714773, "size": 10, "id": "C4BPA", "group": 1.5, "name": "C4BPA"}, {"Name": "CPB2", "d": 1.7868069138182534, "color": "rgb(51, 204, 51)", "type": "square", "label": "CPB2", "x": 0.005918725090868364, "y": -0.21370077890922853, "size": 10, "id": "CPB2", "group": 1.5, "name": "CPB2"}, {"Name": "FN1", "d": 0.5457280631776094, "color": "rgb(153, 255, 51)", "type": "square", "label": "FN1", "x": 0.10773970106896563, "y": -0.26910493560594656, "size": 10, "id": "FN1", "group": 0.5, "name": "FN1"}, {"Name": "DCN", "d": 0.07523726540508413, "color": "rgb(204, 255, 51)", "type": "square", "label": "DCN", "x": -0.1449109959561148, "y": -0.5406452007869201, "size": 10, "id": "DCN", "group": 0.5, "name": "DCN"}, {"Name": "KRT13", "d": -5.884559807904592, "color": "rgb(255, 0, 0)", "type": "circle", "label": "KRT13", "x": -0.5462663294859071, "y": 0.2179240739679362, "size": 10, "id": "KRT13", "group": 2.0, "name": "KRT13"}, {"Name": "KRT14", "d": -5.979503966095012, "color": "rgb(255, 0, 0)", "type": "circle", "label": "KRT14", "x": 0.20723970121617027, "y": 0.3335529310573068, "size": 10, "id": "KRT14", "group": 2.0, "name": "KRT14"}, {"Name": "KRT5", "d": -7.3912122103291935, "color": "rgb(255, 0, 0)", "type": "circle", "label": "KRT5", "x": 0.001680558082502895, "y": 0.1554556904769493, "size": 10, "id": "KRT5", "group": 2.0, "name": "KRT5"}, {"Name": "KRT6A", "d": -7.364973261442935, "color": "rgb(255, 0, 0)", "type": "circle", "label": "KRT6A", "x": -0.3511002998605662, "y": 0.3925879058088128, "size": 10, "id": "KRT6A", "group": 2.0, "name": "KRT6A"}, {"Name": "CSTA", "d": -3.8792306737039226, "color": "rgb(255, 0, 0)", "type": "circle", "label": "CSTA", "x": -0.010849204611034656, "y": 0.7467591168222204, "size": 10, "id": "CSTA", "group": 2.0, "name": "CSTA"}, {"Name": "DSP", "d": -1.7563342206781023, "color": "rgb(255, 153, 51)", "type": "circle", "label": "DSP", "x": -0.0678748213735474, "y": 0.39925246533037617, "size": 10, "id": "DSP", "group": -2.0, "name": "DSP"}, {"Name": "PI3", "d": -4.265528188882317, "color": "rgb(255, 0, 0)", "type": "circle", "label": "PI3", "x": 0.031056762567423294, "y": 1.0, "size": 10, "id": "PI3", "group": 2.0, "name": "PI3"}, {"Name": "KRT16", "d": -4.794121223753202, "color": "rgb(255, 0, 0)", "type": "circle", "label": "KRT16", "x": 0.03152510498669397, "y": 0.06575226291390532, "size": 10, "id": "KRT16", "group": 2.0, "name": "KRT16"}, {"Name": "KRT15", "d": -4.518290478769958, "color": "rgb(255, 0, 0)", "type": "circle", "label": "KRT15", "x": -0.2895261348950512, "y": 0.2654866500427342, "size": 10, "id": "KRT15", "group": 2.0, "name": "KRT15"}, {"Name": "KRT6B", "d": -5.5864948168835005, "color": "rgb(255, 0, 0)", "type": "circle", "label": "KRT6B", "x": -0.5348816001833466, "y": 0.32709964482335674, "size": 10, "id": "KRT6B", "group": 2.0, "name": "KRT6B"}], "edges": [{"from": "SFTPD", "to": "DCN", "group": "custom"}, {"from": "FGG", "to": "FGB", "group": "custom"}, {"from": "FGG", "to": "FN1", "group": "custom"}, {"from": "FGB", "to": "FN1", "group": "custom"}, {"from": "CFI", "to": "C3", "group": "custom"}, {"from": "C5", "to": "CPB2", "group": "custom"}, {"from": "C5", "to": "C3", "group": "custom"}, {"from": "C3", "to": "FN1", "group": "custom"}, {"from": "C4BPA", "to": "FN1", "group": "custom"}, {"from": "CPB2", "to": "FN1", "group": "custom"}, {"from": "FN1", "to": "KRT5", "group": "custom"}, {"from": "FN1", "to": "KRT16", "group": "custom"}, {"from": "FN1", "to": "DCN", "group": "custom"}, {"from": "KRT13", "to": "KRT6B", "group": "custom"}, {"from": "KRT13", "to": "KRT6A", "group": "custom"}, {"from": "KRT14", "to": "KRT5", "group": "custom"}, {"from": "KRT5", "to": "KRT15", "group": "custom"}, {"from": "KRT5", "to": "KRT16", "group": "custom"}, {"from": "KRT5", "to": "DSP", "group": "custom"}, {"from": "KRT6A", "to": "KRT15", "group": "custom"}, {"from": "KRT6A", "to": "DSP", "group": "custom"}, {"from": "CSTA", "to": "DSP", "group": "custom"}, {"from": "CSTA", "to": "PI3", "group": "custom"}, {"from": "DSP", "to": "KRT16", "group": "custom"}, {"from": "KRT15", "to": "KRT6B", "group": "custom"}]}' - style="height: 100%; width: 100vw; display: block;"></network-expander> + network='{ + "nodes": [{"name": "ENSG00000171862", "id": "ENSG00000171862", "group": "0.5"}, {"name": "ENSG00000284792", "id": "ENSG00000284792", "group": 0.5}], + "edges": [] + }' + style="height: 100%; width: 100vw; display: block;" + ></network-expander> </div> + <br> <br> <br> @@ -88,13 +94,8 @@ netexp.setAttribute('network', JSON.stringify({ nodes: [ { - label: "PTEN", - id: "PTEN", - group: "genes" - }, - { - label: "TP53", - id: "TP53", + name: "ENSG00000171862", + id: "ENSG00000171862", group: "genes" } ], -- GitLab