From 2ea0be00f04f73e72f0008f3ecd5f2d281731180 Mon Sep 17 00:00:00 2001 From: "Hartung, Michael" <michael.hartung@uni-hamburg.de> Date: Fri, 5 May 2023 16:00:52 +0200 Subject: [PATCH] hide connector nodes in legend if none in network --- .../analysis-panel.component.ts | 682 +++++++++++------- .../network-legend.component.ts | 65 +- .../legend-service/legend-service.service.ts | 7 + src/index.html | 2 +- 4 files changed, 481 insertions(+), 275 deletions(-) diff --git a/src/app/components/analysis-panel/analysis-panel.component.ts b/src/app/components/analysis-panel/analysis-panel.component.ts index 26c8b639..a616c00f 100644 --- a/src/app/components/analysis-panel/analysis-panel.component.ts +++ b/src/app/components/analysis-panel/analysis-panel.component.ts @@ -9,9 +9,12 @@ import { Output, SimpleChanges, ViewChild, -} from '@angular/core'; -import {HttpClient} from '@angular/common/http'; -import {algorithmNames, AnalysisService} from '../../services/analysis/analysis.service'; +} from "@angular/core"; +import { HttpClient } from "@angular/common/http"; +import { + algorithmNames, + AnalysisService, +} from "../../services/analysis/analysis.service"; import { Drug, NodeAttributeMap, @@ -23,22 +26,26 @@ import { Tissue, Wrapper, NodeInteraction, -} from '../../interfaces'; -import {NetworkSettings} from '../../network-settings'; -import {NetexControllerService} from 'src/app/services/netex-controller/netex-controller.service'; -import {mapCustomEdge, mapNetexEdge, ProteinNetwork} from 'src/app/main-network'; -import {DrugstoneConfigService} from 'src/app/services/drugstone-config/drugstone-config.service'; -import {NetworkHandlerService} from 'src/app/services/network-handler/network-handler.service'; -import {LegendService} from 'src/app/services/legend-service/legend-service.service'; -import {LoadingScreenService} from 'src/app/services/loading-screen/loading-screen.service'; -import {version} from '../../../version'; -import {downloadCSV} from 'src/app/utils'; +} from "../../interfaces"; +import { NetworkSettings } from "../../network-settings"; +import { NetexControllerService } from "src/app/services/netex-controller/netex-controller.service"; +import { + mapCustomEdge, + mapNetexEdge, + ProteinNetwork, +} from "src/app/main-network"; +import { DrugstoneConfigService } from "src/app/services/drugstone-config/drugstone-config.service"; +import { NetworkHandlerService } from "src/app/services/network-handler/network-handler.service"; +import { LegendService } from "src/app/services/legend-service/legend-service.service"; +import { LoadingScreenService } from "src/app/services/loading-screen/loading-screen.service"; +import { version } from "../../../version"; +import { downloadCSV } from "src/app/utils"; declare var vis: any; interface Scored { - score: number; // Normalized or unnormalized (whichever user selects, will be displayed in the table) - rawScore: number; // Unnormalized (kept to restore unnormalized value) + score: number; // Normalized or unnormalized (whichever user selects, will be displayed in the table) + rawScore: number; // Unnormalized (kept to restore unnormalized value) rank: number; } @@ -46,23 +53,25 @@ interface Seeded { isSeed: boolean; } - @Component({ - selector: 'app-analysis-panel', - templateUrl: './analysis-panel.component.html', - styleUrls: ['./analysis-panel.component.scss'], + selector: "app-analysis-panel", + templateUrl: "./analysis-panel.component.html", + styleUrls: ["./analysis-panel.component.scss"], }) -export class AnalysisPanelComponent implements OnInit, OnChanges, AfterViewInit { - - @ViewChild('networkWithLegend', {static: false}) networkWithLegendEl: ElementRef; +export class AnalysisPanelComponent + implements OnInit, OnChanges, AfterViewInit +{ + @ViewChild("networkWithLegend", { static: false }) + networkWithLegendEl: ElementRef; @Input() token: string | null = null; @Input() tokenType: string | null = null; - @Output() tokenChange = new EventEmitter<string | null>(); @Output() showDetailsChange = new EventEmitter<Wrapper>(); @Output() setInputNetwork = new EventEmitter<any>(); - @Output() visibleItems = new EventEmitter<[any[], [Node[], Tissue], NodeInteraction[]]>(); + @Output() visibleItems = new EventEmitter< + [any[], [Node[], Tissue], NodeInteraction[]] + >(); public task: Task | null = null; public result: any = null; @@ -71,10 +80,10 @@ export class AnalysisPanelComponent implements OnInit, OnChanges, AfterViewInit public algorithmDefault = undefined; 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 tab: 'meta' | 'network' | 'table' = 'network'; + public tab: "meta" | "network" | "table" = "network"; private proteins: any; public effects: any; @@ -85,15 +94,15 @@ export class AnalysisPanelComponent implements OnInit, OnChanges, AfterViewInit public tableNormalize = false; public tableHasScores = false; - public LegendContext: LegendContext = 'drugTarget'; + public LegendContext: LegendContext = "drugTarget"; public expressionExpanded = false; public selectedTissue: Tissue | null = null; public algorithmNames = algorithmNames; - public tableDrugScoreTooltip = ''; - public tableProteinScoreTooltip = ''; + public tableDrugScoreTooltip = ""; + public tableProteinScoreTooltip = ""; public versionString = undefined; @@ -101,18 +110,24 @@ export class AnalysisPanelComponent implements OnInit, OnChanges, AfterViewInit public loading = false; - constructor(public legendService: LegendService, public networkHandler: NetworkHandlerService, public drugstoneConfig: DrugstoneConfigService, private http: HttpClient, public analysis: AnalysisService, public netex: NetexControllerService, public loadingScreen: LoadingScreenService) { + constructor( + public legendService: LegendService, + public networkHandler: NetworkHandlerService, + public drugstoneConfig: DrugstoneConfigService, + private http: HttpClient, + public analysis: AnalysisService, + public netex: NetexControllerService, + public loadingScreen: LoadingScreenService + ) { try { this.versionString = version; - } catch (e) { - } + } catch (e) {} } - async ngOnInit() { - } + async ngOnInit() {} ngAfterViewInit() { - this.networkHandler.setActiveNetwork('analysis'); + this.networkHandler.setActiveNetwork("analysis"); } async ngOnChanges(changes: SimpleChanges) { @@ -127,53 +142,70 @@ export class AnalysisPanelComponent implements OnInit, OnChanges, AfterViewInit this.resetEmitter.emit(true); } - private setNetworkListeners(){ - this.networkHandler.activeNetwork.networkInternal.on('dragEnd', (properties) => { - const node_ids = this.networkHandler.activeNetwork.networkInternal.getSelectedNodes(); - if (node_ids.length === 0 || !this.networkHandler.shiftDown) { - return; - } - this.analysis.addNodesByIdsToSelection(node_ids); - this.networkHandler.activeNetwork.networkInternal.unselectAll(); - }); - this.networkHandler.activeNetwork.networkInternal.on('deselectNode', (properties) => { - this.showDetailsChange.emit(null); - }); - this.networkHandler.activeNetwork.networkInternal.on('doubleClick', (properties) => { - const nodeIds: Array<string> = properties.nodes; - if (nodeIds.length > 0) { - const nodeId = nodeIds[0]; - const node = this.nodeData.nodes.get(nodeId); - if (node.drugstoneId === undefined || node.nodeType === 'drug' || node.drugstoneType !== 'protein') { - this.analysis.unmappedNodeToast(); + private setNetworkListeners() { + this.networkHandler.activeNetwork.networkInternal.on( + "dragEnd", + (properties) => { + const node_ids = + this.networkHandler.activeNetwork.networkInternal.getSelectedNodes(); + if (node_ids.length === 0 || !this.networkHandler.shiftDown) { return; } - const wrapper = getWrapperFromNode(node); - if (this.analysis.inSelection(wrapper)) { - this.analysis.removeItems([wrapper]); - this.analysis.getCount(); - } else { - this.analysis.addItems([wrapper]); - this.analysis.getCount(); + this.analysis.addNodesByIdsToSelection(node_ids); + this.networkHandler.activeNetwork.networkInternal.unselectAll(); + } + ); + this.networkHandler.activeNetwork.networkInternal.on( + "deselectNode", + (properties) => { + this.showDetailsChange.emit(null); + } + ); + this.networkHandler.activeNetwork.networkInternal.on( + "doubleClick", + (properties) => { + const nodeIds: Array<string> = properties.nodes; + if (nodeIds.length > 0) { + const nodeId = nodeIds[0]; + const node = this.nodeData.nodes.get(nodeId); + if ( + node.drugstoneId === undefined || + node.nodeType === "drug" || + node.drugstoneType !== "protein" + ) { + this.analysis.unmappedNodeToast(); + return; + } + const wrapper = getWrapperFromNode(node); + if (this.analysis.inSelection(wrapper)) { + this.analysis.removeItems([wrapper]); + this.analysis.getCount(); + } else { + this.analysis.addItems([wrapper]); + this.analysis.getCount(); + } } } - }); - - this.networkHandler.activeNetwork.networkInternal.on('click', (properties) => { - if (properties.nodes.length === 0 && properties.edges.length === 1) { - // clicked on one edge - const edgeId = properties.edges[0]; - this.networkHandler.activeNetwork.openEdgeSummary(edgeId); - } else { - this.networkHandler.activeNetwork.activeEdge = null; - const selectedNodes = this.nodeData.nodes.get(properties.nodes); - if (selectedNodes.length > 0) { - this.showDetailsChange.emit(getWrapperFromNode(selectedNodes[0])); + ); + + this.networkHandler.activeNetwork.networkInternal.on( + "click", + (properties) => { + if (properties.nodes.length === 0 && properties.edges.length === 1) { + // clicked on one edge + const edgeId = properties.edges[0]; + this.networkHandler.activeNetwork.openEdgeSummary(edgeId); } else { - this.showDetailsChange.emit(null); + this.networkHandler.activeNetwork.activeEdge = null; + const selectedNodes = this.nodeData.nodes.get(properties.nodes); + if (selectedNodes.length > 0) { + 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) { @@ -187,10 +219,15 @@ export class AnalysisPanelComponent implements OnInit, OnChanges, AfterViewInit if (!node) { continue; } - const pos = this.networkHandler.activeNetwork.networkInternal.getPositions([item.id]); + const pos = + this.networkHandler.activeNetwork.networkInternal.getPositions([ + item.id, + ]); 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 isSeed = this.networkHandler.activeNetwork.highlightSeeds + ? this.networkHandler.activeNetwork.seedMap[node.id] + : false; const nodeStyled = NetworkSettings.getNodeStyle( node, this.drugstoneConfig.currentConfig(), @@ -206,8 +243,12 @@ export class AnalysisPanelComponent implements OnInit, OnChanges, AfterViewInit const proteinSelection = this.tableSelectedProteins; for (const item of items) { // TODO: Refactor! - const found = proteinSelection.findIndex((i) => getProteinNodeId(i) === item.id); - const tableItem = this.tableProteins.find((i) => getProteinNodeId(i) === item.id); + const found = proteinSelection.findIndex( + (i) => getProteinNodeId(i) === item.id + ); + const tableItem = this.tableProteins.find( + (i) => getProteinNodeId(i) === item.id + ); if (selected && found === -1 && tableItem) { proteinSelection.push(tableItem); } @@ -220,7 +261,9 @@ export class AnalysisPanelComponent implements OnInit, OnChanges, AfterViewInit // else: selected is null const updatedNodes = []; this.nodeData.nodes.forEach((node) => { - const isSeed = this.networkHandler.activeNetwork.highlightSeeds ? this.networkHandler.activeNetwork.seedMap[node.id] : false; + const isSeed = this.networkHandler.activeNetwork.highlightSeeds + ? this.networkHandler.activeNetwork.seedMap[node.id] + : false; if (!isSeed) { return; } @@ -238,7 +281,9 @@ export class AnalysisPanelComponent implements OnInit, OnChanges, AfterViewInit const proteinSelection = []; for (const item of items) { - const tableItem = this.tableProteins.find((i) => getProteinNodeId(i) === item.id); + const tableItem = this.tableProteins.find( + (i) => getProteinNodeId(i) === item.id + ); if (tableItem) { proteinSelection.push(tableItem); } @@ -248,7 +293,9 @@ export class AnalysisPanelComponent implements OnInit, OnChanges, AfterViewInit }); } - private rankTable(table: Array<Drug & Scored> | Array<Node & Scored & Seeded>) { + private rankTable( + table: Array<Drug & Scored> | Array<Node & Scored & Seeded> + ) { let lastRank = 1; for (let idx = 0; idx < table.length; idx++) { if (idx === 0) { @@ -265,16 +312,15 @@ export class AnalysisPanelComponent implements OnInit, OnChanges, AfterViewInit private async refreshView() { this.loading = true; this.loadingScreen.stateUpdate(true); - this.getView(this.token).then(async view => { + this.getView(this.token).then(async (view) => { this.task = view; this.result = view; this.drugstoneConfig.set_analysisConfig(view.config); this.analysis.switchSelection(this.token); this.loadingScreen.stateUpdate(false); - // Reset - this.nodeData = {nodes: null, edges: null}; + this.nodeData = { nodes: null, edges: null }; // this.networkHandler.activeNetwork.networkEl.nativeElement.innerHTML = ''; // this.networkHandler.activeNetwork.networkInternal = null; // Create+ @@ -284,34 +330,56 @@ export class AnalysisPanelComponent implements OnInit, OnChanges, AfterViewInit if (this.drugstoneConfig.config.autofillEdges && nodes.length) { const node_map = {}; - nodes.filter(n => n.drugstoneType === 'protein').forEach(node => { - if (typeof node.drugstoneId === 'string') { - if (node_map[node.drugstoneId]) { - node_map[node.drugstoneId].push(node.id); - } else { - node_map[node.drugstoneId] = [node.id]; - } - } else { - node.drugstoneId.forEach(n => { - if (node_map[n]) { - node_map[n].push(node.id); + nodes + .filter((n) => n.drugstoneType === "protein") + .forEach((node) => { + if (typeof node.drugstoneId === "string") { + if (node_map[node.drugstoneId]) { + node_map[node.drugstoneId].push(node.id); } else { - node_map[n] = [node.id]; + node_map[node.drugstoneId] = [node.id]; } - }); - } - }); - const netexEdges = await this.netex.fetchEdges(nodes, this.drugstoneConfig.config.interactionProteinProtein, this.drugstoneConfig.config.licensedDatasets); - edges.push(...netexEdges.map(netexEdge => mapNetexEdge(netexEdge, this.drugstoneConfig.currentConfig(), node_map)).flatMap(e => e)); + } else { + node.drugstoneId.forEach((n) => { + if (node_map[n]) { + node_map[n].push(node.id); + } else { + node_map[n] = [node.id]; + } + }); + } + }); + const netexEdges = await this.netex.fetchEdges( + nodes, + this.drugstoneConfig.config.interactionProteinProtein, + this.drugstoneConfig.config.licensedDatasets + ); + edges.push( + ...netexEdges + .map((netexEdge) => + mapNetexEdge( + netexEdge, + this.drugstoneConfig.currentConfig(), + node_map + ) + ) + .flatMap((e) => e) + ); } const edge_map = {}; - edges = edges.filter(edge => { - if (edge_map[edge.to] && edge_map[edge.to].indexOf(edge.from) !== -1) { + edges = edges.filter((edge) => { + if ( + edge_map[edge.to] && + edge_map[edge.to].indexOf(edge.from) !== -1 + ) { return false; } - if (edge_map[edge.from] && edge_map[edge.from].indexOf(edge.to) !== -1) { + if ( + edge_map[edge.from] && + edge_map[edge.from].indexOf(edge.to) !== -1 + ) { return false; } if (!edge_map[edge.from]) { @@ -324,15 +392,22 @@ export class AnalysisPanelComponent implements OnInit, OnChanges, AfterViewInit // @ts-ignore if (!this.drugstoneConfig.selfReferences) { - edges = edges.filter(el => el.from !== el.to); + edges = edges.filter((el) => el.from !== el.to); } - this.networkHandler.activeNetwork.inputNetwork = {nodes: nodes, edges: edges}; + this.networkHandler.activeNetwork.inputNetwork = { + 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; + const container = + this.networkHandler.activeNetwork.networkEl.nativeElement; const isBig = nodes.length > 100 || edges.length > 100; - const options = NetworkSettings.getOptions(isBig ? 'analysis-big' : 'analysis', this.drugstoneConfig.currentConfig()); + const options = NetworkSettings.getOptions( + isBig ? "analysis-big" : "analysis", + this.drugstoneConfig.currentConfig() + ); // @ts-ignore options.groups = this.drugstoneConfig.currentConfig().nodeGroups; // @ts-ignore @@ -343,19 +418,31 @@ export class AnalysisPanelComponent implements OnInit, OnChanges, AfterViewInit if (this.drugstoneConfig.config.physicsOn) { this.drugstoneConfig.config.physicsOn = !isBig; } - this.networkHandler.activeNetwork.networkInternal = new vis.Network(container, this.nodeData, options); + this.networkHandler.activeNetwork.networkInternal = new vis.Network( + container, + this.nodeData, + options + ); if (isBig) { resolve(nodes); } - this.networkHandler.activeNetwork.networkInternal.once('stabilizationIterationsDone', async () => { - if (!this.drugstoneConfig.config.physicsOn || this.networkHandler.activeNetwork.isBig()) { - this.networkHandler.activeNetwork.updatePhysicsEnabled(false); + this.networkHandler.activeNetwork.networkInternal.once( + "stabilizationIterationsDone", + async () => { + if ( + !this.drugstoneConfig.config.physicsOn || + this.networkHandler.activeNetwork.isBig() + ) { + this.networkHandler.activeNetwork.updatePhysicsEnabled(false); + } + this.networkHandler + .updateAdjacentNodes(this.networkHandler.activeNetwork.isBig()) + .then(() => { + resolve(nodes); + }); } - this.networkHandler.updateAdjacentNodes(this.networkHandler.activeNetwork.isBig()).then(() => { - resolve(nodes); - }); - }); + ); }).then(() => { this.setNetworkListeners(); this.emitVisibleItems(true); @@ -363,79 +450,84 @@ export class AnalysisPanelComponent implements OnInit, OnChanges, AfterViewInit }); } - private async refreshTask() { this.loadingScreen.stateUpdate(true); this.task = await this.getTask(this.token); this.analysis.switchSelection(this.token); - if (this.task.info.algorithm === 'degree') { + if (this.task.info.algorithm === "degree") { this.tableDrugScoreTooltip = - 'Normalized number of direct interactions of the drug with the seeds. ' + - 'The higher the score, the more relevant the drug.'; + "Normalized number of direct interactions of the drug with the seeds. " + + "The higher the score, the more relevant the drug."; this.tableProteinScoreTooltip = - 'Normalized number of direct interactions of the protein with the seeds. ' + - 'The higher the score, the more relevant the protein.'; - } else if (this.task.info.algorithm === 'closeness' || this.task.info.algorithm === 'quick' || this.task.info.algorithm === 'super') { + "Normalized number of direct interactions of the protein with the seeds. " + + "The higher the score, the more relevant the protein."; + } else if ( + this.task.info.algorithm === "closeness" || + this.task.info.algorithm === "quick" || + this.task.info.algorithm === "super" + ) { this.tableDrugScoreTooltip = - 'Normalized inverse mean distance of the drug to the seeds. ' + - 'The higher the score, the more relevant the drug.'; + "Normalized inverse mean distance of the drug to the seeds. " + + "The higher the score, the more relevant the drug."; this.tableProteinScoreTooltip = - 'Normalized inverse mean distance of the protein to the seeds. ' + - 'The higher the score, the more relevant the protein.'; - } else if (this.task.info.algorithm === 'trustrank') { + "Normalized inverse mean distance of the protein to the seeds. " + + "The higher the score, the more relevant the protein."; + } else if (this.task.info.algorithm === "trustrank") { this.tableDrugScoreTooltip = - 'Amount of ‘trust’ on the drug at termination of the algorithm. ' + - 'The higher the score, the more relevant the drug.'; + "Amount of ‘trust’ on the drug at termination of the algorithm. " + + "The higher the score, the more relevant the drug."; this.tableProteinScoreTooltip = - 'Amount of ‘trust’ on the protein at termination of the algorithm. ' + - 'The higher the score, the more relevant the protein.'; - } else if (this.task.info.algorithm === 'proximity') { + "Amount of ‘trust’ on the protein at termination of the algorithm. " + + "The higher the score, the more relevant the protein."; + } else if (this.task.info.algorithm === "proximity") { this.tableDrugScoreTooltip = - 'Empirical z-score of mean minimum distance between the drug’s targets and the seeds. ' + - 'The lower the score, the more relevant the drug.'; + "Empirical z-score of mean minimum distance between the drug’s targets and the seeds. " + + "The lower the score, the more relevant the drug."; this.tableProteinScoreTooltip = - 'Empirical z-score of mean minimum distance between the drug’s targets and the seeds. ' + - 'The lower the score, the more relevant the drug.'; + "Empirical z-score of mean minimum distance between the drug’s targets and the seeds. " + + "The lower the score, the more relevant the drug."; } if (this.task && this.task.info && this.task.info.done) { - this.loading = true; - this.netex.getTaskResult(this.token).then(async result => { - if (this.networkHandler.activeNetwork.networkType !== 'analysis') { + this.netex.getTaskResult(this.token).then(async (result) => { + if (this.networkHandler.activeNetwork.networkType !== "analysis") { return; } this.drugstoneConfig.set_analysisConfig(result.parameters.config); this.analysis.switchSelection(this.token); this.result = result; - if (this.result.parameters.target === 'drug') { - this.legendService.add_to_context('drug'); + if (this.result.parameters.target === "drug") { + this.legendService.add_to_context("drug"); } else { - this.legendService.add_to_context('drugTarget'); + this.legendService.add_to_context("drugTarget"); } const nodeAttributes = this.result.nodeAttributes || {}; - const analysisNetwork = this.networkHandler.networks['analysis']; + const analysisNetwork = this.networkHandler.networks["analysis"]; analysisNetwork.seedMap = nodeAttributes.isSeed || {}; // Reset - this.nodeData = {nodes: null, edges: null}; - analysisNetwork.networkEl.nativeElement.innerHTML = ''; + this.nodeData = { nodes: null, edges: null }; + analysisNetwork.networkEl.nativeElement.innerHTML = ""; analysisNetwork.networkInternal = null; // Create - await this.createNetwork(this.result).then(nw => { + await this.createNetwork(this.result).then((nw) => { return new Promise<any>((resolve, reject) => { - if (this.networkHandler.activeNetwork.networkType !== 'analysis') { + if (this.networkHandler.activeNetwork.networkType !== "analysis") { return; } const nodes = nw.nodes; const edges = nw.edges; - analysisNetwork.inputNetwork = {nodes: nodes, edges: edges}; + analysisNetwork.inputNetwork = { nodes: nodes, edges: edges }; this.nodeData.nodes = new vis.DataSet(nodes); this.nodeData.edges = new vis.DataSet(edges); const container = analysisNetwork.networkEl.nativeElement; const isBig = nodes.length > 100 || edges.length > 100; - const options = NetworkSettings.getOptions(isBig ? 'analysis-big' : 'analysis', this.drugstoneConfig.currentConfig()); + const options = NetworkSettings.getOptions( + isBig ? "analysis-big" : "analysis", + this.drugstoneConfig.currentConfig() + ); // @ts-ignore options.groups = this.drugstoneConfig.currentConfig().nodeGroups; // @ts-ignore @@ -446,60 +538,94 @@ export class AnalysisPanelComponent implements OnInit, OnChanges, AfterViewInit if (this.drugstoneConfig.config.physicsOn) { this.drugstoneConfig.config.physicsOn = !isBig; } - analysisNetwork.networkInternal = new vis.Network(container, this.nodeData, options); + analysisNetwork.networkInternal = new vis.Network( + container, + this.nodeData, + options + ); if (isBig) { resolve(nodes); } - analysisNetwork.networkInternal.once('stabilizationIterationsDone', async () => { - if (!this.drugstoneConfig.config.physicsOn || analysisNetwork.isBig()) { - analysisNetwork.updatePhysicsEnabled(false); + analysisNetwork.networkInternal.once( + "stabilizationIterationsDone", + async () => { + if ( + !this.drugstoneConfig.config.physicsOn || + analysisNetwork.isBig() + ) { + analysisNetwork.updatePhysicsEnabled(false); + } + this.networkHandler + .updateAdjacentNodes(analysisNetwork.isBig()) + .then(() => { + resolve(nodes); + }); } - this.networkHandler.updateAdjacentNodes(analysisNetwork.isBig()).then(() => { - resolve(nodes); + ); + }) + .then((nodes) => { + this.tableDrugs = nodes.filter( + (e) => e.drugstoneId && e.drugstoneType === "drug" + ); + this.tableDrugs.forEach((r) => { + r.rawScore = r.score; }); - }); - }).then(nodes => { - - this.tableDrugs = nodes.filter(e => e.drugstoneId && e.drugstoneType === 'drug'); - this.tableDrugs.forEach((r) => { - r.rawScore = r.score; - }); - // @ts-ignore - this.tableDrugs.sort((a, b) => b.score - a.score); - this.rankTable(this.tableDrugs); - this.tableProteins = nodes.filter(e => e.drugstoneId && e.drugstoneType === 'protein'); - this.tableSelectedProteins = []; - this.tableProteins.forEach((r) => { - r.rawScore = r.score; - r.isSeed = analysisNetwork.seedMap[r.id]; - const wrapper = getWrapperFromNode(r); - if (this.analysis.inSelection(wrapper)) { - this.tableSelectedProteins.push(r); + // @ts-ignore + this.tableDrugs.sort((a, b) => b.score - a.score); + this.rankTable(this.tableDrugs); + this.tableProteins = nodes.filter( + (e) => e.drugstoneId && e.drugstoneType === "protein" + ); + this.tableSelectedProteins = []; + this.tableProteins.forEach((r) => { + r.rawScore = r.score; + r.isSeed = analysisNetwork.seedMap[r.id]; + const wrapper = getWrapperFromNode(r); + if (this.analysis.inSelection(wrapper)) { + this.tableSelectedProteins.push(r); + } + }); + this.tableProteins.sort((a, b) => b.score - a.score); + this.rankTable(this.tableProteins); + + this.tableHasScores = + [ + "trustrank", + "closeness", + "degree", + "betweenness", + "quick", + "super", + ].indexOf(this.task.info.algorithm) !== -1; + if (this.tableHasScores) { + this.toggleNormalization(true); } - }); - this.tableProteins.sort((a, b) => b.score - a.score); - this.rankTable(this.tableProteins); - - this.tableHasScores = ['trustrank', 'closeness', 'degree', 'betweenness', 'quick', 'super'] - .indexOf(this.task.info.algorithm) !== -1; - if (this.tableHasScores) { - this.toggleNormalization(true); - } - analysisNetwork.networkInternal.setData({nodes: undefined, edge: undefined}); - setTimeout(() => { - analysisNetwork.networkInternal.setData(this.nodeData); - }, 1000); - this.setNetworkListeners(); - this.emitVisibleItems(true); - }).then(() => { - if (!['quick', 'super', 'connect', 'connectSelected'].includes(this.task.info.algorithm)) { - return; - } - this.netex.getAlgorithmDefaults(this.task.info.algorithm).then(response => { - this.algorithmDefault = response; - }); - }).catch(console.error); + analysisNetwork.networkInternal.setData({ + nodes: undefined, + edge: undefined, + }); + setTimeout(() => { + analysisNetwork.networkInternal.setData(this.nodeData); + }, 1000); + this.setNetworkListeners(); + this.emitVisibleItems(true); + }) + .then(() => { + if ( + !["quick", "super", "connect", "connectSelected"].includes( + this.task.info.algorithm + ) + ) { + return; + } + this.netex + .getAlgorithmDefaults(this.task.info.algorithm) + .then((response) => { + this.algorithmDefault = response; + }); + }) + .catch(console.error); }); this.loadingScreen.stateUpdate(false); }); @@ -508,7 +634,7 @@ export class AnalysisPanelComponent implements OnInit, OnChanges, AfterViewInit private async refresh() { if (this.token) { - if (this.tokenType === 'view') { + if (this.tokenType === "view") { this.networkHandler.showSeedsButton = false; await this.refreshView(); } else { @@ -516,39 +642,47 @@ export class AnalysisPanelComponent implements OnInit, OnChanges, AfterViewInit await this.refreshTask(); } } - } public emitVisibleItems(on: boolean) { if (on) { - this.visibleItems.emit([this.nodeData.nodes, [this.proteins, this.selectedTissue], this.nodeData.edges]); + this.visibleItems.emit([ + this.nodeData.nodes, + [this.proteins, this.selectedTissue], + this.nodeData.edges, + ]); } else { this.visibleItems.emit(null); } } private async getView(token: string): Promise<any> { - return await this.http.get(`${this.netex.getBackend()}view/?token=${token}`).toPromise(); + return await this.http + .get(`${this.netex.getBackend()}view/?token=${token}`) + .toPromise(); } private async getTask(token: string): Promise<any> { - return await this.http.get(`${this.netex.getBackend()}task/?token=${token}`).toPromise(); + return await this.http + .get(`${this.netex.getBackend()}task/?token=${token}`) + .toPromise(); } close() { - const analysisNetwork = this.networkHandler.networks['analysis']; + const analysisNetwork = this.networkHandler.networks["analysis"]; analysisNetwork.gradientMap = {}; this.drugstoneConfig.remove_analysisConfig(); this.expressionExpanded = false; this.expressionMap = undefined; analysisNetwork.seedMap = {}; analysisNetwork.highlightSeeds = false; - this.analysis.switchSelection('main'); + this.legendService.networkHasConnector = false; + this.analysis.switchSelection("main"); // this.analysis.resetSelection(); this.token = null; this.tokenChange.emit(this.token); - this.legendService.remove_from_context('drug'); - this.legendService.remove_from_context('drugTarget'); + this.legendService.remove_from_context("drug"); + this.legendService.remove_from_context("drugTarget"); this.emitVisibleItems(false); } @@ -557,30 +691,30 @@ export class AnalysisPanelComponent implements OnInit, OnChanges, AfterViewInit const normalizeFn = (table) => { let max = 0; - table.forEach(i => { + table.forEach((i) => { if (i.rawScore > max) { max = i.rawScore; } }); - table.forEach(i => { + table.forEach((i) => { i.score = i.rawScore / max; }); }; const unnormalizeFn = (table) => { - table.forEach(i => { + table.forEach((i) => { i.score = i.rawScore; }); }; if (normalize) { normalizeFn(this.tableProteins); - if (this.task.info.target === 'drug') { + if (this.task.info.target === "drug") { normalizeFn(this.tableDrugs); } } else { unnormalizeFn(this.tableProteins); - if (this.task.info.target === 'drug') { + if (this.task.info.target === "drug") { unnormalizeFn(this.tableDrugs); } } @@ -595,11 +729,22 @@ export class AnalysisPanelComponent implements OnInit, OnChanges, AfterViewInit } }); - if ('score' in data[0]) { - data = data.sort((a, b) => b['score'] - a['score']); + if ("score" in data[0]) { + data = data.sort((a, b) => b["score"] - a["score"]); } - const columns = ['label', 'symbol', 'uniprot', 'ensg', 'entrez', 'proteinName', 'isSeed', 'score', 'rank', 'status']; + const columns = [ + "label", + "symbol", + "uniprot", + "ensg", + "entrez", + "proteinName", + "isSeed", + "score", + "rank", + "status", + ]; downloadCSV(data, columns, `drugstone_${view}`); } @@ -609,7 +754,9 @@ export class AnalysisPanelComponent implements OnInit, OnChanges, AfterViewInit * @param result * @returns */ - public async createNetwork(result: any): Promise<{ edges: any[]; nodes: any[]; }> { + public async createNetwork( + result: any + ): Promise<{ edges: any[]; nodes: any[] }> { const identifier = this.drugstoneConfig.currentConfig().identifier; // add drugGroup and foundNodesGroup for added nodes @@ -625,47 +772,84 @@ export class AnalysisPanelComponent implements OnInit, OnChanges, AfterViewInit network.nodes = [...new Set<string>(network.nodes)]; const details = attributes.details || {}; const nodeIdMap = {}; + Object.entries(details) // @ts-ignore - Object.entries(details).filter(e => e[1].drugstoneType === 'protein').forEach(e => { - // @ts-ignore - e[1].drugstoneId.forEach(id => { - nodeIdMap[id] = e[1][identifier][0]; + .filter((e) => e[1].drugstoneType === "protein") + .forEach((e) => { + // @ts-ignore + e[1].drugstoneId.forEach((id) => { + nodeIdMap[id] = e[1][identifier][0]; + }); }); - }); for (const nodeId of network.nodes) { if (details[nodeId]) { const nodeDetails = details[nodeId]; - nodeDetails.id = nodeDetails.id ? nodeDetails.id : (typeof nodeDetails.drugstoneId === 'string' ? nodeDetails.drugstoneId : nodeDetails.drugstoneId[0]); - if (nodeDetails.drugstoneId && nodeDetails.drugstoneType === 'protein') { + nodeDetails.id = nodeDetails.id + ? nodeDetails.id + : typeof nodeDetails.drugstoneId === "string" + ? nodeDetails.drugstoneId + : nodeDetails.drugstoneId[0]; + if ( + nodeDetails.drugstoneId && + nodeDetails.drugstoneType === "protein" + ) { // node is protein from database, has been mapped on init to backend protein from backend // or was found during analysis // FIXME connectorNodes are not visualized correctly - nodeDetails.group = result.targetNodes && result.targetNodes.indexOf(nodeId) !== -1 ? 'foundNode' : (nodeDetails.group ? nodeDetails.group : 'connectorNode'); - nodeDetails.label = nodeDetails.label ? nodeDetails.label : nodeDetails[identifier]; - nodeDetails.id = nodeDetails[identifier][0] ? nodeDetails[identifier][0] : nodeDetails.id; + nodeDetails.group = + result.targetNodes && result.targetNodes.indexOf(nodeId) !== -1 + ? "foundNode" + : nodeDetails.group + ? nodeDetails.group + : "connectorNode"; + nodeDetails.label = nodeDetails.label + ? nodeDetails.label + : nodeDetails[identifier]; + nodeDetails.id = nodeDetails[identifier][0] + ? nodeDetails[identifier][0] + : nodeDetails.id; this.proteins.push(nodeDetails); - } else if (nodeDetails.drugstoneId && nodeDetails.drugstoneType === 'drug') { + } else if ( + nodeDetails.drugstoneId && + nodeDetails.drugstoneType === "drug" + ) { // node is drug, was found during analysis - nodeDetails.type = 'Drug'; - nodeDetails.group = 'foundDrug'; + nodeDetails.type = "Drug"; + nodeDetails.group = "foundDrug"; } else { // node is custom input from user, could not be mapped to backend protein - nodeDetails.group = nodeDetails.group ? nodeDetails.group : 'default'; - nodeDetails.label = nodeDetails.label ? nodeDetails.label : nodeDetails[identifier]; + nodeDetails.group = nodeDetails.group ? nodeDetails.group : "default"; + nodeDetails.label = nodeDetails.label + ? nodeDetails.label + : nodeDetails[identifier]; } // 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, this.drugstoneConfig.currentConfig(), false, false, 1, this.networkHandler.activeNetwork.nodeRenderer)); + nodes.push( + NetworkSettings.getNodeStyle( + nodeDetails as Node, + this.drugstoneConfig.currentConfig(), + false, + false, + 1, + this.networkHandler.activeNetwork.nodeRenderer + ) + ); } else { - console.log('Missing details for ' + nodeId); + console.log("Missing details for " + nodeId); } } const uniqEdges = []; for (const edge of network.edges) { - const e = mapCustomEdge(edge, this.drugstoneConfig.currentConfig(), this.drugstoneConfig); - e.from = e.from[0] === 'p' && nodeIdMap[e.from] ? nodeIdMap[e.from] : e.from; - e.to = e.to[0] === 'p' && nodeIdMap[e.to] ? nodeIdMap[e.to] : e.to; - const hash = e.from + '_' + e.to; + const e = mapCustomEdge( + edge, + this.drugstoneConfig.currentConfig(), + this.drugstoneConfig + ); + e.from = + e.from[0] === "p" && nodeIdMap[e.from] ? nodeIdMap[e.from] : e.from; + e.to = e.to[0] === "p" && nodeIdMap[e.to] ? nodeIdMap[e.to] : e.to; + const hash = e.from + "_" + e.to; if (uniqEdges.indexOf(hash) === -1) { uniqEdges.push(hash); edges.push(e); @@ -673,24 +857,35 @@ export class AnalysisPanelComponent implements OnInit, OnChanges, AfterViewInit } // remove self-edges/loops if (!this.drugstoneConfig.currentConfig().selfReferences) { - edges = edges.filter(el => el.from !== el.to); + edges = edges.filter((el) => el.from !== el.to); } - return { + + this.legendService.networkHasConnector = + nodes.filter((node) => node.group === "connectorNode").length > 0; + + return { nodes, edges, }; } getResultNodes() { - if (this.nodeData && this.nodeData['nodes']) { - return this.nodeData['nodes'].get(); + if (this.nodeData && this.nodeData["nodes"]) { + return this.nodeData["nodes"].get(); } return []; } getResultEdges() { - if (this.nodeData && this.nodeData['edges']) { - return this.nodeData['edges'].get().filter(e => !e.id || !e.groupName || (typeof e.from === 'string' && typeof e.to === 'string')); + if (this.nodeData && this.nodeData["edges"]) { + return this.nodeData["edges"] + .get() + .filter( + (e) => + !e.id || + !e.groupName || + (typeof e.from === "string" && typeof e.to === "string") + ); } return []; } @@ -728,5 +923,4 @@ export class AnalysisPanelComponent implements OnInit, OnChanges, AfterViewInit public openBugreport() { this.drugstoneConfig.showBugreport = true; } - } diff --git a/src/app/components/network/network-legend/network-legend.component.ts b/src/app/components/network/network-legend/network-legend.component.ts index 7db97954..8dbafa89 100644 --- a/src/app/components/network/network-legend/network-legend.component.ts +++ b/src/app/components/network/network-legend/network-legend.component.ts @@ -1,38 +1,37 @@ -import {Component, Input, OnInit} from '@angular/core'; -import { LegendContext } from 'src/app/interfaces'; -import { DrugstoneConfigService } from 'src/app/services/drugstone-config/drugstone-config.service'; -import {IConfig} from '../../../config'; -import {LegendService} from "src/app/services/legend-service/legend-service.service"; -import { NetworkHandlerService } from 'src/app/services/network-handler/network-handler.service'; +import { Component, Input, OnInit } from "@angular/core"; +import { LegendContext } from "src/app/interfaces"; +import { DrugstoneConfigService } from "src/app/services/drugstone-config/drugstone-config.service"; +import { IConfig } from "../../../config"; +import { LegendService } from "src/app/services/legend-service/legend-service.service"; +import { NetworkHandlerService } from "src/app/services/network-handler/network-handler.service"; @Component({ - selector: 'app-network-legend', - templateUrl: './network-legend.component.html', - styleUrls: ['./network-legend.component.scss'] + selector: "app-network-legend", + templateUrl: "./network-legend.component.html", + styleUrls: ["./network-legend.component.scss"], }) export class NetworkLegendComponent implements OnInit { - - _context = 'explorer'; + _context = "explorer"; _emptyEdgeConfig = false; - @Input() set context (value: LegendContext) { - this._context = value + @Input() set context(value: LegendContext) { + this._context = value; this._emptyEdgeConfig = this.checkIfEdgeConfigEmpty(); - }; + } @Input() config: IConfig; private contextEdgeGroupsToDelete = { - 'explorer': ['default'], - 'adjacentDrugs': ['default'], - 'adjacentDisorders': ['default'], - 'adjacentDrugsAndDisorders' :['default'], - 'drugTarget': ['default'], - 'drug': ['default'], - 'drugTargetAndSeeds': ['default'], - 'drugAndSeeds': ['default'] - } + explorer: ["default"], + adjacentDrugs: ["default"], + adjacentDisorders: ["default"], + adjacentDrugsAndDisorders: ["default"], + drugTarget: ["default"], + drug: ["default"], + drugTargetAndSeeds: ["default"], + drugAndSeeds: ["default"], + }; public checkNodeGroupContext(nodeGroupKey) { - if (nodeGroupKey === 'selectedNode') { + if (nodeGroupKey === "selectedNode") { // selected node is not supposed to appear in legend return false; } @@ -40,16 +39,22 @@ export class NetworkLegendComponent implements OnInit { } public checkEdgeGroupContext(edgeGroupKey) { - return !this.contextEdgeGroupsToDelete[this._context].includes(edgeGroupKey); + return !this.contextEdgeGroupsToDelete[this._context].includes( + edgeGroupKey + ); } public checkIfEdgeConfigEmpty() { - return Object.keys(this.config.edgeGroups).some(key => this.checkEdgeGroupContext(key)); + return Object.keys(this.config.edgeGroups).some((key) => + this.checkEdgeGroupContext(key) + ); } - constructor(public drugstoneConfig: DrugstoneConfigService, public legendService: LegendService, public networkHandler: NetworkHandlerService) { } - - ngOnInit(): void { - } + constructor( + public drugstoneConfig: DrugstoneConfigService, + public legendService: LegendService, + public networkHandler: NetworkHandlerService + ) {} + ngOnInit(): void {} } diff --git a/src/app/services/legend-service/legend-service.service.ts b/src/app/services/legend-service/legend-service.service.ts index a883f0dd..cd651ba9 100644 --- a/src/app/services/legend-service/legend-service.service.ts +++ b/src/app/services/legend-service/legend-service.service.ts @@ -11,6 +11,7 @@ export class LegendService { private default_delete = ['foundNode', 'foundDrug', 'seedNode', 'default', 'defaultDisorder', 'connectorNode']; private context = []; + public networkHasConnector = false; private contextNodeGroupsToDelete = { adjacentDrugs: ['foundNode', 'seedNode', 'default', 'defaultDisorder', 'connectorNode'], @@ -41,6 +42,12 @@ export class LegendService { const out = [].concat(this.default_delete); for (const node of this.default_delete) { let keep = false; + + // delete connectorNodes if network does not contain any + if (node === 'connectorNode' && !this.networkHasConnector) { + break; + } + for (const c of this.context) { if (this.contextNodeGroupsToDelete[c].indexOf(node) === -1) { keep = true; diff --git a/src/index.html b/src/index.html index c25ff979..f21e306c 100644 --- a/src/index.html +++ b/src/index.html @@ -115,7 +115,7 @@ menu<br> <!-- task-id="ks38WxeCSdbXk2cajKACinnUnCHWbf4I" --> <drugst-one id="netexp1" groups='{"nodeGroups":{"important":{"type":"gene","color":"#ff881f","font":{"color":"#000000"},"groupName":"Seed","shape":"star"},"gene":{"type":"gene","color":"#4da300","font":{"color":"#f0f0f0"},"groupName":"Discovered target","shape":"circle"},"foundDrug":{"type":"drug","color":"#F12590","font":{"color":"#000000"},"groupName":"Drug","shape":"diamond"}},"edgeGroups":{"default":{"color":"#000000","groupName":"default edge"}}}' - config='{"customEdges":{"default":true, "selectable":false}, "showAdvAnalysisContent":["drug-search", "enrichment-gprofiler", "enrichment-digest", "search-ndex"],"identifier":"symbol","title":"ROBUST output network", "taskDrugName": "Drug Search", "showLegendNodes": true, "showLegendEdges": true, "showSidebar": "left", "showOverview": true, "legendPos": "left", "legendClass": "legend", "showQuery": true, "showItemSelector": true,"showSimpleAnalysis": false,"showAdvAnalysis": true,"showSelection": true,"showTasks": true,"showNetworkMenu": "right","showLegend": true,"showNetworkMenuButtonExpression": true, "showNetworkMenuButtonScreenshot": true,"showNetworkMenuButtonExportGraphml": true,"showNetworkMenuButtonAdjacentDrugs": true,"showNetworkMenuButtonCenter": true,"showConnectGenes": false,"networkMenuButtonAdjacentDrugsLabel": "Drugs","showNetworkMenuButtonAdjacentDisordersProteins": true,"networkMenuButtonAdjacentDisordersProteinsLabel": "Disorders (protein)","showNetworkMenuButtonAdjacentDisordersDrugs": true,"networkMenuButtonAdjacentDisordersDrugsLabel": "Disorders (drug)","showNetworkMenuButtonAnimation": true,"networkMenuButtonAnimationLabel": "Animation", "autofillEdges": false, "physicsOn": false,"useNedrexLicenced": true,"selfReferences": false, "interactionDrugProtein": "NeDRex", "indicationDrugDisorder": "NeDRex","nodeShadow": true,"edgeShadow": true, "algorithms": {"drug": ["trustrank", "closeness", "degree", "proximity"], "drug-target": ["trustrank", "multisteiner", "keypathwayminer", "degree", "closeness", "betweenness"]}, "associatedProteinDisorder": "NeDRex", "nodeGroups":{"important":{"type":"gene","color":"#ff881f","font":{"color":"#000000"},"groupName":"Seed","shape":"star"},"gene":{"type":"gene","color":"#4da300","font":{"color":"#f0f0f0"},"groupName":"Discovered target","shape":"circle"},"foundDrug":{"type":"drug","color":"#F12590","font":{"color":"#000000"},"groupName":"Drug","shape":"diamond"}},"edgeGroups":{"default":{"color":"#000000","groupName":"default edge"}}}' + config='{"customEdges":{"default":true, "selectable":false}, "showAdvAnalysisContent":["drug-search", "drug-target-search", "enrichment-gprofiler", "enrichment-digest", "search-ndex"],"identifier":"symbol","title":"ROBUST output network", "taskDrugName": "Drug Search", "showLegendNodes": true, "showLegendEdges": true, "showSidebar": "left", "showOverview": true, "legendPos": "left", "legendClass": "legend", "showQuery": true, "showItemSelector": true,"showSimpleAnalysis": false,"showAdvAnalysis": true,"showSelection": true,"showTasks": true,"showNetworkMenu": "right","showLegend": true,"showNetworkMenuButtonExpression": true, "showNetworkMenuButtonScreenshot": true,"showNetworkMenuButtonExportGraphml": true,"showNetworkMenuButtonAdjacentDrugs": true,"showNetworkMenuButtonCenter": true,"showConnectGenes": false,"networkMenuButtonAdjacentDrugsLabel": "Drugs","showNetworkMenuButtonAdjacentDisordersProteins": true,"networkMenuButtonAdjacentDisordersProteinsLabel": "Disorders (protein)","showNetworkMenuButtonAdjacentDisordersDrugs": true,"networkMenuButtonAdjacentDisordersDrugsLabel": "Disorders (drug)","showNetworkMenuButtonAnimation": true,"networkMenuButtonAnimationLabel": "Animation", "autofillEdges": false, "physicsOn": false,"useNedrexLicenced": true,"selfReferences": false, "interactionDrugProtein": "NeDRex", "indicationDrugDisorder": "NeDRex","nodeShadow": true,"edgeShadow": true, "algorithms": {"drug": ["trustrank", "closeness", "degree", "proximity"], "drug-target": ["trustrank", "multisteiner", "keypathwayminer", "degree", "closeness", "betweenness"]}, "associatedProteinDisorder": "NeDRex", "nodeGroups":{"important":{"type":"gene","color":"#ff881f","font":{"color":"#000000"},"groupName":"Seed","shape":"star"},"gene":{"type":"gene","color":"#4da300","font":{"color":"#f0f0f0"},"groupName":"Discovered target","shape":"circle"},"foundDrug":{"type":"drug","color":"#F12590","font":{"color":"#000000"},"groupName":"Drug","shape":"diamond"}},"edgeGroups":{"default":{"color":"#000000","groupName":"default edge"}}}' network='{"nodes": [{"id": "DEFA1", "group": "gene"},{"id": "DEFA1", "group": "gene"}, {"id": "CST6", "group": "gene"}, {"id": "IGFBP2", "group": "gene"}, {"id": "TNFSF8", "group": "gene"}, {"id": "COPRS", "group": "gene"}, {"id": "AGT", "group": "important"}, {"id": "IL6", "group": "important"}, {"id": "A2M", "group": "gene"}, {"id": "NLRP3", "group": "important"}, {"id": "TLR4", "group": "important"}, {"id": "TNFSF9", "group": "gene"}, {"id": "RPL18", "group": "gene"}, {"id": "F5", "group": "gene"}, {"id": "IVL", "group": "gene"}, {"id": "IL6R", "group": "gene"}, {"id": "CPB2", "group": "gene"}, {"id": "CCDC8", "group": "gene"}, {"id": "SERPINB6", "group": "gene"}, {"id": "MBL2", "group": "important"}, {"id": "IL1B", "group": "important"}, {"id": "HIST1H3E", "group": "gene"}, {"id": "IL24", "group": "gene"}, {"id": "GSDMB", "group": "gene"}, {"id": "NOTCH2", "group": "gene"}, {"id": "F2", "group": "important"}, {"id": "CCR5", "group": "important"}, {"id": "SERPINB8", "group": "gene"}, {"id": "KRT1", "group": "gene"}, {"id": "IL1RN", "group": "important"}, {"id": "PLAT", "group": "gene"}, {"id": "URB1", "group": "gene"}, {"id": "FCF1", "group": "gene"}, {"id": "ACE", "group": "important"}, {"id": "THBS3", "group": "gene"}, {"id": "CALML3", "group": "gene"}, {"id": "PSMA5", "group": "gene"}, {"id": "NDUFA3", "group": "gene"}, {"id": "PARK2", "group": "gene"}, {"id": "FANCB", "group": "gene"}, {"id": "SERPINB2", "group": "gene"}, {"id": "KLRG2", "group": "gene"}, {"id": "FAM19A3", "group": "gene"}, {"id": "CRYZL1", "group": "gene"}, {"id": "HEATR1", "group": "gene"}, {"id": "IGHG2", "group": "gene"}, {"id": "C17orf70", "group": "gene"}, {"id": "TINAG", "group": "gene"}, {"id": "RSPRY1", "group": "gene"}, {"id": "TMPRSS11A", "group": "gene"}, {"id": "SLC18A1", "group": "gene"}, {"id": "PSMD1", "group": "gene"}, {"id": "PCDHB15", "group": "gene"}, {"id": "TSR3", "group": "gene"}, {"id": "FGL1", "group": "gene"}, {"id": "C7orf60", "group": "gene"}, {"id": "SSR3", "group": "gene"}, {"id": "REN", "group": "gene"}, {"id": "MYH14", "group": "gene"}, {"id": "TBCK", "group": "gene"}, {"id": "DARS", "group": "gene"}, {"id": "C16orf70", "group": "gene"}, {"id": "DQX1", "group": "gene"}, {"id": "RPL30", "group": "gene"}, {"id": "FBXO30", "group": "gene"}, {"id": "EPPK1", "group": "gene"}, {"id": "LAMA1", "group": "gene"}, {"id": "AP4E1", "group": "gene"}, {"id": "AP4S1", "group": "gene"}, {"id": "HIST1H1B", "group": "gene"}, {"id": "AFP", "group": "gene"}], "edges": [{"from": "DEFA1", "to": "PLAT", "group": "default"}, {"from": "DEFA1", "to": "IGFBP2", "group": "default"}, {"from": "CST6", "to": "FCF1", "group": "default"}, {"from": "CST6", "to": "NOTCH2", "group": "default"}, {"from": "IGFBP2", "to": "GSDMB", "group": "default"}, {"from": "TNFSF8", "to": "F5", "group": "default"}, {"from": "TNFSF8", "to": "TNFSF9", "group": "default"}, {"from": "COPRS", "to": "HIST1H3E", "group": "default"}, {"from": "COPRS", "to": "IL6R", "group": "default"}, {"from": "AGT", "to": "ACE", "group": "default"}, {"from": "AGT", "to": "GSDMB", "group": "default"}, {"from": "AGT", "to": "NDUFA3", "group": "default"}, {"from": "AGT", "to": "REN", "group": "default"}, {"from": "IL6", "to": "IL6R", "group": "default"}, {"from": "A2M", "to": "IL1B", "group": "default"}, {"from": "A2M", "to": "CPB2", "group": "default"}, {"from": "NLRP3", "to": "URB1", "group": "default"}, {"from": "NLRP3", "to": "HIST1H1B", "group": "default"}, {"from": "TLR4", "to": "TNFSF9", "group": "default"}, {"from": "TNFSF9", "to": "KLRG2", "group": "default"}, {"from": "RPL18", "to": "FCF1", "group": "default"}, {"from": "RPL18", "to": "URB1", "group": "default"}, {"from": "F5", "to": "F2", "group": "default"}, {"from": "F5", "to": "CCDC8", "group": "default"}, {"from": "F5", "to": "KLRG2", "group": "default"}, {"from": "IVL", "to": "FCF1", "group": "default"}, {"from": "IVL", "to": "KRT1", "group": "default"}, {"from": "IL6R", "to": "FANCB", "group": "default"}, {"from": "IL6R", "to": "CRYZL1", "group": "default"}, {"from": "IL6R", "to": "C17orf70", "group": "default"}, {"from": "IL6R", "to": "TBCK", "group": "default"}, {"from": "CPB2", "to": "F2", "group": "default"}, {"from": "CPB2", "to": "TINAG", "group": "default"}, {"from": "CCDC8", "to": "HEATR1", "group": "default"}, {"from": "CCDC8", "to": "PSMD1", "group": "default"}, {"from": "CCDC8", "to": "DARS", "group": "default"}, {"from": "SERPINB6", "to": "F2", "group": "default"}, {"from": "SERPINB6", "to": "SERPINB8", "group": "default"}, {"from": "SERPINB6", "to": "TMPRSS11A", "group": "default"}, {"from": "SERPINB6", "to": "C16orf70", "group": "default"}, {"from": "MBL2", "to": "KRT1", "group": "default"}, {"from": "IL24", "to": "NOTCH2", "group": "default"}, {"from": "IL24", "to": "CCR5", "group": "default"}, {"from": "F2", "to": "PLAT", "group": "default"}, {"from": "CCR5", "to": "PSMA5", "group": "default"}, {"from": "CCR5", "to": "AFP", "group": "default"}, {"from": "SERPINB8", "to": "FCF1", "group": "default"}, {"from": "IL1RN", "to": "FCF1", "group": "default"}, {"from": "PLAT", "to": "SERPINB2", "group": "default"}, {"from": "PLAT", "to": "FGL1", "group": "default"}, {"from": "PLAT", "to": "LAMA1", "group": "default"}, {"from": "FCF1", "to": "CALML3", "group": "default"}, {"from": "FCF1", "to": "SERPINB2", "group": "default"}, {"from": "FCF1", "to": "IGHG2", "group": "default"}, {"from": "FCF1", "to": "MYH14", "group": "default"}, {"from": "FCF1", "to": "RPL30", "group": "default"}, {"from": "FCF1", "to": "EPPK1", "group": "default"}, {"from": "THBS3", "to": "NDUFA3", "group": "default"}, {"from": "THBS3", "to": "FANCB", "group": "default"}, {"from": "CALML3", "to": "PARK2", "group": "default"}, {"from": "PSMA5", "to": "PARK2", "group": "default"}, {"from": "PSMA5", "to": "HEATR1", "group": "default"}, {"from": "PSMA5", "to": "PSMD1", "group": "default"}, {"from": "PSMA5", "to": "DARS", "group": "default"}, {"from": "NDUFA3", "to": "SLC18A1", "group": "default"}, {"from": "NDUFA3", "to": "DQX1", "group": "default"}, {"from": "FAM19A3", "to": "CRYZL1", "group": "default"}, {"from": "RSPRY1", "to": "TMPRSS11A", "group": "default"}, {"from": "RSPRY1", "to": "SLC18A1", "group": "default"}, {"from": "PCDHB15", "to": "SSR3", "group": "default"}, {"from": "PCDHB15", "to": "TBCK", "group": "default"}, {"from": "TSR3", "to": "FGL1", "group": "default"}, {"from": "TSR3", "to": "C7orf60", "group": "default"}, {"from": "C7orf60", "to": "REN", "group": "default"}, {"from": "SSR3", "to": "MYH14", "group": "default"}, {"from": "C16orf70", "to": "FBXO30", "group": "default"}, {"from": "DQX1", "to": "FBXO30", "group": "default"}, {"from": "LAMA1", "to": "AP4E1", "group": "default"}, {"from": "AP4E1", "to": "AP4S1", "group": "default"}, {"from": "AP4S1", "to": "AFP", "group": "default"}]}'> </drugst-one> -- GitLab