From e5f52d696ed5da37feaa9f67b74e36a004bf1839 Mon Sep 17 00:00:00 2001
From: "Hartung, Michael" <michael.hartung@uni-hamburg.de>
Date: Fri, 15 Jul 2022 09:37:18 +0200
Subject: [PATCH] bugfix: select node when expression pie charts does not break
 chart style anymore

---
 .../analysis-panel.component.ts               | 42 +++++++--------
 .../components/network/network.component.ts   | 32 ++++++++----
 src/app/config.ts                             |  2 +
 src/app/interfaces.ts                         |  1 +
 src/app/network-settings.ts                   | 51 ++++---------------
 .../explorer-page/explorer-page.component.ts  |  3 +-
 src/app/utils.ts                              |  5 +-
 src/index.html                                | 28 ++--------
 8 files changed, 62 insertions(+), 102 deletions(-)

diff --git a/src/app/components/analysis-panel/analysis-panel.component.ts b/src/app/components/analysis-panel/analysis-panel.component.ts
index 3e9f514f..a47f0aa7 100644
--- a/src/app/components/analysis-panel/analysis-panel.component.ts
+++ b/src/app/components/analysis-panel/analysis-panel.component.ts
@@ -10,9 +10,9 @@ import {
   SimpleChanges,
   ViewChild,
 } from '@angular/core';
-import {HttpClient} from '@angular/common/http';
-import {environment} from '../../../environments/environment';
-import {algorithmNames, AnalysisService} from '../../services/analysis/analysis.service';
+import { HttpClient } from '@angular/common/http';
+import { environment } from '../../../environments/environment';
+import { algorithmNames, AnalysisService } from '../../services/analysis/analysis.service';
 import {
   Drug,
   EdgeType,
@@ -28,9 +28,9 @@ import {
   NodeInteraction,
 } from '../../interfaces';
 import domtoimage from 'dom-to-image';
-import {NetworkSettings} from '../../network-settings';
-import {NetexControllerService} from 'src/app/services/netex-controller/netex-controller.service';
-import {defaultConfig, IConfig} from 'src/app/config';
+import { NetworkSettings } from '../../network-settings';
+import { NetexControllerService } from 'src/app/services/netex-controller/netex-controller.service';
+import { defaultConfig, IConfig } from 'src/app/config';
 import { mapCustomEdge, mapCustomNode } from 'src/app/main-network';
 import { downLoadFile, pieChartContextRenderer, removeDuplicateObjectsFromList } from 'src/app/utils';
 import { DrugstoneConfigService } from 'src/app/services/drugstone-config/drugstone-config.service';
@@ -60,7 +60,7 @@ interface Baited {
 })
 export class AnalysisPanelComponent implements OnInit, OnChanges, AfterViewInit {
 
-  @ViewChild('networkWithLegend', {static: false}) networkWithLegendEl: ElementRef;
+  @ViewChild('networkWithLegend', { static: false }) networkWithLegendEl: ElementRef;
   @Input() token: string | null = null;
   @Input()
   public set config(config: IConfig | undefined) {
@@ -80,7 +80,7 @@ export class AnalysisPanelComponent implements OnInit, OnChanges, AfterViewInit
   public myConfig: IConfig = JSON.parse(JSON.stringify(defaultConfig));
 
   public network: any;
-  public nodeData: { nodes: any, edges: any } = {nodes: null, edges: null};
+  public nodeData: { nodes: any, edges: any } = { nodes: null, edges: null };
   private drugNodes: any[] = [];
   private drugEdges: any[] = [];
   public showDrugs = false;
@@ -180,14 +180,14 @@ export class AnalysisPanelComponent implements OnInit, OnChanges, AfterViewInit
         this.networkHandler.activeNetwork.seedMap = nodeAttributes.isSeed || {};
 
         // Reset
-        this.nodeData = {nodes: null, edges: null};
+        this.nodeData = { nodes: null, edges: null };
         this.networkHandler.activeNetwork.networkEl.nativeElement.innerHTML = '';
         this.networkHandler.activeNetwork.networkInternal = null;
         this.showDrugs = false;
 
         // Create
-        const {nodes, edges} = this.createNetwork(this.result);
-        this.setInputNetwork.emit({nodes: nodes, edges: edges});
+        const { nodes, edges } = this.createNetwork(this.result);
+        this.setInputNetwork.emit({ nodes: nodes, edges: edges });
         this.nodeData.nodes = new vis.DataSet(nodes);
         this.nodeData.edges = new vis.DataSet(edges);
         const container = this.networkHandler.activeNetwork.networkEl.nativeElement;
@@ -197,12 +197,12 @@ export class AnalysisPanelComponent implements OnInit, OnChanges, AfterViewInit
 
         this.networkHandler.activeNetwork.networkInternal = new vis.Network(container, this.nodeData, options);
 
-        this.tableDrugs = nodes.filter( e => e.drugstoneId && e.drugstoneId.startsWith('d'));
+        this.tableDrugs = nodes.filter(e => e.drugstoneId && e.drugstoneId.startsWith('d'));
         this.tableDrugs.forEach((r) => {
           r.rawScore = r.score;
         });
 
-        this.tableProteins = nodes.filter( e => e.drugstoneId && e.drugstoneId.startsWith('p'));
+        this.tableProteins = nodes.filter(e => e.drugstoneId && e.drugstoneId.startsWith('p'));
         this.tableSelectedProteins = [];
         this.tableProteins.forEach((r) => {
           r.rawScore = r.score;
@@ -273,14 +273,14 @@ export class AnalysisPanelComponent implements OnInit, OnChanges, AfterViewInit
               node.x = pos[item.id].x;
               node.y = pos[item.id].y;
               const isSeed = this.networkHandler.activeNetwork.highlightSeeds ? this.networkHandler.activeNetwork.seedMap[node.id] : false;
-              const gradient = (this.networkHandler.activeNetwork.gradientMap !== {}) && (this.networkHandler.activeNetwork.gradientMap[item.id]) ? this.networkHandler.activeNetwork.gradientMap[item.id] : 1.0;
               const nodeStyled = NetworkSettings.getNodeStyle(
                 node,
                 this.myConfig,
                 isSeed,
                 selected,
-                gradient
-                )
+                this.networkHandler.activeNetwork.getGradient(item.id),
+                this.networkHandler.activeNetwork.nodeRenderer
+              )
               updatedNodes.push(nodeStyled);
             }
             this.nodeData.nodes.update(updatedNodes);
@@ -311,14 +311,14 @@ export class AnalysisPanelComponent implements OnInit, OnChanges, AfterViewInit
               //   drugInTrial = node.inTrial;
               // }
               const isSeed = this.networkHandler.activeNetwork.highlightSeeds ? this.networkHandler.activeNetwork.seedMap[node.id] : false;
-              const gradient = (this.networkHandler.activeNetwork.gradientMap !== {}) && (this.networkHandler.activeNetwork.gradientMap[node.id]) ? this.networkHandler.activeNetwork.gradientMap[node.id] : 1.0;
               const nodeStyled = NetworkSettings.getNodeStyle(
                 node,
                 this.myConfig,
                 isSeed,
                 selected,
-                gradient
-                )
+                this.networkHandler.activeNetwork.getGradient(node.id),
+                this.networkHandler.activeNetwork.nodeRenderer
+              )
               updatedNodes.push(nodeStyled);
             });
             this.nodeData.nodes.update(updatedNodes);
@@ -531,7 +531,7 @@ export class AnalysisPanelComponent implements OnInit, OnChanges, AfterViewInit
   public createNetwork(result: any): { edges: any[], nodes: any[] } {
     const config = result.parameters.config;
     this.myConfig = config;
-    
+
     const identifier = this.myConfig.identifier;
 
     // add drugGroup and foundNodesGroup for added nodes
@@ -572,7 +572,7 @@ export class AnalysisPanelComponent implements OnInit, OnChanges, AfterViewInit
       }
       // 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, false, 1))
+      nodes.push(NetworkSettings.getNodeStyle(nodeDetails as Node, config, false, false, 1, this.networkHandler.activeNetwork.nodeRenderer))
     }
 
     // remove self-edges/loops
diff --git a/src/app/components/network/network.component.ts b/src/app/components/network/network.component.ts
index 529f5fcc..df290410 100644
--- a/src/app/components/network/network.component.ts
+++ b/src/app/components/network/network.component.ts
@@ -79,6 +79,8 @@ export class NetworkComponent implements OnInit {
 
   public fullscreen = false;
 
+  public nodeRenderer = null;
+
   constructor(public networkHandler: NetworkHandlerService, public analysis: AnalysisService, public drugstoneConfig: DrugstoneConfigService, public netex: NetexControllerService, public omnipath: OmnipathControllerService) { }
 
   ngOnInit(): void {
@@ -267,7 +269,12 @@ export class NetworkComponent implements OnInit {
   public selectTissue(tissue: Tissue | null) {
     this.expressionExpanded = false;
     if (!tissue) {
+      // delete expression values
+      this.expressionMap = {};
+      // delete gradient map
+      this.gradientMap = {};
       this.selectedTissue = null;
+      this.nodeRenderer = null;
       const updatedNodes = [];
       // for (const item of this.proteins) {
       for (const item of this.currentViewProteins) {
@@ -289,14 +296,14 @@ export class NetworkComponent implements OnInit {
             this.drugstoneConfig.config,
             false,
             this.analysis.inSelection(getWrapperFromNode(item)),
-            1.0
+            1.0,
+            this.nodeRenderer
           )
         )
         updatedNodes.push(node);
       }
       this.nodeData.nodes.update(updatedNodes);
-      // delete expression values
-      this.expressionMap = undefined;
+
     } else {
       this.selectedTissue = tissue
       const minExp = 0.3;
@@ -310,6 +317,7 @@ export class NetworkComponent implements OnInit {
       this.netex.tissueExpressionGenes(this.selectedTissue, proteinNodes).subscribe((response) => {
         this.expressionMap = response;
         const updatedNodes = [];
+        this.nodeRenderer = pieChartContextRenderer;
         // mapping from netex IDs to network IDs, TODO check if this step is necessary
         const networkIdMappping = {}
         this.nodeData.nodes.forEach(element => {
@@ -324,6 +332,7 @@ export class NetworkComponent implements OnInit {
           }
           const wrapper = getWrapperFromNode(node)
           const gradient = expressionlvl !== null ? (Math.pow(expressionlvl / maxExpr, 1 / 3) * (1 - minExp) + minExp) : -1;
+          this.gradientMap[drugstoneId] = gradient;
           const pos = this.networkInternal.getPositions([networkId]);
           node.x = pos[networkId].x;
           node.y = pos[networkId].y;
@@ -333,11 +342,10 @@ export class NetworkComponent implements OnInit {
               this.drugstoneConfig.config,
               node.isSeed,
               this.analysis.inSelection(wrapper),
-              gradient));
-
-          // custom ctx renderer for pie chart
-          node.shape = 'custom';
-          node.ctxRenderer = pieChartContextRenderer;
+              gradient,
+              this.nodeRenderer
+            )
+          );
           updatedNodes.push(node);
         }
         this.nodeData.nodes.update(updatedNodes);
@@ -368,6 +376,10 @@ export class NetworkComponent implements OnInit {
     }
   }
 
+  public getGradient(nodeId: string) {
+    return (this.gradientMap !== {}) && (this.gradientMap[nodeId]) ? this.gradientMap[nodeId] : 1.0;
+  }
+
   /**
    * To highlight the seeds in the analysis network, not used in the browser network
    * @param bool
@@ -388,7 +400,6 @@ export class NetworkComponent implements OnInit {
       node.x = pos[item.id].x;
       node.y = pos[item.id].y;
       const isSeed = this.highlightSeeds ? this.seedMap[node.id] : false;
-      const gradient = (this.gradientMap !== {}) && (this.gradientMap[item.id]) ? this.gradientMap[item.id] : 1.0;
       Object.assign(
         node,
         NetworkSettings.getNodeStyle(
@@ -396,7 +407,8 @@ export class NetworkComponent implements OnInit {
           this.drugstoneConfig.config,
           isSeed,
           this.analysis.inSelection(getWrapperFromNode(item)),
-          gradient
+          this.getGradient(item.id),
+          this.nodeRenderer
         )
       )
       updatedNodes.push(node);
diff --git a/src/app/config.ts b/src/app/config.ts
index 8529a7f1..13229016 100644
--- a/src/app/config.ts
+++ b/src/app/config.ts
@@ -13,6 +13,7 @@ export interface NodeGroup {
   borderWidthSelected?: number;
   background?: any;
   shadow?: any;
+  ctxRenderer?: any;
 }
 
 export interface EdgeGroup {
@@ -132,6 +133,7 @@ export const defaultConfig: IConfig = {
       // 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',
+      ctxRenderer: null,
       color: {
         border: '#FFFF00',
         background: '#FFFF00',
diff --git a/src/app/interfaces.ts b/src/app/interfaces.ts
index 59daa8bf..8f5eacee 100644
--- a/src/app/interfaces.ts
+++ b/src/app/interfaces.ts
@@ -1,6 +1,7 @@
 import {AlgorithmType, QuickAlgorithmType} from './services/analysis/analysis.service';
 
 export interface Node {
+  ctxRenderer?: any;
   label: string;
   symbol: string;
   id: string;
diff --git a/src/app/network-settings.ts b/src/app/network-settings.ts
index b8e1ae85..38881ef2 100644
--- a/src/app/network-settings.ts
+++ b/src/app/network-settings.ts
@@ -59,15 +59,6 @@ export class NetworkSettings {
     enabled: false
   };
 
-  // Node size
-  private static hostSize = 20;
-  private static drugSize = 15;
-
-  // Node shape
-  private static hostShape = 'ellipse';
-  private static drugNotInTrialShape = 'box';
-  private static drugInTrialShape = 'triangle';
-
   static getOptions(network: 'main' | 'analysis' | 'analysis-big', physicsOn) {
     if (network === 'main') {
       return {
@@ -90,43 +81,16 @@ export class NetworkSettings {
     }
   }
 
-  static getColor(color: 'protein' | 'approvedDrug' | 'unapprovedDrug' | 'hostFont' | 'drugFont' |
-    'nonSeedHost' | 'selectedForAnalysis' | 'selectedForAnalysisText' |
-    'edgeHostDrug' | 'edgeHostDrugHighlight' | 'edgeGeneGene' | 'edgeGeneGeneHighlight')
-    /**
-     * Collection of all colors per use-case
-     */ {
-    if (color === 'protein') {
-      return this.hostColor;
-    } else if (color === 'approvedDrug') {
-      return this.approvedDrugColor;
-    } else if (color === 'unapprovedDrug') {
-      return this.unapprovedDrugColor;
-    } else if (color === 'hostFont') {
-      return this.hostFontColor;
-    } else if (color === 'drugFont') {
-      return this.drugFontColor;
-    } else if (color === 'nonSeedHost') {
-      return this.nonSeedHostColor;
-    } else if (color === 'edgeHostDrug') {
-      return this.edgeHostDrugColor;
-    } else if (color === 'edgeHostDrugHighlight') {
-      return this.edgeHostDrugHighlightColor;
-    } else if (color === 'edgeGeneGene') {
-      return this.edgeGeneGeneColor;
-    } else if (color === 'edgeGeneGeneHighlight') {
-      return this.edgeGeneGeneHighlightColor;
-    }
-  }
-
   static getNodeStyle(
     node: Node,
     config: IConfig,
     isSeed: boolean,
     isSelected: boolean,
-    gradient: number = 1): Node {
+    gradient: number = 1,
+    renderer = null): Node {
     // delete possible old styles
     Object.keys(config.nodeGroups.default).forEach(e => delete node[e]);
+
     // set group styles
     if (node.group === 'default') {
       node = merge(node, config.nodeGroups.default);
@@ -135,7 +99,7 @@ export class NetworkSettings {
     }
 
     // note that seed and selected node style are applied after the node style is fetched.
-    // this allows to overwrite only attributes of interest, therefor in e.g. seedNode group
+    // this allows to overwrite only attributes of interest, therefore in e.g. seedNode group
     // certain attributes like shape can remain undefined
     // use lodash merge to not lose deep attributes, e.g. "font.size"
     if (isSeed) {
@@ -147,18 +111,21 @@ export class NetworkSettings {
       // apply selected node style to node
       node = merge(node, config.nodeGroups.selectedNode);
     }
-
     // show image if image url is given. If seed nodes are highlighted, ignore image property
     if (node.image && !isSeed) {
       node.shape = 'image';
     }
-
     // use opactiy as gradient
     if (gradient === null) {
       node.opacity = 0
     } else {
       node.opacity = gradient
     }
+    // custom ctx renderer for e.g. pie chart
+    if (renderer !== null) {
+      node.shape = 'custom';
+      node.ctxRenderer = renderer;
+    }
     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 ecd333c4..2a83f988 100644
--- a/src/app/pages/explorer-page/explorer-page.component.ts
+++ b/src/app/pages/explorer-page/explorer-page.component.ts
@@ -146,7 +146,8 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit {
             this.drugstoneConfig.config,
             false,
             selected,
-            1.0
+            this.networkHandler.activeNetwork.getGradient(wrapper.id),
+            this.networkHandler.activeNetwork.nodeRenderer
           )
           nodeStyled.x = pos[wrapper.id].x;
           nodeStyled.y = pos[wrapper.id].y;
diff --git a/src/app/utils.ts b/src/app/utils.ts
index c81884d5..c7116154 100644
--- a/src/app/utils.ts
+++ b/src/app/utils.ts
@@ -162,7 +162,6 @@ export function pieChartContextRenderer({ctx, x, y, state: {selected, hover}, st
 
   ctx.drawPie = function (style, x, y) {
     const total = 1;
-
     // draw shadow
     if (style.shadow) {
       ctx.save()
@@ -183,7 +182,6 @@ export function pieChartContextRenderer({ctx, x, y, state: {selected, hover}, st
     // prepare pi-chart
     ctx.fillStyle = style.color ? style.color : 'rgba(255, 0, 0, 1)';
     // set alpha value to 1
-    // ctx.fillStyle = ctx.fillStyle.replace(/[^,]+(?=\))/, '1')
     ctx.fillStyle = RGBAtoRGB(ctx.fillStyle)
     ctx.beginPath();
     ctx.moveTo(x, y);
@@ -195,7 +193,7 @@ export function pieChartContextRenderer({ctx, x, y, state: {selected, hover}, st
       // removing shadow application of future fill or stroke calls
       ctx.restore();
     }
-    ctx.strokeStyle = "black";
+    ctx.strokeStyle = style.borderColor ? style.borderColor : 'black';
     ctx.lineWidth = selected ? 3 : 2;
     if (style.opacity !== total) {
       // avoid the inner line when circle is complete
@@ -205,6 +203,7 @@ export function pieChartContextRenderer({ctx, x, y, state: {selected, hover}, st
     // draw the surrounding border circle
     ctx.beginPath();
     ctx.arc(x, y, style.size, 0, 2 * Math.PI);
+    ctx.strokeStyle = style.borderColor ? style.borderColor : 'black';
     ctx.stroke();
   }
 
diff --git a/src/index.html b/src/index.html
index 668db0dd..3a24b363 100644
--- a/src/index.html
+++ b/src/index.html
@@ -49,31 +49,9 @@
 
   <drugst-one id="netexp1"
               pluginId="2"
-              config='{"nodeGroups":{
-                "proteinCoding":{"type":"gene","color":{background:"#116466",border:"#000000"} ,"font":{"color":"#000000"},"borderWidth":2,"groupName":"gene","shape":"square", "id":"proteinCoding"},
-                "up":{"type":"gene","color":{background:"#FC6566",border:"#000000"},"font":{"color":"#000000"},"borderWidth":2,"groupName":"up-regulated gene","shape":"square","id":"up"},
-                "down":{"type":"gene","color":{background:"#1158E9",border:"#000000"},"font":{"color":"#000000"},"borderWidth":2,"groupName":"down-regulated gene","shape":"square","id":"down"},
-                "unchanged":{"type":"gene","color":{background:"#A0B89D",border:"#000000"},"font":{"color":"#000000"},"borderWidth":2,"groupName":"unchanged gene","shape":"square","id":"unchanged"},
-                "metMeta":{"type":"metabolite","color":{background:"#E8A87C",border:"#000000"},"font":{"color":"#000000"},"borderWidth":2,"groupName":"metabolite","shape":"dot","id":"metMeta"},
-                "trait":{"type":"trait","color":"#B4CADB","font":{"color":"#000000"},"groupName":"trait","shape":"ellipse","id":"trait"},
-                "traitMeta":{"type":"trait","color":"#8c3d37","font":{"color":"#000000"},"groupName":"traitMeta","shape":"star","id":"traitMeta"},
-                "foundDrug":{"type":"drug","color":"#B186B4","font":{"color":"#000000"},"groupName":"drug","shape":"diamond"},
-                "defaultDisorder":{"type":"disorder","color":"#F0E48C","font":{"color":"#000000"},"groupName":"disorder","shape":"triangle"}
-              },
-                "edgeGroups":{
-              "GENETIC_ASSOCIATION":{"type":"GENETIC_ASSOCIATION", "groupName":"mQTL","color":"#A9A9A9","dashes":false,"arrowStrikethrough":false},
-              "GENETIC_TRAIT_ASSOCIATION":{"type":"GENETIC_TRAIT_ASSOCIATION","groupName":"mQTL","color":"#b4cadb33","dashes":false,"arrowStrikethrough":false},
-              "COABUNDANCE":{"type":"COABUNDANCE","groupName":"coabundance","color":"#5a735a","dashes":false,"arrowStrikethrough":false}, 
-              "METABOLIC_ASSOCIATION":{"type":"METABOLIC_ASSOCIATION","groupName":"traitQTL/mWAS","color":"#b4cadb33","dashes":false,"arrowStrikethrough":false},
-              "COREGULATION":{"type":"COREGULATION","groupName":"coregulation","color":"#1db81d","dashes":false,"arrowStrikethrough":false},
-              "PARTIAL_CORRELATION":{"type":"PARTIAL_CORRELATION","groupName":"partial correlation","color":"#FFC31E","dashes":false,"arrowStrikethrough":false},
-              "COEXPRESSION":{"type":"COEXPRESSION","groupName":"coexpression","color":"#82B81D","dashes":false,"arrowStrikethrough":false}},
-              "identifier":"symbol","title":"Drugst.one network","sidebarPos":"right","showOverview":true,"nodeShadow":false,"edgeShadow":false,"showLegend":true,
-              "showFooter":true, "showSimpleAnalysis":true,"showAdvAnalysis":true,"showSelection":true,
-              "autofillEdges":false,"physicsOn":true}'
-   network='{"nodes": [{"type": "gene", "id": "ZNF235", "group": "proteinCoding", "shape": "circle", "label": "ZNF235", "x": 45.1427, "y": 183.494915, "value": 43}, {"type": "gene", "color": {"background": "#116466", "border": "#000000"}, "font": {"color": "#000000"}, "border_width": 2, "shape": "square", "id": "CEACAM16", "border_width_selected": 0, "shadow": false, "group": "proteinCoding", "label": "CEACAM16", "x": -257.39927, "y": 500, "value": 39, "scaling.min": 2, "scaling.max": 54, "physics": false}],
-   "edges":[{"from":"ZNF235","to":"ZNF235"}]
-  }'>
+              config='{"nodeGroups":{"patient":{"type":"patient","color":"#000000","font":{"color":"#000000"},"groupName":"Patient","shape":"image","image":"https://static.thenounproject.com/png/22780-200.png"},"condition":{"type":"condition","color":"#000000","font":{"color":"#000000"},"groupName":"Condition","shape":"text"},"important":{"type":"gene","color":"#ff881f","font":{"color":"#000000"},"groupName":"Important Gene","shape":"star"},"gene":{"type":"gene","color":"#4da300","font":{"color":"#f0f0f0"},"groupName":"Gene","shape":"circle"},"foundDrug":{"type":"drug","color":"#F12590","font":{"color":"#000000"},"groupName":"Drug","shape":"diamond"}},"edgeGroups":{"genotype":{"color":"#000000","groupName":"Relevant Gene"},"has-condition":{"color":"#000000","groupName":"Has Condition","dashes":[2,2]},"default":{"color":"#000000","groupName":"default edge"},"ggi":{"color":"#000000","groupName":"Interaction","dashes":[3,2]}},"identifier":"symbol","title":"Breast cancer example network","nodeShadow":true,"edgeShadow":false,"autofillEdges":false,"showLegend":true}'
+   network='{"nodes":[{"id":"patient-1","group":"patient","x":592,"y":446},{"id":"patient-2","group":"patient","x":235,"y":87},{"id":"patient-3","group":"patient","x":105,"y":369},{"id":"ATM","label":"ATM","group":"gene","x":289,"y":242},{"id":"BARD1","label":"BARD1","group":"gene","x":44,"y":250},{"id":"BRCA1","label":"BRCA1","group":"gene","x":466,"y":576},{"id":"BRCA2","label":"BRCA2","group":"gene","x":507,"y":285},{"id":"BRIP1","label":"BRIP1","group":"gene","x":54,"y":474},{"id":"CHEK2","label":"CHEK2","group":"gene","x":216,"y":590},{"id":"CDH1","label":"CDH1","group":"gene","x":320,"y":-57},{"id":"NF1","label":"NF1","group":"gene","x":481,"y":111},{"id":"NBN","label":"NBN","group":"gene","x":-57,"y":314},{"id":"PALB2","label":"PALB2","group":"gene","x":450,"y":190},{"id":"PTEN","label":"PTEN","group":"important","x":305,"y":494},{"id":"RAD51C","label":"RAD51C","group":"gene","x":182,"y":-90},{"id":"RAD51D","label":"RAD51D","group":"gene","x":368,"y":73},{"id":"STK11","label":"STK11","group":"gene","x":686,"y":330},{"id":"TP53","label":"TP53","group":"important","x":333,"y":316},{"id":"subtype-1","label":"Subtype 1","group":"condition","x":556,"y":171},{"id":"subtype-2","label":"Subtype 2","group":"condition","x":-87,"y":221}],"edges":[{"from":"BRCA1","to":"BRCA2","group":"ggi"},{"from":"ATM","to":"BARD1","group":"ggi"},{"from":"BRCA1","to":"CHEK2","group":"ggi"},{"from":"RAD51C","to":"RAD51D","group":"ggi"},{"from":"STK11","to":"TP53","group":"ggi"},{"from":"TP53","to":"PALB2","group":"ggi"},{"from":"TP53","to":"RAD51D","group":"ggi"},{"from":"TP53","to":"NF1","group":"ggi"},{"from":"TP53","to":"BRCA1","group":"ggi"},{"from":"TP53","to":"BRCA2","group":"ggi"},{"from":"PTEN","to":"BRCA1","group":"ggi"},{"from":"PTEN","to":"BRCA2","group":"ggi"},{"from":"TP53","to":"PTEN","group":"ggi"},{"from":"ATM","to":"PTEN","group":"ggi"},{"from":"CDH1","to":"RAD51D","group":"ggi"},{"from":"CDH1","to":"PALB2","group":"ggi"},{"from":"NBN","to":"BRIP1","group":"ggi"},{"from":"BRIP1","to":"PTEN","group":"ggi"},{"from":"patient-1","to":"BRCA1","group":"genotype"},{"from":"patient-1","to":"TP53","group":"genotype"},{"from":"patient-1","to":"BRCA2","group":"genotype"},{"from":"patient-1","to":"PTEN","group":"genotype"},{"from":"patient-2","to":"TP53","group":"genotype"},{"from":"patient-2","to":"NF1","group":"genotype"},{"from":"patient-2","to":"BARD1","group":"genotype"},{"from":"patient-3","to":"TP53","group":"genotype"},{"from":"patient-3","to":"PTEN","group":"genotype"},{"from":"patient-3","to":"NBN","group":"genotype"},{"from":"patient-1","to":"subtype-1","group":"has-condition"},{"from":"patient-2","to":"subtype-1","group":"has-condition"},{"from":"patient-3","to":"subtype-2","group":"has-condition"}]}'
+   >
 </drugst-one>
 </div>
 
-- 
GitLab