-
Julian Matschinske authoredJulian Matschinske authored
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
explorer-page.component.ts 12.78 KiB
import {
AfterViewInit,
Component,
ElementRef, Input,
OnInit,
ViewChild
} from '@angular/core';
import {
NodeInteraction,
Node,
Wrapper,
getWrapperFromProtein,
Tissue, getNodeIdsFromI
} from '../../interfaces';
import {ProteinNetwork} from '../../main-network';
import {HttpClient} from '@angular/common/http';
import {AnalysisService} from '../../analysis.service';
import html2canvas from 'html2canvas';
import {NetworkSettings} from '../../network-settings';
import {defaultConfig, IConfig} from '../../config';
declare var vis: any;
@Component({
selector: 'app-explorer-page',
templateUrl: './explorer-page.component.html',
styleUrls: ['./explorer-page.component.scss'],
})
export class ExplorerPageComponent implements OnInit, AfterViewInit {
private networkJSON = '{"nodes": [], "edges": []}';
public myConfig: IConfig = JSON.parse(JSON.stringify(defaultConfig));
@Input()
public onload: undefined | string;
@Input()
public set config(config: string | undefined) {
if (typeof config === 'undefined') {
return;
}
const configObj = JSON.parse(config);
for (const key of Object.keys(configObj)) {
if (key === 'nodeGroups' || key === 'edgeGroups') {
this.myConfig[key] = {...this.myConfig[key], ...configObj[key]};
continue;
}
this.myConfig[key] = configObj[key];
}
}
@Input()
public set network(network: string | undefined) {
if (typeof network === 'undefined') {
return;
}
this.networkJSON = network;
this.createNetwork();
}
public get network() {
return this.networkJSON;
}
public showDetails = false;
public selectedWrapper: Wrapper | null = null;
public collapseAnalysisQuick = true;
public collapseAnalysis = true;
public collapseDetails = true;
public collapseTask = true;
public collapseSelection = true;
public collapseBaitFilter = true;
public collapseQuery = true;
public collapseData = true;
public collapseOverview = true;
public proteinData: ProteinNetwork;
public proteins: any;
public edges: any;
private networkInternal: any;
public nodeData: { nodes: any, edges: any } = {nodes: null, edges: null};
private dumpPositions = false;
public physicsEnabled = false;
public queryItems: Wrapper[] = [];
public showAnalysisDialog = false;
public showThresholdDialog = false;
public analysisDialogTarget: 'drug' | 'drug-target';
public showCustomProteinsDialog = false;
public selectedAnalysisToken: string | null = null;
public currentDataset = [];
public currentViewProteins: Node[];
public currentViewSelectedTissue: Tissue | null = null;
public currentViewNodes: any[];
public expressionExpanded = false;
public selectedTissue: Tissue | null = null;
@Input()
public textColor = 'red';
@ViewChild('network', {static: false}) networkEl: ElementRef;
constructor(private http: HttpClient, public analysis: AnalysisService) {
this.showDetails = false;
this.analysis.subscribeList((items, selected) => {
if (!this.nodeData.nodes) {
return;
}
if (selected !== null) {
if (items.length === 0) {
return;
}
const updatedNodes = [];
for (const item of items) {
const node = this.nodeData.nodes.get(item.nodeId);
if (!node) {
continue;
}
const pos = this.networkInternal.getPositions([item.nodeId]);
node.x = pos[item.nodeId].x;
node.y = pos[item.nodeId].y;
node.x = pos[item.nodeId].x;
node.y = pos[item.nodeId].y;
Object.assign(node, this.myConfig.nodeGroups[node.wrapper.data.group]);
updatedNodes.push(node);
}
this.nodeData.nodes.update(updatedNodes);
} else {
const updatedNodes = [];
this.nodeData.nodes.forEach((node) => {
const nodeSelected = this.analysis.idInSelection(node.id);
Object.assign(node, this.myConfig.nodeGroups[node.wrapper.data.group]);
});
this.nodeData.nodes.update(updatedNodes);
}
});
}
ngOnInit() {
}
async ngAfterViewInit() {
this.createNetwork();
if (this.onload) {
// tslint:disable-next-line:no-eval
eval(this.onload);
}
}
private getNetwork() {
const network = JSON.parse(this.networkJSON);
this.proteins = network.nodes;
this.edges = network.edges;
}
private zoomToNode(id: string) {
this.nodeData.nodes.getIds();
const coords = this.networkInternal.getPositions(id)[id];
if (!coords) {
return;
}
let zoomScale = null;
if (id.startsWith('eff')) {
zoomScale = 1.0;
} else {
zoomScale = 3.0;
}
this.networkInternal.moveTo({
position: {x: coords.x, y: coords.y},
scale: zoomScale,
animation: true,
});
}
public async openSummary(item: Wrapper, zoom: boolean) {
this.selectedWrapper = item;
if (zoom) {
this.zoomToNode(item.nodeId);
}
this.showDetails = true;
}
public async closeSummary() {
this.selectedWrapper = null;
this.showDetails = false;
}
public async createNetwork() {
this.analysis.resetSelection();
this.selectedWrapper = null;
this.getNetwork();
this.proteinData = new ProteinNetwork(this.proteins, this.edges);
this.proteinData.linkNodes();
// Populate baits
const effectNames = [];
const {nodes, edges} = this.mapDataToNodes(this.proteinData);
this.nodeData.nodes = new vis.DataSet(nodes);
this.nodeData.edges = new vis.DataSet(edges);
const container = this.networkEl.nativeElement;
const options = NetworkSettings.getOptions('main');
this.networkInternal = new vis.Network(container, this.nodeData, options);
this.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);
const wrapper = node.wrapper;
if (this.analysis.inSelection(wrapper)) {
this.analysis.removeItems([wrapper]);
} else {
this.analysis.addItems([wrapper]);
}
}
});
this.networkInternal.on('click', (properties) => {
const nodeIds: Array<string> = properties.nodes;
if (nodeIds.length > 0) {
const nodeId = nodeIds[0];
const node = this.nodeData.nodes.get(nodeId);
const wrapper = node.wrapper;
this.openSummary(wrapper, false);
} else {
this.closeSummary();
}
});
this.networkInternal.on('deselectNode', (properties) => {
this.closeSummary();
});
if (this.selectedWrapper) {
this.zoomToNode(this.selectedWrapper.nodeId);
}
this.queryItems = [];
this.fillQueryItems(this.proteins);
if (this.selectedWrapper) {
this.networkInternal.selectNodes([this.selectedWrapper.nodeId]);
}
}
fillQueryItems(hostProteins: Node[]) {
this.queryItems = [];
hostProteins.forEach((protein) => {
this.queryItems.push(getWrapperFromProtein(protein));
});
this.currentViewNodes = this.nodeData.nodes;
this.currentViewProteins = this.proteins;
}
public queryAction(item: any) {
if (item) {
this.openSummary(item, true);
}
}
public updatePhysicsEnabled(bool) {
this.physicsEnabled = bool;
this.networkInternal.setOptions({
physics: {
enabled: this.physicsEnabled,
stabilization: {
enabled: false,
},
}
});
}
private mapCustomNode(customNode: Node): any {
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]));
let nodeLabel = customNode.name;
if (customNode.name.length === 0) {
nodeLabel = customNode.id;
}
node.label = nodeLabel;
node.id = customNode.id;
node.x = customNode.x;
node.y = customNode.y;
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');
const a = document.createElement('a');
a.href = generatedImage;
a.download = `Network.png`;
a.click();
});
}
analysisWindowChanged($event: [any[], [Node[], Tissue]]) {
if ($event) {
this.currentViewNodes = $event[0];
this.currentViewProteins = $event[1][0];
this.currentViewSelectedTissue = $event[1][1];
} else {
this.currentViewNodes = this.nodeData.nodes;
this.currentViewProteins = this.proteins;
this.currentViewSelectedTissue = this.selectedTissue;
}
}
gProfilerLink(): string {
const queryString = this.analysis.getSelection()
.filter(wrapper => wrapper.type === 'protein')
.map(wrapper => wrapper.data.proteinAc)
.join('%0A');
return 'http://biit.cs.ut.ee/gprofiler/gost?' +
'organism=hsapiens&' +
`query=${queryString}&` +
'ordered=false&' +
'all_results=false&' +
'no_iea=false&' +
'combined=false&' +
'measure_underrepresentation=false&' +
'domain_scope=annotated&' +
'significance_threshold_method=g_SCS&' +
'user_threshold=0.05&' +
'numeric_namespace=ENTREZGENE_ACC&' +
'sources=GO:MF,GO:CC,GO:BP,KEGG,TF,REAC,MIRNA,HPA,CORUM,HP,WP&' +
'background=';
}
public selectTissue(tissue: Tissue | null) {
this.expressionExpanded = false;
if (!tissue) {
this.selectedTissue = null;
const updatedNodes = [];
for (const protein of this.proteins) {
const item = getWrapperFromProtein(protein);
const node = this.nodeData.nodes.get(item.nodeId);
if (!node) {
continue;
}
const pos = this.networkInternal.getPositions([item.nodeId]);
node.x = pos[item.nodeId].x;
node.y = pos[item.nodeId].y;
Object.assign(node,
NetworkSettings.getNodeStyle(
node.wrapper.type,
node.isSeed,
this.analysis.inSelection(item),
undefined,
undefined,
1.0));
node.wrapper = item;
node.gradient = 1.0;
protein.expressionLevel = undefined;
(node.wrapper.data as Node).expressionLevel = undefined;
updatedNodes.push(node);
}
this.nodeData.nodes.update(updatedNodes);
} else {
this.selectedTissue = tissue;
const minExp = 0.3;
// const params = new HttpParams().set('tissue', `${tissue.id}`).set('data', JSON.stringify(this.currentDataset));
// this.http.get<any>(
// `${environment.backend}tissue_expression/`, {params})
// .subscribe((levels) => {
// const updatedNodes = [];
// const maxExpr = Math.max(...levels.map(lvl => lvl.level));
// for (const lvl of levels) {
// const item = getWrapperFromProtein(lvl.protein);
// const node = this.nodeData.nodes.get(item.nodeId);
// if (!node) {
// continue;
// }
// const gradient = lvl.level !== null ? (Math.pow(lvl.level / maxExpr, 1 / 3) * (1 - minExp) + minExp) : -1;
// const pos = this.network.getPositions([item.nodeId]);
// node.x = pos[item.nodeId].x;
// node.y = pos[item.nodeId].y;
// Object.assign(node,
// NetworkSettings.getNodeStyle(
// node.wrapper.type,
// node.isSeed,
// this.analysis.inSelection(item),
// undefined,
// undefined,
// gradient));
// node.wrapper = item;
// node.gradient = gradient;
// this.proteins.find(prot => getProteinNodeId(prot) === item.nodeId).expressionLevel = lvl.level;
// (node.wrapper.data as Protein).expressionLevel = lvl.level;
// updatedNodes.push(node);
// }
// this.nodeData.nodes.update(updatedNodes);
// });
}
this.currentViewSelectedTissue = this.selectedTissue;
}
}