From f9f2e5aaf8bd5a6d1c62408fc836f08c5eee7d08 Mon Sep 17 00:00:00 2001 From: Michael Hartung <michi@Michaels-MacBook-Pro.local> Date: Wed, 21 Jul 2021 12:40:59 +0200 Subject: [PATCH] toggle seed nodes in analysis network --- .../analysis-panel.component.html | 6 ++ .../analysis-panel.component.ts | 70 +++++++++++++++---- .../network-legend.component.ts | 4 +- src/app/config.ts | 16 ++--- .../add-expressed-proteins.component.ts | 4 +- src/app/interfaces.ts | 5 +- src/app/network-settings.ts | 5 +- .../explorer-page/explorer-page.component.ts | 4 +- 8 files changed, 81 insertions(+), 33 deletions(-) diff --git a/src/app/components/analysis-panel/analysis-panel.component.html b/src/app/components/analysis-panel/analysis-panel.component.html index c074cc08..b476baa0 100644 --- a/src/app/components/analysis-panel/analysis-panel.component.html +++ b/src/app/components/analysis-panel/analysis-panel.component.html @@ -213,6 +213,12 @@ </div> </div> + <app-toggle class="footer-buttons" textOn="Seeds On" textOff="Off" + tooltipOn="Highlight seed nodes ON." + tooltipOff="Highlight seed nodes OFF." + [smallStyle]="smallStyle" + [value]="highlightSeeds" (valueChange)="updateHighlightSeeds($event)"></app-toggle> + <app-toggle *ngIf="task.info.target === 'drug-target'" class="footer-buttons" textOn="Drugs On" textOff="Off" tooltipOn="Display adjacent drugs ON." tooltipOff="Display adjacent drugs OFF." diff --git a/src/app/components/analysis-panel/analysis-panel.component.ts b/src/app/components/analysis-panel/analysis-panel.component.ts index e2dd40ef..6eeec400 100644 --- a/src/app/components/analysis-panel/analysis-panel.component.ts +++ b/src/app/components/analysis-panel/analysis-panel.component.ts @@ -15,7 +15,7 @@ import {algorithmNames, AnalysisService} from '../../services/analysis/analysis. import { Drug, EdgeType, - ExpressionMap, + NodeAttributeMap, getDrugNodeId, getProteinNodeId, getWrapperFromNode, @@ -89,6 +89,9 @@ export class AnalysisPanelComponent implements OnInit, OnChanges { public adjacentDrugList: Node[] = []; public adjacentDrugEdgesList: Node[] = []; + public highlightSeeds = false; + public seedMap: NodeAttributeMap; + private proteins: any; public effects: any; @@ -110,7 +113,7 @@ export class AnalysisPanelComponent implements OnInit, OnChanges { public tableDrugScoreTooltip = ''; public tableProteinScoreTooltip = ''; - public expressionMap: ExpressionMap; + public expressionMap: NodeAttributeMap; constructor(private http: HttpClient, public analysis: AnalysisService, public netex: NetexControllerService) { } @@ -160,7 +163,8 @@ export class AnalysisPanelComponent implements OnInit, OnChanges { if (this.task && this.task.info.done) { const result = await this.netex.getTaskResult(this.token); const nodeAttributes = result.nodeAttributes || {}; - const isSeed: { [key: string]: boolean } = nodeAttributes.isSeed || {}; + + this.seedMap = nodeAttributes.isSeed || {}; // Reset this.nodeData = {nodes: null, edges: null}; @@ -194,7 +198,7 @@ export class AnalysisPanelComponent implements OnInit, OnChanges { this.tableSelectedProteins = []; this.tableProteins.forEach((r) => { r.rawScore = r.score; - r.isSeed = isSeed[r.id]; + r.isSeed = this.seedMap[r.id]; const wrapper = getWrapperFromNode(r); if (this.analysis.inSelection(wrapper)) { this.tableSelectedProteins.push(r); @@ -261,10 +265,11 @@ export class AnalysisPanelComponent implements OnInit, OnChanges { const pos = this.network.getPositions([item.id]); node.x = pos[item.id].x; node.y = pos[item.id].y; + const isSeed = this.highlightSeeds ? this.seedMap[node.id] : false; const nodeStyled = NetworkSettings.getNodeStyle( node, this.myConfig, - false, + isSeed, selected, 1.0 ) @@ -481,7 +486,7 @@ export class AnalysisPanelComponent implements OnInit, OnChanges { // IMPORTANT we set seeds to "selected" and not to seeds. The user should be inspired to run // further analysis and the button function can be used to highlight seeds // option to use scores[node] as gradient, but sccores are very small - nodes.push(NetworkSettings.getNodeStyle(nodeDetails as Node, config, false, isSeed[node], 1)) + nodes.push(NetworkSettings.getNodeStyle(nodeDetails as Node, config, false, false, 1)) } for (const edge of network.edges) { edges.push(mapCustomEdge(edge, this.myConfig)); @@ -494,15 +499,56 @@ export class AnalysisPanelComponent implements OnInit, OnChanges { public setLegendContext() { const target = this.task.info.target; - if (target === 'drug') { - this.legendContext = "drug"; + if (target === 'drug' || this.adjacentDrugs) { + if (this.highlightSeeds) { + this.legendContext = "drugAndSeeds"; + } else { + this.legendContext = "drug"; + } + } else if (target === 'drug-target') { - this.legendContext = 'drugTarget' + if (this.highlightSeeds) { + this.legendContext = "drugTargetAndSeeds"; + } else { + this.legendContext = 'drugTarget' + } } else { throw `Could not set legend context based on ${target}.` } } + public updateHighlightSeeds(bool: boolean) { + this.highlightSeeds = bool; + const updatedNodes = []; + for (const item of this.proteins) { + 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.network.getPositions([item.id]); + node.x = pos[item.id].x; + node.y = pos[item.id].y; + const isSeed = this.highlightSeeds ? this.seedMap[node.id] : false; + Object.assign( + node, + NetworkSettings.getNodeStyle( + node, + this.myConfig, + isSeed, + this.analysis.inSelection(getWrapperFromNode(item)), + 1.0 + ) + ) + updatedNodes.push(node); + } + this.nodeData.nodes.update(updatedNodes); + this.setLegendContext(); + } + public updateAdjacentDrugs(bool: boolean) { this.adjacentDrugs = bool; if (this.adjacentDrugs) { @@ -519,15 +565,13 @@ export class AnalysisPanelComponent implements OnInit, OnChanges { this.nodeData.nodes.add(this.adjacentDrugList); this.nodeData.edges.add(this.adjacentDrugEdgesList); }) - this.legendContext = 'drug' } else { this.nodeData.nodes.remove(this.adjacentDrugList); this.nodeData.edges.remove(this.adjacentDrugEdgesList); this.adjacentDrugList = []; this.adjacentDrugEdgesList = []; - - this.setLegendContext() } + this.setLegendContext() } public updatePhysicsEnabled(bool: boolean) { @@ -656,7 +700,7 @@ export class AnalysisPanelComponent implements OnInit, OnChanges { NetworkSettings.getNodeStyle( node, this.myConfig, - node.isSeed, + false, // node.isSeed, this.analysis.inSelection(wrapper), gradient)); node.gradient = gradient; diff --git a/src/app/components/network-legend/network-legend.component.ts b/src/app/components/network-legend/network-legend.component.ts index 826135a8..1b9bd1b2 100644 --- a/src/app/components/network-legend/network-legend.component.ts +++ b/src/app/components/network-legend/network-legend.component.ts @@ -16,7 +16,9 @@ export class NetworkLegendComponent implements OnInit { 'explorer': ['foundNode', 'foundDrug', 'seedNode'], 'adjacentDrugs': ['foundNode', 'seedNode'], 'drugTarget': ['foundDrug', 'seedNode'], - 'drug': ['seedNode'] + 'drug': ['seedNode'], + 'drugTargetAndSeeds': ['foundDrug'], + 'drugAndSeeds': [] } public checkContext(nodeGroupKey) { diff --git a/src/app/config.ts b/src/app/config.ts index cab2597f..5c8265b7 100644 --- a/src/app/config.ts +++ b/src/app/config.ts @@ -123,7 +123,7 @@ export const defaultConfig: IConfig = { groupName: 'Found Nodes', color: { border: '#F12590', - background: '##F12590', + background: '#F12590', highlight: { border: '#F12590', background: '#F12590' @@ -146,10 +146,9 @@ export const defaultConfig: IConfig = { type: 'default drug type', }, seedNode: { - // groupName: 'Seed Nodes', - // color: '#F8981D', - // shape: 'circle', - // type: 'seed', + groupName: 'Seed Nodes', + shape: 'triangle', + type: 'seed', color: { border: '#F1111D', background: '#F1111D', @@ -164,19 +163,12 @@ export const defaultConfig: IConfig = { } }, selectedNode: { - // groupName: 'Selected Nodes', - // color: '#F8981D', - // shape: 'dot', - // type: 'selected', - borderWidth: 3, borderWidthSelected: 4, color: { border: '#F8981D', - // background: '#F8981D', highlight: { border: '#F8981D', - // background: '#F8981D' }, }, font: { 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 97e07f2e..634873da 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, ExpressionMap} from '../../interfaces'; +import {getWrapperFromNode, Node, Tissue, NodeAttributeMap} from '../../interfaces'; import {environment} from '../../../environments/environment'; import {HttpClient} from '@angular/common/http'; @@ -22,7 +22,7 @@ export class AddExpressedProteinsComponent implements OnChanges { @Input() public selectedTissue: Tissue | null = null; @Input() - public expressionMap: ExpressionMap = undefined; + public expressionMap: NodeAttributeMap = undefined; public proteins = []; public threshold = 5; diff --git a/src/app/interfaces.ts b/src/app/interfaces.ts index 2a7cb686..21836941 100644 --- a/src/app/interfaces.ts +++ b/src/app/interfaces.ts @@ -30,10 +30,11 @@ export interface Tissue { name: string; } -export type legendContext = 'explorer' | 'adjacentDrugs' | 'drug' | 'drugTarget'; +export type legendContext = 'explorer' | 'adjacentDrugs' | 'drug' | 'drugTarget' | +'drugTargetAndSeeds' | 'drugAndSeeds'; /// netexId to expressionlvl -export type ExpressionMap = { string: number }; +export type NodeAttributeMap = { string: number }; export interface NodeInteraction { diff --git a/src/app/network-settings.ts b/src/app/network-settings.ts index 077e5386..717f8c27 100644 --- a/src/app/network-settings.ts +++ b/src/app/network-settings.ts @@ -141,10 +141,13 @@ export class NetworkSettings { if (isSeed) { // apply seed node style to node node = merge(node, config.nodeGroups.seedNode); - } else if (isSelected) { + } + // selection on purpose after seed style, so seed style will be combined with selection style + if (isSelected) { // apply selected node style to node node = merge(node, config.nodeGroups.selectedNode); } + // show image if image url is given if (node.image) { node.shape = 'image'; diff --git a/src/app/pages/explorer-page/explorer-page.component.ts b/src/app/pages/explorer-page/explorer-page.component.ts index ba76f096..4528fa49 100644 --- a/src/app/pages/explorer-page/explorer-page.component.ts +++ b/src/app/pages/explorer-page/explorer-page.component.ts @@ -11,7 +11,7 @@ import { Wrapper, getWrapperFromNode, Tissue, - ExpressionMap, + NodeAttributeMap, getDrugNodeId, Drug, legendContext @@ -170,7 +170,7 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit { public legendContext: legendContext = 'explorer'; // keys are node netexIds - public expressionMap: ExpressionMap = undefined; + public expressionMap: NodeAttributeMap = undefined; @Input() public textColor = 'red'; -- GitLab