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