From 14d4f92d6325c81cdf02ec58f1aff70081298644 Mon Sep 17 00:00:00 2001 From: Maiykol <hartung.michael@outlook.com> Date: Wed, 7 Jul 2021 23:59:35 +0200 Subject: [PATCH] current node styles, for expression and selection --- src/app/app.component.ts | 5 +- .../add-expressed-proteins.component.ts | 8 +- src/app/interfaces.ts | 21 ++-- src/app/main-network.ts | 14 +-- src/app/network-settings.ts | 118 ++++++++++++++---- .../explorer-page.component.html | 4 +- .../explorer-page/explorer-page.component.ts | 78 ++++++++---- 7 files changed, 169 insertions(+), 79 deletions(-) diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 39258565..ff2be59c 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -1,11 +1,12 @@ -import {Component, Injector} from '@angular/core'; +import {Component, Injector, ViewEncapsulation} from '@angular/core'; import {ExplorerPageComponent} from './pages/explorer-page/explorer-page.component'; import {createCustomElement} from '@angular/elements'; @Component({ selector: 'app-root', template: `<div></div>`, - styleUrls: ['./app.component.scss'] + styleUrls: ['./app.component.scss'], + encapsulation: ViewEncapsulation.Emulated, }) export class AppComponent { mobileWindowExpanded = false; diff --git a/src/app/dialogs/add-expressed-proteins/add-expressed-proteins.component.ts b/src/app/dialogs/add-expressed-proteins/add-expressed-proteins.component.ts index 05337778..97e07f2e 100644 --- a/src/app/dialogs/add-expressed-proteins/add-expressed-proteins.component.ts +++ b/src/app/dialogs/add-expressed-proteins/add-expressed-proteins.component.ts @@ -1,6 +1,6 @@ import {Component, EventEmitter, Input, OnChanges, Output, SimpleChanges} from '@angular/core'; import {AnalysisService} from '../../services/analysis/analysis.service'; -import {getWrapperFromNode, Node, Tissue} from '../../interfaces'; +import {getWrapperFromNode, Node, Tissue, ExpressionMap} from '../../interfaces'; import {environment} from '../../../environments/environment'; import {HttpClient} from '@angular/common/http'; @@ -21,6 +21,8 @@ export class AddExpressedProteinsComponent implements OnChanges { public currentViewProteins: Array<Node> = []; @Input() public selectedTissue: Tissue | null = null; + @Input() + public expressionMap: ExpressionMap = undefined; public proteins = []; public threshold = 5; @@ -54,10 +56,10 @@ export class AddExpressedProteinsComponent implements OnChanges { public setThreshold(threshold: number) { this.threshold = threshold; - if (!this.currentViewProteins) { + if (!this.currentViewProteins || this.expressionMap === undefined) { return; } - this.proteins = this.currentViewProteins.filter(p => p.expressionLevel >= threshold); + this.proteins = this.currentViewProteins.filter(p => this.expressionMap[p.netexId] >= threshold); } public close() { diff --git a/src/app/interfaces.ts b/src/app/interfaces.ts index 3ba80fc8..0fd28729 100644 --- a/src/app/interfaces.ts +++ b/src/app/interfaces.ts @@ -10,12 +10,13 @@ export interface Node { ensg?: Array<string>; group?: string; groupName?: string; - color?: string; + color?: string | any; // mostly any, but vis js allows detail settings shape?: string; interactions?: Node[]; x?: number; y?: number; - expressionLevel?: number; + borderWidth: number; + borderWidthSelected: number; } export interface Tissue { @@ -23,6 +24,11 @@ export interface Tissue { name: string; } +export interface ExpressionMap { + // node --> expression level + netexId: number; +} + export interface NodeInteraction { from: string; to: string; @@ -80,8 +86,8 @@ export function getNodeIdsFromI(pvi: NodeInteraction) { export function getNodeIdsFromPPI(edge: NetworkEdge, wrappers: { [key: string]: Wrapper }) { return { - from: wrappers[edge.from].nodeId, - to: wrappers[edge.to].nodeId, + from: wrappers[edge.from].id, + to: wrappers[edge.to].id, }; } @@ -129,7 +135,6 @@ export function getWrapperFromCustom(gene: Node): Wrapper { gene.label = gene.label ? gene.label : gene.id return { id: getNodeId(gene), - nodeId: getNodeId(gene), data: gene, }; } @@ -142,7 +147,6 @@ export function getWrapperFromNode(gene: Node): Wrapper { gene.group = gene.group ? gene.group : 'foundNode'; return { id: getNodeId(gene), - nodeId: getNodeId(gene), data: gene, }; } @@ -153,8 +157,7 @@ export function getWrapperFromDrug(drug: Drug): Wrapper { drug.type = 'Drug'; drug.group = 'foundDrug'; return { - id: getDrugBackendId(drug), - nodeId: getDrugNodeId(drug), + id: getDrugNodeId(drug), data: drug, }; } @@ -163,7 +166,6 @@ export type EdgeType = 'protein-protein' | 'protein-drug'; export interface Wrapper { id: string; - nodeId: string; data: { id: string; label: string; @@ -178,6 +180,7 @@ export interface Wrapper { groupName?: string; uniprotAc?: string; expressionLevel?: number; + gradient?: number; x?: number; y?: number; drugId?: string; diff --git a/src/app/main-network.ts b/src/app/main-network.ts index 9a035ddc..8262cdb6 100644 --- a/src/app/main-network.ts +++ b/src/app/main-network.ts @@ -11,17 +11,6 @@ export class ProteinNetwork { constructor(public proteins: Node[], public edges: NodeInteraction[]) { } - public async loadPositions(http: HttpClient, dataset: Array<[string, string]>) { - const nodePositions = await http.get(`assets/positions/${getDatasetFilename(dataset)}`).toPromise(); - this.proteins.forEach((node) => { - const nodePosition = nodePositions[getProteinNodeId(node)]; - if (nodePosition) { - node.x = nodePosition.x; - node.y = nodePosition.y; - } - }); - } - public getProtein(ac: string): Node | undefined { return this.proteins.find((p) => p.id === ac); } @@ -53,6 +42,7 @@ export class ProteinNetwork { if (customNode.group === undefined) { // fallback to default node node = JSON.parse(JSON.stringify(defaultConfig.nodeGroups.default)); + node.group = 'default' } else { if (config.nodeGroups[customNode.group] === undefined) { throw `Node with id ${customNode.id} has undefined node group ${customNode.group}.` @@ -104,7 +94,7 @@ export class ProteinNetwork { return edge; } - public mapDataToNetworkInput(config: IConfig): { nodes: any[], edges: any[]; } { + public mapDataToNetworkInput(config: IConfig): { nodes: Node[], edges: any[]; } { const nodes = []; const edges = []; diff --git a/src/app/network-settings.ts b/src/app/network-settings.ts index 3aa64268..b7e3794f 100644 --- a/src/app/network-settings.ts +++ b/src/app/network-settings.ts @@ -1,7 +1,16 @@ import {getGradientColor} from './utils'; +import { + Node, +} from './interfaces'; +import { IConfig } from './config'; export class NetworkSettings { + // colors + private static Grey = '#A0A0A0' + private static White = '#FFFFFF'; + private static Black = '#000000'; + // Node color private static hostColor = '#123456'; private static approvedDrugColor = '#48C774'; @@ -9,8 +18,11 @@ export class NetworkSettings { private static nonSeedHostColor = '#3070B3'; private static nonSeedVirusColor = '#87082c'; - private static selectedBorderColor = '#F8981D'; - private static selectBorderHighlightColor = '#F8981D'; + private static selectedBorderColor = NetworkSettings.Black; + private static selectBorderHighlightColor = NetworkSettings.Black; + + private static seedBorderColor = '#F8981D'; + private static seedBorderHighlightColor = '#F8981D'; // Edge color private static edgeHostVirusColor = '#686868'; @@ -21,19 +33,22 @@ export class NetworkSettings { private static edgeGeneGeneHighlightColor = '#686868'; - // Border width + // Border width for nodes in selection private static selectedBorderWidth = 3; private static selectedBorderWidthSelected = 3; - + // Border width for seed nodes + private static seedBorderWidth = 3; + private static seedBorderWidthSelected = 3; + // Border width private static borderWidth = 1; private static borderWidthSelected = 3; // Node Font private static hostFontSize = 20; private static drugFontSize = 30; - private static hostFontColor = '#FFFFFF'; - private static drugFontColor = '#FFFFFF'; - private static drugInTrialFontColor = 'black'; + private static hostFontColor = NetworkSettings.White; + private static drugFontColor = NetworkSettings.White; + private static drugInTrialFontColor = NetworkSettings.Black; // Network Layout private static analysisLayout = { @@ -160,7 +175,56 @@ export class NetworkSettings { // } // } - // static getNodeStyle(nodeType: WrapperType, + static getNodeStyle( + node: Node, + config: IConfig, + isSeed: boolean, + isSelected: boolean, + drugType?: string, + drugInTrial?: boolean, + gradient?: number): any { + console.log(node) + if (!gradient) { + gradient = 1.0; + } + const nodeGroupObject = config.nodeGroups[node.group]; + // vis js style attributes + const nodeShadow = true; + // const nodeShape = node.shape; + // const nodeSize = 10; + // const nodeFont = node.font; + const nodeColor = nodeGroupObject.color; + if (isSeed) { + node.color = { + background: nodeColor, + border: this.seedBorderColor, + highlight: { + border: this.seedBorderHighlightColor, + background: nodeColor + } + }; + node.borderWidth = this.seedBorderWidth; + node.borderWidthSelected = this.seedBorderWidthSelected; + } else if (isSelected) { + node.color = { + background: nodeColor, + border: this.selectedBorderColor, + highlight: { + border: this.selectBorderHighlightColor, + background: nodeColor + } + }; + node.borderWidth = this.selectedBorderWidth; + node.borderWidthSelected = this.selectedBorderWidthSelected; + } else { + node.color = nodeColor; + node.borderWidth = this.borderWidth; + node.borderWidthSelected = this.borderWidthSelected; + } + return node; + } + + // static getNodeStyleOld(nodeType: WrapperType, // isSeed: boolean, // isSelected: boolean, // drugType?: string, @@ -198,9 +262,9 @@ export class NetworkSettings { // } // if (gradient === -1) { - // nodeColor = '#A0A0A0'; + // nodeColor = NetworkSettings.GREY; // } else { - // nodeColor = getGradientColor('#FFFFFF', nodeColor, gradient); + // nodeColor = getGradientColor(NetworkSettings.WHITE, nodeColor, gradient); // } // const node: any = { @@ -210,24 +274,24 @@ export class NetworkSettings { // shadow: nodeShadow, // }; - // if (isSelected) { - // node.color = { - // background: nodeColor, - // border: this.selectedBorderColor, - // highlight: { - // border: this.selectBorderHighlightColor, - // background: nodeColor, - // }, - // }; - - // node.borderWidth = this.selectedBorderWidth; - // node.borderWidthSelected = this.selectedBorderWidthSelected; - // } else { - // node.color = nodeColor; + // if (isSelected) { + // node.color = { + // background: nodeColor, + // border: this.selectedBorderColor, + // highlight: { + // border: this.selectBorderHighlightColor, + // background: nodeColor, + // }, + // }; - // node.borderWidth = this.borderWidth; - // node.borderWidthSelected = this.borderWidthSelected; - // } + // node.borderWidth = this.selectedBorderWidth; + // node.borderWidthSelected = this.selectedBorderWidthSelected; + // } else { + // node.color = nodeColor; + + // node.borderWidth = this.borderWidth; + // node.borderWidthSelected = this.borderWidthSelected; + // } // return node; // } diff --git a/src/app/pages/explorer-page/explorer-page.component.html b/src/app/pages/explorer-page/explorer-page.component.html index c4606ac3..6472ada6 100644 --- a/src/app/pages/explorer-page/explorer-page.component.html +++ b/src/app/pages/explorer-page/explorer-page.component.html @@ -13,7 +13,9 @@ <app-add-expressed-proteins [(show)]="showThresholdDialog" [selectedTissue]="currentViewSelectedTissue" [visibleNodes]="currentViewNodes" - [currentViewProteins]="currentViewProteins"> + [currentViewProteins]="currentViewProteins" + [expressionMap]="expressionMap" + > </app-add-expressed-proteins> <!-- Start explorer --> diff --git a/src/app/pages/explorer-page/explorer-page.component.ts b/src/app/pages/explorer-page/explorer-page.component.ts index e0f50185..aa14480c 100644 --- a/src/app/pages/explorer-page/explorer-page.component.ts +++ b/src/app/pages/explorer-page/explorer-page.component.ts @@ -1,6 +1,6 @@ import { AfterViewInit, - Component, Directive, + Component, ElementRef, HostListener, Input, OnInit, ViewChild @@ -10,7 +10,8 @@ import { Node, Wrapper, getWrapperFromNode, - Tissue + Tissue, + ExpressionMap } from '../../interfaces'; import {ProteinNetwork} from '../../main-network'; import {AnalysisService} from '../../services/analysis/analysis.service'; @@ -128,8 +129,8 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit { public proteinData: ProteinNetwork; - public proteins: any; - public edges: any; + public proteins: Node[]; + public edges: NodeInteraction[]; private networkInternal: any; // this will store the vis Dataset @@ -156,6 +157,9 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit { public expressionExpanded = false; public selectedTissue: Tissue | null = null; + // keys are node netexIds + public expressionMap: ExpressionMap = undefined; + @Input() public textColor = 'red'; @@ -179,14 +183,20 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit { } const updatedNodes = []; for (const item of items) { - const node = this.nodeData.nodes.get(item.id); + const node: Node = this.nodeData.nodes.get(item.id); if (!node) { continue; } const pos = this.networkInternal.getPositions([item.id]); node.x = pos[item.id].x; node.y = pos[item.id].y; + // if (node.group == 'default') { + // Object.assign(node, this.myConfig.nodeGroups.default); + // } else { + // Object.assign(node, this.myConfig.nodeGroups[node.group]); + // } Object.assign(node, this.myConfig.nodeGroups[node.group]); + updatedNodes.push(node); } this.nodeData.nodes.update(updatedNodes); @@ -194,7 +204,13 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit { const updatedNodes = []; this.nodeData.nodes.forEach((node) => { const nodeSelected = this.analysis.idInSelection(node.id); + // if (node.group == 'default') { + // Object.assign(node, this.myConfig.nodeGroups.default); + // } else { + // Object.assign(node, this.myConfig.nodeGroups[node.group]); + // }; Object.assign(node, this.myConfig.nodeGroups[node.group]); + }); this.nodeData.nodes.update(updatedNodes); } @@ -268,7 +284,7 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit { public async openSummary(item: Wrapper, zoom: boolean) { this.selectedWrapper = item; if (zoom) { - this.zoomToNode(item.nodeId); + this.zoomToNode(item.id); } this.showDetails = true; } @@ -326,13 +342,13 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit { }); if (this.selectedWrapper) { - this.zoomToNode(this.selectedWrapper.nodeId); + this.zoomToNode(this.selectedWrapper.id); } this.queryItems = []; this.fillQueryItems(this.proteins); if (this.selectedWrapper) { - this.networkInternal.selectNodes([this.selectedWrapper.nodeId]); + this.networkInternal.selectNodes([this.selectedWrapper.id]); } } @@ -396,7 +412,7 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit { // if user has not set the return-groups, take the defaults nodeGroups = {...defaultNodeGroups, ...nodeGroups} - // override default node groups + // override previous node groups this.myConfig[key] = nodeGroups; } @@ -473,33 +489,45 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit { } public selectTissue(tissue: Tissue | null) { + console.log("here") this.expressionExpanded = false; if (!tissue) { this.selectedTissue = null; const updatedNodes = []; for (const item of this.proteins) { - const node = this.nodeData.nodes.get(item.nodeId); + console.log(item) + if (item.netexId === undefined) { + // nodes that are not mapped to backend remain untouched + continue; + } + const node: Node = this.nodeData.nodes.get(item.id); if (!node) { continue; } - const pos = this.networkInternal.getPositions([item.nodeId]); - node.x = pos[item.nodeId].x; - node.y = pos[item.nodeId].y; - // Object.assign(node, - // NetworkSettings.getNodeStyle( - // node.wrapper.type, - // node.isSeed, - // this.analysis.inSelection(item), - // undefined, - // undefined, - // 1.0)); - node.wrapper = item; - node.gradient = 1.0; - // protein.expressionLevel = undefined; - (node.wrapper.data as Node).expressionLevel = undefined; + console.log("node") + console.log(node) + const pos = this.networkInternal.getPositions([item.id]); + node.x = pos[item.id].x; + node.y = pos[item.id].y; + Object.assign( + node, + NetworkSettings.getNodeStyle( + node, + this.myConfig, + false, + this.analysis.inSelection(getWrapperFromNode(item)), + undefined, + undefined, + 1.0 + ) + ) + console.log("in selection") + console.log(this.analysis.inSelection(getWrapperFromNode(item))) updatedNodes.push(node); } this.nodeData.nodes.update(updatedNodes); + // delete expression values + this.expressionMap = undefined; } else { this.selectedTissue = tissue; -- GitLab