diff --git a/src/app/components/analysis-panel/analysis-panel.component.ts b/src/app/components/analysis-panel/analysis-panel.component.ts index 77150c24efa9af906e78f3f4bedf01c6b7050f9b..d353ebf5ddb4e5aae92794c3b76cb19e701945c9 100644 --- a/src/app/components/analysis-panel/analysis-panel.component.ts +++ b/src/app/components/analysis-panel/analysis-panel.component.ts @@ -30,6 +30,8 @@ import html2canvas from 'html2canvas'; import {toast} from 'bulma-toast'; import {NetworkSettings} from '../../network-settings'; import { NetexControllerService } from 'src/app/services/netex-controller/netex-controller.service'; +import { IConfig } from 'src/app/config'; +import { config } from 'rxjs'; declare var vis: any; @@ -137,7 +139,7 @@ export class AnalysisPanelComponent implements OnInit, OnChanges { } if (this.task && this.task.info.done) { - const result = await this.netex.getTaskResult(this.token) + const result = await this.netex.getTaskResult(this.token); console.log(result) const nodeAttributes = result.nodeAttributes || {}; const isSeed: { [key: string]: boolean } = nodeAttributes.isSeed || {}; @@ -358,21 +360,35 @@ export class AnalysisPanelComponent implements OnInit, OnChanges { return `${environment.backend}graph_export/?token=${this.token}`; } - public inferEdgeType(edge: object): EdgeType { + public inferEdgeGroup(edge: object): EdgeType { if (edge['to'].startsWith('d')) { return 'protein-drug'; } return 'protein-protein'; } - public inferNodeType(nodeId: string): WrapperType { - if (nodeId.startsWith('d')) { + /** + * Infers wrapper type of node returned from backend. + * Node can only be either an input node from the user with a defined group, + * a drug found in the backend with either user defined type or default drug group, + * or an intermediate protein added by the shortest path to the found drug. + * For the third case, fall back to a default case which can also be set by user. + */ + public inferNodeGroup(wrapper: Wrapper): string { + if (wrapper.data.group !== undefined) { + return wrapper.data.group + } + else if (wrapper.data.netexId !== undefined && wrapper.data.netexId.startsWith('d')) { return 'drug'; } - return 'protein'; + else if (wrapper.data.netexId !== undefined && wrapper.data.netexId.startsWith('p')) { + return 'protein'; + } } public createNetwork(result: any): { edges: any[], nodes: any[] } { + const config = result.parameters.config; + const nodes = []; const edges = []; @@ -396,11 +412,10 @@ export class AnalysisPanelComponent implements OnInit, OnChanges { } else if (nodeTypes[nodeObjectKey] === 'drug') { wrappers[node] = getWrapperFromDrug(details[nodeObjectKey]); } - - nodes.push(this.mapNode(this.inferNodeType(node), wrappers[node], isSeed[nodeObjectKey], scores[nodeObjectKey])); + nodes.push(this.mapNode(config, wrappers[node], isSeed[nodeObjectKey], scores[nodeObjectKey])); } for (const edge of network.edges) { - edges.push(this.mapEdge(edge, this.inferEdgeType(edge), wrappers)); + edges.push(this.mapEdge(edge, this.inferEdgeGroup(edge), wrappers)); } return { nodes, @@ -408,11 +423,18 @@ export class AnalysisPanelComponent implements OnInit, OnChanges { }; } - private mapNode(nodeType: WrapperType, wrapper: Wrapper, isSeed?: boolean, score?: number): any { - const node = NetworkSettings.getNodeStyle('protein', isSeed, this.analysis.inSelection(wrapper)); + private mapNode(config: IConfig, wrapper: Wrapper, isSeed?: boolean, score?: number): any { + // const node = NetworkSettings.getNodeStyle(nodeType, isSeed, this.analysis.inSelection(wrapper)); + console.log(wrapper) + let group = this.inferNodeGroup(wrapper); + if (typeof group === 'undefined' || typeof config.nodeGroups[group] === 'undefined') { + group = 'default'; + } + console.log(group) + const node = JSON.parse(JSON.stringify(config.nodeGroups[group])); node.id = wrapper.id; node.label = wrapper.data.name; - node.nodeType = nodeType; + node.nodeType = group; node.isSeed = isSeed; node.wrapper = wrapper; return node; @@ -481,9 +503,9 @@ export class AnalysisPanelComponent implements OnInit, OnChanges { animate: {in: 'fadeIn', out: 'fadeOut'} }); } else { - for (const drug of drugs) { - this.drugNodes.push(this.mapNode('drug', drug, false, null)); - } + // for (const drug of drugs) { + // this.drugNodes.push(this.mapNode(config, 'drug', drug, false, null)); + // } for (const interaction of edges) { console.log(interaction) diff --git a/src/app/components/info-tile/info-tile.component.html b/src/app/components/info-tile/info-tile.component.html index 24b6ca4e871d6e3ae9febd460ccc2ad160c848a9..8e6fbef571a361a5f026b875d0a709950677b0e0 100644 --- a/src/app/components/info-tile/info-tile.component.html +++ b/src/app/components/info-tile/info-tile.component.html @@ -8,6 +8,12 @@ <b><span>Type:</span></b> <span class="is-capitalized"> {{ wrapper.type }}</span> </p> + <p *ngIf="wrapper.data.drugId" [ngClass]="{'text-normal':smallStyle}"> + <b><span>DrugBank:</span></b> + <a href="https://go.drugbank.com/drugs/{{ wrapper.data.drugId }}" target="_blank"> + <span class="is-capitalized"> {{ wrapper.data.drugId }}</span> + </a> + </p> <p *ngIf="wrapper.data.group" [ngClass]="{'text-normal':smallStyle}"> <b><span>Group:</span></b> <span class="is-capitalized"> {{ wrapper.data.group }}</span> @@ -21,7 +27,9 @@ </div> - <app-toggle [value]="analysis.inSelection(wrapper)" [smallStyle]="smallStyle" + <app-toggle + *ngIf="wrapper.type !== 'drug'" + [value]="analysis.inSelection(wrapper)" [smallStyle]="smallStyle" (valueChange)="$event ? analysis.addItems([wrapper]) : analysis.removeItems([wrapper])" textOn="Selected" textOff="Deselected" tooltipOn="Add protein to selection." tooltipOff="Remove protein from selection."></app-toggle> </div> diff --git a/src/app/main-network.ts b/src/app/main-network.ts index 27e2f2032ec316ee8c041be6a90f699243b4b867..1d827e18ed46984e948a407034086d9acf1c1511 100644 --- a/src/app/main-network.ts +++ b/src/app/main-network.ts @@ -1,4 +1,5 @@ import {HttpClient} from '@angular/common/http'; +import { IConfig } from './config'; import {NodeInteraction, Node, getProteinNodeId} from './interfaces'; export function getDatasetFilename(dataset: Array<[string, string]>): string { @@ -39,4 +40,76 @@ export class ProteinNetwork { }); } + /** Maps user input node to network node object + * + * @param customNode + * @param config + * @returns + */ + private mapCustomNode(customNode: any, config: IConfig): Node { + let group = customNode.group; + if (typeof group === 'undefined' || typeof config.nodeGroups[group] === 'undefined') { + group = 'default'; + } + const node = JSON.parse(JSON.stringify(config.nodeGroups[group])); + + // label is only used for network visualization + let nodeLabel = customNode.name; + if (customNode.name.length === 0) { + nodeLabel = customNode.userId; + } + + // node.name is actually group name since it comes from the group configuration + // this property is already stored in the wrapper object + // instead, node.name should reflect the actual node name + node.name = customNode.name; + + if (node.image) { + node.shape = 'image'; + } + node.label = nodeLabel; + node.id = customNode.id; + node.x = customNode.x; + node.y = customNode.y; + node.uniprotAc = customNode.uniprotAc; + node.netexId = customNode.netexId; + // console.log(node) + return node; + } + + /** Maps user input edge to network edge object + * + * @param customEdge + * @param config + * @returns + */ + private mapCustomEdge(customEdge: NodeInteraction, config: IConfig): any { + let group = customEdge.group; + if (typeof group === 'undefined' || typeof config.edgeGroups[group] === 'undefined') { + group = 'default'; + } + const edge = JSON.parse(JSON.stringify(config.edgeGroups[group])); + edge.from = customEdge.from; + edge.to = customEdge.to; + return edge; + } + + public mapDataToNodes(config: IConfig): { nodes: any[], edges: any[]; } { + const nodes = []; + const edges = []; + + for (const protein of this.proteins) { + nodes.push(this.mapCustomNode(protein, config)); + } + + for (const edge of this.edges) { + edges.push(this.mapCustomEdge(edge, config)); + } + + return { + nodes, + edges, + }; + } + } diff --git a/src/app/pages/explorer-page/explorer-page.component.ts b/src/app/pages/explorer-page/explorer-page.component.ts index b25104090f84e1bc855e05de24e2944dea6699c0..4dbbdb5c3fa4328729c49f9533971cfd155a159a 100644 --- a/src/app/pages/explorer-page/explorer-page.component.ts +++ b/src/app/pages/explorer-page/explorer-page.component.ts @@ -73,8 +73,6 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit { // extend main column document.getElementById('main-column').classList.add('rightgone'); } - - } this.myConfig[key] = configObj[key]; @@ -267,7 +265,7 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit { this.proteinData = new ProteinNetwork(this.proteins, this.edges); this.proteinData.linkNodes(); - const {nodes, edges} = this.mapDataToNodes(this.proteinData); + const {nodes, edges} = this.proteinData.mapDataToNodes(this.myConfig); this.nodeData.nodes = new vis.DataSet(nodes); this.nodeData.edges = new vis.DataSet(edges); @@ -348,71 +346,6 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit { this.myConfig[key] = {...this.myConfig[key], ...values}; } - /** Convert input nodes into node objects - * - * @param customNode - * @returns - */ - private mapCustomNode(customNode: any): Node { - let group = customNode.group; - if (typeof group === 'undefined' || typeof this.myConfig.nodeGroups[group] === 'undefined') { - group = 'default'; - } - const node = JSON.parse(JSON.stringify(this.myConfig.nodeGroups[group])); - - // label is only used for network visualization - let nodeLabel = customNode.name; - if (customNode.name.length === 0) { - nodeLabel = customNode.userId; - } - - // node.name is actually group name since it comes from the group configuration - // this property is already stored in the wrapper object - // instead, node.name should reflect the actual node name - node.name = customNode.name; - - if (node.image) { - node.shape = 'image'; - } - node.label = nodeLabel; - node.id = customNode.id; - node.x = customNode.x; - node.y = customNode.y; - node.uniprotAc = customNode.uniprotAc; - node.netexId = customNode.netexId; - // console.log(node) - return node; - } - - private mapCustomEdge(customEdge: NodeInteraction): any { - let group = customEdge.group; - if (typeof group === 'undefined' || typeof this.myConfig.edgeGroups[group] === 'undefined') { - group = 'default'; - } - const edge = JSON.parse(JSON.stringify(this.myConfig.edgeGroups[group])); - edge.from = customEdge.from; - edge.to = customEdge.to; - return edge; - } - - private mapDataToNodes(data: ProteinNetwork): { nodes: any[], edges: any[]; } { - const nodes = []; - const edges = []; - - for (const protein of data.proteins) { - nodes.push(this.mapCustomNode(protein)); - } - - for (const edge of data.edges) { - edges.push(this.mapCustomEdge(edge)); - } - - return { - nodes, - edges, - }; - } - public toCanvas() { html2canvas(this.networkEl.nativeElement).then((canvas) => { const generatedImage = canvas.toDataURL('image/png').replace('image/png', 'image/octet-stream');