From b444945dd13a8aedd3465fc0092c47964b76f467 Mon Sep 17 00:00:00 2001 From: Michael Hartung <michi@Michaels-MacBook-Pro.local> Date: Mon, 12 Jul 2021 19:44:58 +0200 Subject: [PATCH] fix dashed legend when colored background; node analysis style half fixed; default nodes style huge somehwoe --- .../analysis-panel.component.ts | 77 ++++++++----------- .../network-legend.component.scss | 1 + src/app/config.ts | 10 +-- src/app/interfaces.ts | 1 + src/app/main-network.ts | 14 ---- src/app/network-settings.ts | 5 +- .../explorer-page.component.html | 9 ++- .../explorer-page/explorer-page.component.ts | 46 +++++++---- src/index.html | 4 +- src/styles.scss | 7 +- 10 files changed, 85 insertions(+), 89 deletions(-) diff --git a/src/app/components/analysis-panel/analysis-panel.component.ts b/src/app/components/analysis-panel/analysis-panel.component.ts index 164b6a36..58746d63 100644 --- a/src/app/components/analysis-panel/analysis-panel.component.ts +++ b/src/app/components/analysis-panel/analysis-panel.component.ts @@ -214,10 +214,11 @@ export class AnalysisPanelComponent implements OnInit, OnChanges { if (nodeIds.length > 0) { const nodeId = nodeIds[0]; const node = this.nodeData.nodes.get(nodeId); - if (node.nodeType === 'drug') { + console.log(node) + if (node.nodeType === 'drug' || node.netexId === undefined || !node.netexId.startsWith('p')) { return; } - const wrapper = node.wrapper; + const wrapper = getWrapperFromNode(node); if (this.analysis.inSelection(wrapper)) { this.analysis.removeItems([wrapper]); this.analysis.getCount(); @@ -231,17 +232,20 @@ export class AnalysisPanelComponent implements OnInit, OnChanges { this.network.on('click', (properties) => { const selectedNodes = this.nodeData.nodes.get(properties.nodes); if (selectedNodes.length > 0) { - const selectedNode = selectedNodes[0]; - const wrapper = selectedNode.wrapper; - this.showDetailsChange.emit(wrapper); + this.showDetailsChange.emit(getWrapperFromNode(selectedNodes[0])); } else { this.showDetailsChange.emit(null); } }); this.analysis.subscribeList((items, selected) => { + // return if analysis panel is closed or no nodes are loaded + if (!this.token) { + return; + } + if (selected !== null) { - const updatedNodes = []; + const updatedNodes: Node[] = []; for (const item of items) { const node = this.nodeData.nodes.get(item.id); if (!node) { @@ -250,11 +254,14 @@ 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; - // Object.assign(node, NetworkSettings.getNodeStyle( - // node.wrapper.type, - // node.isSeed, - // selected)); - updatedNodes.push(node); + const nodeStyled = NetworkSettings.getNodeStyle( + node, + this.myConfig, + false, + selected, + 1.0 + ) + updatedNodes.push(nodeStyled); } this.nodeData.nodes.update(updatedNodes); @@ -276,21 +283,20 @@ export class AnalysisPanelComponent implements OnInit, OnChanges { } else { const updatedNodes = []; this.nodeData.nodes.forEach((node) => { - const nodeSelected = this.analysis.idInSelection(node.id); let drugType; let drugInTrial; if (node.wrapper.data.netexId && node.wrapper.data.netexId.startswith('d')) { drugType = node.wrapper.data.status; drugInTrial = node.wrapper.data.inTrial; } - // Object.assign(node, NetworkSettings.getNodeStyle( - // node.wrapper.type, - // node.isSeed, - // nodeSelected, - // drugType, - // drugInTrial, - // node.gradient)); - updatedNodes.push(node); + const nodeStyled = NetworkSettings.getNodeStyle( + node, + this.myConfig, + false, + selected, + 1.0 + ) + updatedNodes.push(nodeStyled); }); this.nodeData.nodes.update(updatedNodes); @@ -426,6 +432,8 @@ export class AnalysisPanelComponent implements OnInit, OnChanges { // add drugGroup and foundNodesGroup for added nodes // these groups can be overwritten by the user + console.log("result") + console.log(result) const nodes = []; const edges = []; @@ -455,7 +463,11 @@ export class AnalysisPanelComponent implements OnInit, OnChanges { // node is custom input from user, could not be mapped to backend protein wrappers[node] = getWrapperFromCustom(details[node]); } - nodes.push(this.mapNode(config, wrappers[node], isSeed[node], scores[node])); + // 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 details[node] as gradient, but sccores are very small + console.log(details[node]) + nodes.push(NetworkSettings.getNodeStyle(wrappers[node].data as Node, config, false, isSeed[node], 1)) } for (const edge of network.edges) { edges.push(this.mapEdge(edge, this.inferEdgeGroup(edge), wrappers)); @@ -466,29 +478,6 @@ export class AnalysisPanelComponent implements OnInit, OnChanges { }; } - /** - * maps node object returned from backend to frontend node, i.e. input to vis.js - * @param config - * @param wrapper - * @param isSeed - * @param score - * @returns - */ - private mapNode(config: IConfig, wrapper: Wrapper, isSeed?: boolean, score?: number): any { - // override group is node is seed - // TODO Move this to extra function - // 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); - node.isSeed = isSeed; - node.wrapper = wrapper; - if (node.image) { - node.shape = 'image'; - } - return node; - } - private mapEdge(edge: any, type: 'protein-protein' | 'protein-drug', wrappers?: { [key: string]: Wrapper }): any { let edgeColor; if (type === 'protein-protein') { diff --git a/src/app/components/network-legend/network-legend.component.scss b/src/app/components/network-legend/network-legend.component.scss index ca7cfadd..01304490 100644 --- a/src/app/components/network-legend/network-legend.component.scss +++ b/src/app/components/network-legend/network-legend.component.scss @@ -122,6 +122,7 @@ div.legend { margin: 0 auto; &.dashes { border-top: dotted; + background-color: transparent; } } diff --git a/src/app/config.ts b/src/app/config.ts index 7b6e0978..ef644117 100644 --- a/src/app/config.ts +++ b/src/app/config.ts @@ -149,15 +149,15 @@ export const defaultConfig: IConfig = { // shape: 'circle', // type: 'seed', color: { - border: '#F8981D', - background: '#F8981D', + border: '#F1111D', + background: '#F1111D', highlight: { - border: '#F8981D', - background: '#F8981D' + border: '#F1111D', + background: '#F1111D' }, }, font: { - color: '#F8981D', + color: '#F1111D', size: 14 } }, diff --git a/src/app/interfaces.ts b/src/app/interfaces.ts index 4871bace..ac8dee3c 100644 --- a/src/app/interfaces.ts +++ b/src/app/interfaces.ts @@ -158,6 +158,7 @@ export function getWrapperFromNode(gene: Node): Wrapper { */ // if node does not have property group, it was found by the analysis gene.group = gene.group ? gene.group : 'foundNode'; + gene.label = gene.label ? gene.label : gene.id return { id: getNetworkId(gene), data: gene, diff --git a/src/app/main-network.ts b/src/app/main-network.ts index 147d1bff..052d040b 100644 --- a/src/app/main-network.ts +++ b/src/app/main-network.ts @@ -68,20 +68,6 @@ export class ProteinNetwork { node = merge(node, customNode) // label is only used for network visualization node.label = customNode.label ? customNode.label : customNode.id; - if (node.image) { - node.shape = 'image'; - } - // if color is set as string, add detail settings - if (typeof node.color === 'string') { - node.color = { - border: node.color, - background: node.color, - highlight: { - border: node.color, - background: node.color - } - } - } return node; } diff --git a/src/app/network-settings.ts b/src/app/network-settings.ts index acdf8bb9..71b6c28b 100644 --- a/src/app/network-settings.ts +++ b/src/app/network-settings.ts @@ -125,8 +125,7 @@ export class NetworkSettings { config: IConfig, isSeed: boolean, isSelected: boolean, - gradient: number = 1): any { - + gradient: number = 1): Node { // delete possible old styles Object.keys(defaultConfig.nodeGroups.default).forEach(e => delete node[e]); // set group styles @@ -144,7 +143,9 @@ export class NetworkSettings { node = merge(node, config.nodeGroups.seedNode); } else if (isSelected) { // apply selected node style to node + console.log(node) node = merge(node, config.nodeGroups.selectedNode); + console.log(node) } // show image if image url is given if (node.image) { diff --git a/src/app/pages/explorer-page/explorer-page.component.html b/src/app/pages/explorer-page/explorer-page.component.html index 28978dcb..30c5b4ac 100644 --- a/src/app/pages/explorer-page/explorer-page.component.html +++ b/src/app/pages/explorer-page/explorer-page.component.html @@ -135,7 +135,7 @@ <footer *ngIf="myConfig.showFooter" class="card-footer toolbar explorer-footer"> <ng-container *ngIf="myConfig.showFooterButtonScreenshot"> - <button (click)="toImage()" class="button is-primary is-rounded has-tooltip" + <button (click)="toImage()" class="button is-primary is-rounded has-tooltip explorer-footer-element" data-tooltip="Take a screenshot of the current network."> <span class="icon"> <i class="fas fa-camera" aria-hidden="true"></i> @@ -145,7 +145,7 @@ </ng-container> <ng-container *ngIf="myConfig.showFooterButtonExpression"> - <div class="footer-buttons dropdown is-up" [class.is-active]="expressionExpanded"> + <div class="footer-buttons dropdown is-up explorer-footer-element" [class.is-active]="expressionExpanded"> <div class="dropdown-trigger"> <button (click)="expressionExpanded=!expressionExpanded" class="button is-rounded is-primary" [class.is-outlined]="!selectedTissue" @@ -182,17 +182,18 @@ </div> </ng-container> - <app-toggle class="footer-buttons" textOn="Drugs On" textOff="Off" + <app-toggle class="footer-buttons explorer-footer-element" textOn="Drugs On" textOff="Off" tooltipOn="Display adjacent drugs ON." tooltipOff="Display adjacent drugs OFF." [smallStyle]="smallStyle" [value]="adjacentDrugs" (valueChange)="updateAdjacentDrugs($event)"></app-toggle> - <app-toggle class="footer-buttons" textOn="Animation On" textOff="Off" + <app-toggle class="footer-buttons explorer-footer-element" textOn="Animation On" textOff="Off" tooltipOn="Enable the network animation." tooltipOff="Disable the network animation and freeze nodes." [smallStyle]="smallStyle" [value]="physicsEnabled" (valueChange)="updatePhysicsEnabled($event)"></app-toggle> + </footer> </div> </div> diff --git a/src/app/pages/explorer-page/explorer-page.component.ts b/src/app/pages/explorer-page/explorer-page.component.ts index 964ac8d1..3f5d7760 100644 --- a/src/app/pages/explorer-page/explorer-page.component.ts +++ b/src/app/pages/explorer-page/explorer-page.component.ts @@ -184,7 +184,8 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit { this.showDetails = false; this.analysis.subscribeList((items, selected) => { - if (!this.nodeData.nodes) { + // return if analysis panel is open or no nodes are loaded + if (this.selectedAnalysisToken || !this.nodeData.nodes) { return; } if (selected !== null) { @@ -201,7 +202,6 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit { const pos = this.networkInternal.getPositions([wrapper.id]); node.x = pos[wrapper.id].x; node.y = pos[wrapper.id].y; - console.log('before styling') const nodeStyled = NetworkSettings.getNodeStyle( node, this.myConfig, @@ -209,7 +209,6 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit { selected, 1.0 ) - console.log('after styling') nodeStyled.x = pos[wrapper.id].x; nodeStyled.y = pos[wrapper.id].y; updatedNodes.push(nodeStyled); @@ -218,7 +217,7 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit { } else { const updatedNodes = []; this.nodeData.nodes.forEach((node) => { - const nodeSelected = this.analysis.idInSelection(node.id); + // const nodeSelected = this.analysis.idInSelection(node.id); // if (node.group == 'default') { // Object.assign(node, this.myConfig.nodeGroups.default); // } else { @@ -348,11 +347,11 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit { if (nodeIds.length > 0) { const nodeId = nodeIds[0]; const node = this.nodeData.nodes.get(nodeId); - const wrapper = getWrapperFromNode(node); - if (wrapper.data.netexId === undefined || !wrapper.data.netexId.startsWith('p')) { + if (node.netexId === undefined || !node.netexId.startsWith('p')) { // skip if node is not a protein mapped to backend return; } + const wrapper = getWrapperFromNode(node); if (this.analysis.inSelection(node)) { this.analysis.removeItems([wrapper]); } else { @@ -483,17 +482,32 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit { if (!group.borderWidthSelected) { group.borderWidthSelected = 0; } - // color needs to be hexacode to calculate gradient, group.color might not be set for seed and selected group - if (!group.color.startsWith('#')) { - // color is either rgba, rgb or string like "red" - if (group.color.startsWith('rgba')) { - group.color = rgbaToHex(group.color).slice(0, 7) - } else if (group.color.startsWith('rgb')) { - group.color = rgbToHex(group.color) - } else ( - group.color = standardize_color(group.color) - ) + // if color is set as string, add detail settings + if (typeof group.color === 'string') { + group.color = { + border: group.color, + background: group.color, + highlight: { + border: group.color, + background: group.color + } + } } + // if image is given, set node shape to image + if (group.image) { + group.shape = 'image'; + } + // color needs to be hexacode to calculate gradient, group.color might not be set for seed and selected group + // if (!group.color.startsWith('#')) { + // // color is either rgba, rgb or string like "red" + // if (group.color.startsWith('rgba')) { + // group.color = rgbaToHex(group.color).slice(0, 7) + // } else if (group.color.startsWith('rgb')) { + // group.color = rgbToHex(group.color) + // } else ( + // group.color = standardize_color(group.color) + // ) + // } }); // make sure that return-groups (seeds, drugs, found nodes) are set diff --git a/src/index.html b/src/index.html index 5225bf72..87b43fc7 100644 --- a/src/index.html +++ b/src/index.html @@ -36,13 +36,13 @@ <network-expander id="netexp1" config='{ "nodeGroups": {"selectedNode": {"font": {"size": "18"} }, "0.5": {"font": "18px verdana blue", "type": "0.5er Instanz", "color": "green", "groupName": "0.5", "shape": "hexagon"}, "patientgroup": {"type": "Patient", "detailShowLabel": "true", "color": "#632345", "groupName": "patient group", "shape": "dot", "size": "50"}, "pugGroup": {"type": "woof woof", "color": "grey", "groupName": "Pug Group", "shape": "triangle", "image": "https://static.raymondcamden.com/images/2016/11/pug.png"}}, - "edgeGroups": {"dashes": {"color": "black", "groupName": "dashes Group", "dashes": [1, 2]}, "notdashes": {"color": "black", "groupName": "not dashes Group"}}, + "edgeGroups": {"xxx": {"color": "black", "groupName": "xxx 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": "pugGroup"}, {"id": "Patient No. 5", "group": "patientgroup"}, {"label": "PTEN", "id": "PTEN", "group": 0.5, "value":"5"}], "edges": [ - {"from": "TP53","to": "C5","group": "dashes", "label": "this is a label", "title": "this is a title"}, + {"from": "TP53","to": "C5","group": "xxx", "label": "this is a label", "title": "this is a title"}, {"from": "Patient No. 5","to": "C5","label": "w/o group"} ] }' diff --git a/src/styles.scss b/src/styles.scss index 46417e24..8a4898db 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -18,10 +18,13 @@ } .explorer-footer { - //position: absolute; - //overflow: auto; + position: absolute; + // overflow: auto; //width: $main-width; bottom: 0; + &-element { + position: relative; + } } nav.navbar { -- GitLab