From 93b11bfef45ae7292ea3ccccf2b78776f5132a62 Mon Sep 17 00:00:00 2001
From: Maiykol <hartung.michael@outlook.com>
Date: Thu, 24 Jun 2021 14:54:56 +0200
Subject: [PATCH] default node groups for analysis network

---
 .../analysis-panel.component.ts               | 10 ++-
 .../network-legend.component.html             | 66 ++++++++++---------
 .../network-legend.component.ts               | 14 +++-
 src/app/config.ts                             | 18 +++--
 .../launch-analysis.component.ts              |  2 +
 src/app/interfaces.ts                         |  8 +++
 src/app/main-network.ts                       | 12 ++--
 .../explorer-page.component.html              |  2 +-
 .../explorer-page/explorer-page.component.ts  | 30 +++++++--
 src/app/utils.ts                              |  9 +++
 src/index.html                                |  4 +-
 11 files changed, 122 insertions(+), 53 deletions(-)

diff --git a/src/app/components/analysis-panel/analysis-panel.component.ts b/src/app/components/analysis-panel/analysis-panel.component.ts
index 014a3a46..4e24e203 100644
--- a/src/app/components/analysis-panel/analysis-panel.component.ts
+++ b/src/app/components/analysis-panel/analysis-panel.component.ts
@@ -139,6 +139,7 @@ export class AnalysisPanelComponent implements OnInit, OnChanges {
 
       if (this.task && this.task.info.done) {
         const result = await this.netex.getTaskResult(this.token);
+        console.log("result")
         console.log(result)
         const nodeAttributes = result.nodeAttributes || {};
         const isSeed: { [key: string]: boolean } = nodeAttributes.isSeed || {};
@@ -415,6 +416,9 @@ export class AnalysisPanelComponent implements OnInit, OnChanges {
   public createNetwork(result: any): { edges: any[], nodes: any[] } {
     const config = result.parameters.config;
 
+    // add drugGroup and foundNodesGroup for added nodes
+    // these groups can be overwritten by the user
+
     const nodes = [];
     const edges = [];
 
@@ -468,8 +472,12 @@ export class AnalysisPanelComponent implements OnInit, OnChanges {
 
     console.log("node group")
     console.log(config.nodeGroups)
-    console.log(config.nodeGroups[wrapper.data.group]);
+    console.log("node")
+
+    console.log(wrapper.data);
 
+    // override group is node is seed
+    wrapper.data.group = isSeed ? 'seedNode' : wrapper.data.group
     const node = JSON.parse(JSON.stringify(config.nodeGroups[wrapper.data.group]));
     node.id = wrapper.id;
     node.label = this.inferNodeLabel(config, wrapper);
diff --git a/src/app/components/network-legend/network-legend.component.html b/src/app/components/network-legend/network-legend.component.html
index e9eeb21b..b71bb125 100644
--- a/src/app/components/network-legend/network-legend.component.html
+++ b/src/app/components/network-legend/network-legend.component.html
@@ -1,43 +1,45 @@
-<div class="legend" [class.right]="this.config.legendPos === 'right'">
+<div class="legend" [class.right]="this.legendConfig.legendPos === 'right'">
 
   <!-- default legend in html -->
-  <table *ngIf="!this.config.legendUrl.length">
-    <ng-container *ngIf="this.config.showLegendNodes">
-      <tr *ngFor="let nodeGroup of this.config.nodeGroups | keyvalue" class="list-item">
+  <table *ngIf="!this.legendConfig.legendUrl.length">
+    <ng-container *ngIf="this.legendConfig.showLegendNodes">
+      <tr *ngFor="let nodeGroup of this.legendConfig.nodeGroups | keyvalue" class="list-item">
 
-        <ng-container *ngIf="nodeGroup.value.image">
-          <!-- group icon given, use icon in legend -->
-          <td>
-            <img [src]="nodeGroup.value.image" class="legend-icon"/>
-          </td>
-          <td>&nbsp;{{ nodeGroup.value.groupName }}</td>
-        </ng-container>
-
-        <ng-container *ngIf="!nodeGroup.value.image">
-          <!-- no image given, create icon programmatically -->
-          <td *ngIf="nodeGroup.value.shape !== 'triangle' && nodeGroup.value.shape !== 'star'">
-          <span class="node {{ nodeGroup.value.shape }}" [style.background-color]=nodeGroup.value.color>
-          </span>
-          </td>
-          <td *ngIf="nodeGroup.value.shape === 'triangle'">
-            <span class="node {{ nodeGroup.value.shape }}" [style.border-bottom-color]=nodeGroup.value.color>
-            </span>
-          </td>
-          <td *ngIf="nodeGroup.value.shape === 'star'">
-            <span class="node {{ nodeGroup.value.shape }}"
-                  [style.border-bottom-color]=nodeGroup.value.color
-                  [style.color]=nodeGroup.value.color
-            >
+        <ng-container *ngIf="!analysis && nodeGroup.key">
+          <ng-container *ngIf="nodeGroup.value.image">
+            <!-- group icon given, use icon in legend -->
+            <td>
+              <img [src]="nodeGroup.value.image" class="legend-icon"/>
+            </td>
+            <td>&nbsp;{{ nodeGroup.value.groupName }}</td>
+          </ng-container>
+  
+          <ng-container *ngIf="!nodeGroup.value.image">
+            <!-- no image given, create icon programmatically -->
+            <td *ngIf="nodeGroup.value.shape !== 'triangle' && nodeGroup.value.shape !== 'star'">
+            <span class="node {{ nodeGroup.value.shape }}" [style.background-color]=nodeGroup.value.color>
             </span>
-          </td>
-          <td>&nbsp;{{ nodeGroup.value.groupName }}</td>
+            </td>
+            <td *ngIf="nodeGroup.value.shape === 'triangle'">
+              <span class="node {{ nodeGroup.value.shape }}" [style.border-bottom-color]=nodeGroup.value.color>
+              </span>
+            </td>
+            <td *ngIf="nodeGroup.value.shape === 'star'">
+              <span class="node {{ nodeGroup.value.shape }}"
+                    [style.border-bottom-color]=nodeGroup.value.color
+                    [style.color]=nodeGroup.value.color
+              >
+              </span>
+            </td>
+            <td>&nbsp;{{ nodeGroup.value.groupName }}</td>
+          </ng-container>
         </ng-container>
 
       </tr>
     </ng-container>
 
-    <ng-container *ngIf="this.config.showLegendEdges">
-      <tr *ngFor="let edgeGroup of this.config.edgeGroups | keyvalue" class="list-item">
+    <ng-container *ngIf="this.legendConfig.showLegendEdges">
+      <tr *ngFor="let edgeGroup of this.legendConfig.edgeGroups | keyvalue" class="list-item">
         <td>
           <hr *ngIf="!edgeGroup.value.dashes" class="edge" [style.background-color]=edgeGroup.value.color>
           <hr *ngIf="edgeGroup.value.dashes" class="edge dashes" [style.color]=edgeGroup.value.color>
@@ -49,5 +51,5 @@
 
 
   <!-- custom legend image if url given by user -->
-  <img *ngIf="this.config.legendUrl.length" [src]="this.config.legendUrl" [ngClass]="this.config.legendClass"/>
+  <img *ngIf="this.legendConfig.legendUrl.length" [src]="this.legendConfig.legendUrl" [ngClass]="this.legendConfig.legendClass"/>
 </div>
diff --git a/src/app/components/network-legend/network-legend.component.ts b/src/app/components/network-legend/network-legend.component.ts
index b3e9079a..28c42814 100644
--- a/src/app/components/network-legend/network-legend.component.ts
+++ b/src/app/components/network-legend/network-legend.component.ts
@@ -7,8 +7,20 @@ import {IConfig} from '../../config';
   styleUrls: ['./network-legend.component.scss']
 })
 export class NetworkLegendComponent implements OnInit {
+  public legendConfig: IConfig;
 
-  @Input() config: IConfig;
+  @Input() analysis: boolean;
+  @Input() set config(value: IConfig) {
+    // copy to not override user config
+    value = JSON.parse(JSON.stringify(value));
+    if (!this.analysis) {
+      // do not show the analysis-groups in the explorer network
+      delete value.nodeGroups.foundNode;
+      delete value.nodeGroups.foundDrug;
+      delete value.nodeGroups.seedNode;
+    }
+    this.legendConfig = value;
+  };
 
   constructor() { }
 
diff --git a/src/app/config.ts b/src/app/config.ts
index 30a2b025..f20b9ff9 100644
--- a/src/app/config.ts
+++ b/src/app/config.ts
@@ -73,25 +73,33 @@ export const defaultConfig: IConfig = {
   interactionDrugProtein: 'DrugBank',
   interactionProteinProtein: 'STRING',
   nodeGroups: {
+    // all NodeGroups but the default group must be set, if not provided by the user, they will be taken from here
     default: {
       // this default group is used for default node group values
+      // and is fallback in case user does not provide any nodeGroup
       groupName: 'Default Node Group',
       color: 'yellow',
       shape: 'triangle',
       type: 'default type',
       detailShowLabel: false,
     },
-    default_protein: {
-      groupName: 'Resulting Proteins',
+    foundNode: {
+      groupName: 'Found Nodes',
       color: 'red',
       shape: 'circle',
-      type: 'default protein type',
+      type: 'default node type',
     },
-    default_drug: {
-      groupName: 'Possible Drugs',
+    foundDrug: {
+      groupName: 'Found Drugs',
       color: 'green',
       shape: 'star',
       type: 'default drug type',
+    },
+    seedNode: {
+      groupName: 'Seed Nodes',
+      color: 'blue',
+      shape: 'circle',
+      type: 'seed',
     }
   },
   edgeGroups: {
diff --git a/src/app/dialogs/launch-analysis/launch-analysis.component.ts b/src/app/dialogs/launch-analysis/launch-analysis.component.ts
index dc1d4ab2..b2e3a533 100644
--- a/src/app/dialogs/launch-analysis/launch-analysis.component.ts
+++ b/src/app/dialogs/launch-analysis/launch-analysis.component.ts
@@ -112,6 +112,8 @@ export class LaunchAnalysisComponent implements OnInit, OnChanges {
       config: this.config,
       input_network: this.inputNetwork
     };
+    console.log("config")
+    console.log(this.config)
 
     parameters.ppi_dataset = this.config.interactionProteinProtein;
     parameters.pdi_dataset = this.config.interactionDrugProtein;
diff --git a/src/app/interfaces.ts b/src/app/interfaces.ts
index 11673307..3ba80fc8 100644
--- a/src/app/interfaces.ts
+++ b/src/app/interfaces.ts
@@ -28,6 +28,7 @@ export interface NodeInteraction {
   to: string;
   group?: string;
   label?: string;
+  title?: string;
 }
 
 export interface NetworkEdge {
@@ -137,6 +138,8 @@ export function getWrapperFromNode(gene: Node): Wrapper {
   /**
    * Constructs wrapper interface for gene
    */
+  // if node does not have property group, it was found by the analysis
+  gene.group = gene.group ? gene.group : 'foundNode';
   return {
     id: getNodeId(gene),
     nodeId: getNodeId(gene),
@@ -146,6 +149,9 @@ export function getWrapperFromNode(gene: Node): Wrapper {
 
 
 export function getWrapperFromDrug(drug: Drug): Wrapper {
+  // set type and group
+  drug.type = 'Drug';
+  drug.group = 'foundDrug';
   return {
     id: getDrugBackendId(drug),
     nodeId: getDrugNodeId(drug),
@@ -186,11 +192,13 @@ export interface Wrapper {
 export interface Drug {
   id: string;
   label: string;
+  type: string;
   status: 'approved' | 'investigational';
   inTrial: boolean;
   inLiterature: boolean;
   trialLinks: string[];
   netexId: string;
+  group: string;
 }
 
 export interface Dataset {
diff --git a/src/app/main-network.ts b/src/app/main-network.ts
index c1444667..9a035ddc 100644
--- a/src/app/main-network.ts
+++ b/src/app/main-network.ts
@@ -52,13 +52,13 @@ export class ProteinNetwork {
     let node;
     if (customNode.group === undefined) {
       // fallback to default node
-      node = {...defaultConfig.nodeGroups.default};
+      node = JSON.parse(JSON.stringify(defaultConfig.nodeGroups.default));
     } else {
       if (config.nodeGroups[customNode.group] === undefined) {
         throw `Node with id ${customNode.id} has undefined node group ${customNode.group}.`
       }
       // copy
-      node = {...config.nodeGroups[customNode.group]};
+      node = JSON.parse(JSON.stringify(config.nodeGroups[customNode.group]));
     }
     // update the node with custom node properties, including values fetched from backend
     node = {
@@ -70,6 +70,8 @@ export class ProteinNetwork {
     if (node.image) {
       node.shape = 'image';
     }
+    // // remove '_' from group if group is defined
+    // node.group = node.group===undefined ? node.group : node.group.replace('_', '');
     return node;
   }
 
@@ -85,18 +87,20 @@ export class ProteinNetwork {
     let edge;
     if (customEdge.group === undefined) {
       // fallback to default node
-      edge = {...defaultConfig.edgeGroups.default};
+      edge = JSON.parse(JSON.stringify(defaultConfig.edgeGroups.default));
     } else {
       if (config.edgeGroups[customEdge.group] === undefined) {
         throw `Edge "from ${customEdge.from}" - "to ${customEdge.to}" has undefined edge group ${customEdge.group}.`
       }
       // copy
-      edge = {...config.edgeGroups[customEdge.group]};
+      edge = JSON.parse(JSON.stringify(config.edgeGroups[customEdge.group]));
     }
     edge = {
       ...edge,
       ...customEdge
     }
+    // // remove '_' from group if group is defined
+    // edge.group = edge.group===undefined ? edge.group : edge.group.replace('_', '');
     return edge;
   }
 
diff --git a/src/app/pages/explorer-page/explorer-page.component.html b/src/app/pages/explorer-page/explorer-page.component.html
index 12084608..c4606ac3 100644
--- a/src/app/pages/explorer-page/explorer-page.component.html
+++ b/src/app/pages/explorer-page/explorer-page.component.html
@@ -113,7 +113,7 @@
         <div class="card-content fullheight">
           <div class="card-image" id="canvas-content">
             <div *ngIf="myConfig.showLegend">
-              <app-network-legend [config]="myConfig"></app-network-legend>
+              <app-network-legend [config]="myConfig" [analysis]="false"></app-network-legend>
             </div>
             <div class="parent fullheight">
               <div class="center image1 fullheight" #network>
diff --git a/src/app/pages/explorer-page/explorer-page.component.ts b/src/app/pages/explorer-page/explorer-page.component.ts
index e18bfa54..cde11c06 100644
--- a/src/app/pages/explorer-page/explorer-page.component.ts
+++ b/src/app/pages/explorer-page/explorer-page.component.ts
@@ -19,6 +19,7 @@ import html2canvas from 'html2canvas';
 import {NetworkSettings} from '../../network-settings';
 import {defaultConfig, EdgeGroup, IConfig, NodeGroup} from '../../config';
 import {NetexControllerService} from 'src/app/services/netex-controller/netex-controller.service';
+import { removeUnderscoreFromKeys } from 'src/app/utils';
 // import * as 'vis' from 'vis-network';
 // import {DataSet} from 'vis-data';
 // import {vis} from 'src/app/scripts/vis-network.min.js';
@@ -358,22 +359,33 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit {
    * @param key 
    * @param values 
    */
-  public setConfigNodeGroup(key: string, nodeGroups: Array<NodeGroup>) {
+  public setConfigNodeGroup(key: string, nodeGroups: { [key: string]: NodeGroup}) {
     if (nodeGroups === undefined || !Object.keys(nodeGroups).length) {
-      // if node groups are not set or empty, use default edge group(s)
+      // if node groups are not set or empty, use default node group(s)
       this.myConfig[key] = defaultConfig.nodeGroups;
       // stop if nodeGroups do not contain any information
       return
     }
+
+    // // do not allow '_' in node Group names since it causes problems with backend
+    // nodeGroups = removeUnderscoreFromKeys(nodeGroups)
+
     // make sure all keys are set
-    Object.entries(nodeGroups).forEach(([key, value]) => {
-      if (!('detailShowLabel' in value)) {
+    Object.entries(nodeGroups).forEach(([key, group]) => {
+      if (!('detailShowLabel' in group)) {
         // use detailShowLabel default value if not set
-        value['detailShowLabel'] = defaultConfig.nodeGroups.default.detailShowLabel;
+        group['detailShowLabel'] = defaultConfig.nodeGroups.default.detailShowLabel;
       }
     })
+
+    // make sure that return-groups (seeds, drugs, found nodes) are set
+    const defaultNodeGroups = JSON.parse(JSON.stringify(defaultConfig.nodeGroups));
+    // if user has set nodeGroups, do not use group "default"
+    delete defaultNodeGroups.default;
+    // if user has not set the return-groups, take the defaults
+    nodeGroups = {...defaultNodeGroups, ...nodeGroups}
     
-    // override default edge groups
+    // override default node groups
     this.myConfig[key] = nodeGroups;
   }
 
@@ -383,13 +395,17 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit {
    * @param key 
    * @param values 
    */
-  public setConfigEdgeGroup(key: string, edgeGroups: Array<EdgeGroup>) {
+  public setConfigEdgeGroup(key: string, edgeGroups: { [key: string]: EdgeGroup}) {
     if (edgeGroups === undefined || !Object.keys(edgeGroups).length) {
       // if edge groups are not set or empty, use default edge group(s)
       this.myConfig[key] = defaultConfig.edgeGroups;
       // stop if edgeGroups do not contain any information
       return
     }
+    
+    // // do not allow '_' in node Group names since it causes problems with backend
+    // edgeGroups = removeUnderscoreFromKeys(edgeGroups)
+
     // make sure all keys are set
     Object.entries(edgeGroups).forEach(([key, value]) => {
       if (!('dashes' in value)) {
diff --git a/src/app/utils.ts b/src/app/utils.ts
index 3d79ea68..6497399d 100644
--- a/src/app/utils.ts
+++ b/src/app/utils.ts
@@ -45,3 +45,12 @@ export function getGradientColor(startColor: string, endColor: string, percent:
 
   return '#' + diffRedStr + diffGreenStr + diffBlueStr;
 }
+
+export function removeUnderscoreFromKeys(obj) {
+  const result = {};
+  Object.keys(obj).forEach(x => {
+    const y = x.replace("_", "");
+    result[y] = obj[x];
+  });
+  return result;
+}
diff --git a/src/index.html b/src/index.html
index 997b419a..d390a791 100644
--- a/src/index.html
+++ b/src/index.html
@@ -38,12 +38,12 @@
 
   <network-expander id="netexp1"
                     config='{
-                      "nodeGroups": {"0.5": {"type": "0.5er Instanz", "color": "rgb(204, 255, 51)", "groupName": "0.5", "shape": "circle"}, "patient_group": {"type": "Patient", "detailShowLabel": "true", "color": "red", "groupName": "patient group", "shape": "circle"}},
+                      "nodeGroups": {"0.5": {"type": "0.5er Instanz", "color": "rgb(204, 255, 51)", "groupName": "0.5", "shape": "circle"}, "patientgroup": {"type": "Patient", "detailShowLabel": "true", "color": "red", "groupName": "patient group", "shape": "circle"}},
                       "edgeGroups": {"dashes": {"color": "black", "groupName": "dashes Group", "dashes": [1, 2]}, "notdashes": {"color": "black", "groupName": "not dashes Group"}},
                       "identifier": "symbol"
                     }'
                     network='{
-                      "nodes": [{"id": "MYC", "label": "node w/o group"}, {"id": "TP53", "group": "0.5"}, {"id": "C5", "group": "0.5"}, {"id": "Patient No. 5", "group": "patient_group"}, {"label": "PTEN", "id": "PTEN", "group": 0.5}],
+                      "nodes": [{"id": "MYC", "label": "node w/o group"}, {"id": "TP53", "group": "0.5"}, {"id": "C5", "group": "0.5"}, {"id": "Patient No. 5", "group": "patientgroup"}, {"label": "PTEN", "id": "PTEN", "group": 0.5}],
                       "edges": [
                       {"from": "TP53","to": "C5","group": "dashes", "label": "this is a label", "title": "this is a title"},
                       {"from": "Patient No. 5","to": "C5","label": "w/o group"}
-- 
GitLab