diff --git a/src/app/components/analysis-panel/analysis-panel.component.ts b/src/app/components/analysis-panel/analysis-panel.component.ts index 014a3a460d31f214b3c9e279b9aa5eea3736050f..4e24e2034f5cd19ed73dbcb4f933ce16c7a3deee 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 e9eeb21b09415392373bd72f87ae75dc1bdea297..b71bb12594868e2e81bd2259e873054e32d7ec04 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> {{ 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> {{ 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> {{ 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> {{ 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 b3e9079ac52cd11dd1eeb28a9a995d7cde86c19e..28c4281444b378900d7433946ada165b9d31c128 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 30a2b025cc81209abd80f3a854dd43675286df14..f20b9ff9739eb66dee4142f418a34eaae710dbf3 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 dc1d4ab20c78652dffb3b79188d0531d014cc60a..b2e3a5336b28bf4fa523d1cc98252c387bcd3877 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 11673307e8a43a34d21c55c3ffae1f7689fcdbe8..3ba80fc8d1643c35ba844f51dbf05523b70eda1e 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 c1444667ca5df6cd5a67edcbfd1edfb8e45bfbb4..9a035ddc6ec38dde455c1588779d88eeb56f97cd 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 12084608f160d5ec60e8d9857f62457b085526f1..c4606ac37466807ddd3b76984241e383b9df0549 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 e18bfa5487c728555b5d5a3810e726fdac07cd49..cde11c0601527bd7dd8ac977fa9d2d2898fe1a13 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 3d79ea68ac46f53c1deadefd38bdf6b02e124bf7..6497399db514498e3281600d8dcc00b846fd1962 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 997b419ab7961c18854fcebdd175e4412b2333df..d390a7910bbb8745058edcfd4a2e29051dc34fb9 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"}