Skip to content
Snippets Groups Projects
Commit bcfe5cb7 authored by Julian Späth's avatar Julian Späth
Browse files

Merge branch 'display-drug-ranks' into 'master'

Adapt Analysis Window

See merge request covid-19/frontend!47
parents d184e0cd da5b8596
Branches
Tags
No related merge requests found
Showing
with 181 additions and 179 deletions
......@@ -62,6 +62,10 @@ export class AnalysisService {
return this.selectedProteins.has(protein.proteinAc);
}
idInSelection(id: string): boolean {
return this.selectedProteins.has(id);
}
removeProtein(protein: Protein) {
if (this.selectedProteins.delete(`${protein.proteinAc}`)) {
this.selectSubject.next({protein, selected: false});
......
......@@ -44,7 +44,7 @@
</button>
</p>
<p class="control">
<button class="button is-danger is-rounded" (click)="analysis.removeTask(token)">
<button class="button is-danger is-rounded" (click)="analysis.removeTask(token); close()">
<span class="icon">
<i class="fas fa-trash" aria-hidden="true"></i>
</span>
......
......@@ -12,7 +12,7 @@ import {
import {HttpClient} from '@angular/common/http';
import {environment} from '../../../environments/environment';
import {AnalysisService} from '../../analysis.service';
import {Protein, Task} from '../../interfaces';
import {Protein, Task, NodeType} from '../../interfaces';
declare var vis: any;
......@@ -34,7 +34,6 @@ export class AnalysisWindowComponent implements OnInit, OnChanges {
private nodeData: { nodes: any, edges: any } = {nodes: null, edges: null};
private drugNodes = [];
public showDrugs = false;
private result: any;
constructor(private http: HttpClient, public analysis: AnalysisService) {
}
......@@ -51,57 +50,33 @@ export class AnalysisWindowComponent implements OnInit, OnChanges {
this.task = await this.getTask(this.token);
if (this.task && this.task.info.done) {
const result = await this.http.get<any>(`${environment.backend}result/?token=${this.token}`).toPromise();
this.result = result;
const result = await this.http.get<any>(`${environment.backend}task_result/?token=${this.token}`).toPromise();
// Reset
this.nodeData = {nodes: null, edges: null};
this.networkEl.nativeElement.innerHTML = '';
this.network = null;
this.showDrugs = false;
this.nodeData = {nodes: null, edges: null};
this.createNetwork(result);
}
}
}
private async getTask(token: string): Promise<any> {
return await this.http.get(`${environment.backend}task/?token=${token}`).toPromise();
}
close() {
this.token = null;
this.tokenChange.emit(this.token);
}
discard() {
}
export() {
}
public async createNetwork(result: any) {
const {nodes, edges} = this.mapDataToNodes(result);
// Create
const {nodes, edges} = this.createNetwork(result);
this.nodeData.nodes = new vis.DataSet(nodes);
this.nodeData.edges = new vis.DataSet(edges);
const container = this.networkEl.nativeElement;
const options = {
layout: {
improvedLayout: false,
},
};
const options = {};
this.network = new vis.Network(container, this.nodeData, options);
this.network.on('select', (properties) => {
const id: Array<string> = properties.nodes;
if (id.length > 0) {
if (id[0].startsWith('p_')) {
const protein = this.getProtein(id[0].substr(2));
const selectedNodes = this.nodeData.nodes.get(properties.nodes);
if (selectedNodes.length > 0) {
if (selectedNodes[0].nodeType === 'host') {
const protein: Protein = {name: '', proteinAc: selectedNodes[0].id};
if (properties.event.srcEvent.ctrlKey) {
if (this.inSelection(protein.proteinAc) === true) {
this.removeFromSelection(protein.proteinAc);
if (this.analysis.inSelection(protein) === true) {
this.analysis.removeProtein(protein);
} else {
this.addToSelection(protein.proteinAc);
this.analysis.addProtein(protein);
this.analysis.getCount();
}
}
......@@ -110,7 +85,7 @@ export class AnalysisWindowComponent implements OnInit, OnChanges {
});
this.analysis.subscribe((protein, selected) => {
const nodeId = `p_${protein.proteinAc}`;
const nodeId = `${protein.proteinAc}`;
const node = this.nodeData.nodes.get(nodeId);
if (!node) {
return;
......@@ -118,122 +93,117 @@ export class AnalysisWindowComponent implements OnInit, OnChanges {
const pos = this.network.getPositions([nodeId]);
node.x = pos[nodeId].x;
node.y = pos[nodeId].y;
if (selected) {
node.color = '#48C774';
this.nodeData.nodes.update(node);
} else {
node.color = '#e2b600';
const {color} = this.getNodeLooks(nodeId, node.nodeType, node.isSeed);
node.color = color;
this.nodeData.nodes.update(node);
}
});
}
inSelection(proteinAc: string): boolean {
if (!this.result.proteins || !proteinAc) {
return false;
}
const protein = this.getProtein(proteinAc);
if (!protein) {
return false;
}
return this.analysis.inSelection(protein);
}
addToSelection(proteinAc: string) {
if (!this.result.proteins || !proteinAc) {
return false;
private async getTask(token: string): Promise<any> {
return await this.http.get(`${environment.backend}task/?token=${token}`).toPromise();
}
const protein = this.getProtein(proteinAc);
if (!protein) {
return false;
close() {
this.token = null;
this.tokenChange.emit(this.token);
}
this.analysis.addProtein(protein);
discard() {
}
removeFromSelection(proteinAc: string) {
if (!this.result.proteins || !proteinAc) {
return false;
export() {
}
const protein = this.getProtein(proteinAc);
if (!protein) {
return false;
public inferNodeType(nodeId: string): 'host' | 'virus' | 'drug' {
if (nodeId.indexOf('-') !== -1 || nodeId.indexOf('_') !== -1) {
return 'virus';
}
this.analysis.removeProtein(protein);
return 'host';
}
public getProtein(ac: string): Protein | undefined {
return this.result.proteins.find((p) => p.proteinAc === ac);
}
public createNetwork(result: any): { edges: any[], nodes: any[] } {
const nodes = [];
const edges = [];
const nodeAttributes = result.nodeAttributes || [];
private mapProteinToNode(protein: any): any {
let color = '#e2b600';
if (this.analysis.inSelection(protein)) {
color = '#48C774';
}
return {
id: `p_${protein.proteinAc}`,
label: `${protein.proteinAc}`,
size: 10, color, shape: 'ellipse', shadow: false,
};
}
for (let i = 0; i < result.networks.length; i++) {
const network = result.networks[i];
private mapDrugToNode(drug: any): any {
let color = '#ffffff';
if (drug.status === 'investigational') {
color = '#ffa066';
} else if (drug.status === 'approved') {
color = '#a0ff66';
}
return {
id: `d_${drug.drugId}`,
label: `${drug.name}`,
size: 10, color, shape: 'ellipse', shadow: true, font: {color: '#000000', size: 5},
};
const attributes = nodeAttributes[i] || {};
const nodeTypes = attributes.nodeTypes || {};
const isSeed = attributes.isSeed || {};
const scores = attributes.scores || {};
for (const node of network.nodes) {
nodes.push(this.mapNode(node, nodeTypes[node] || this.inferNodeType(node), isSeed[node], scores[node]));
}
private mapProteinProteinInteractionToEdge(edge: any): any {
return {
from: `p_${edge.from}`,
to: `p_${edge.to}`,
color: {color: '#afafaf', highlight: '#854141'},
};
for (const edge of network.edges) {
edges.push(this.mapEdge(edge));
}
}
private mapDrugProteinInteractionToEdge(edge: any): any {
return {
from: `p_${edge.proteinAc}`,
to: `d_${edge.drugId}`,
color: {color: '#afafaf', highlight: '#854141'},
nodes,
edges,
};
}
private mapDataToNodes(result: any): { nodes: any[], edges: any[] } {
const nodes = [];
const edges = [];
private getNodeLooks(nodeId: string, nodeType: NodeType, isSeed: boolean):
{ color: string, shape: string, size: number, font: any, shadow: boolean } {
let color = '';
let shape = '';
let size = 10;
let font = {};
let shadow = false;
for (const protein of result.proteins) {
nodes.push(this.mapProteinToNode(protein));
if (nodeType === 'host') {
shape = 'ellipse';
if (this.analysis.idInSelection(nodeId)) {
color = '#c7661c';
} else {
color = '#e2b600';
}
this.drugNodes = [];
for (const drug of result.drugs) {
this.drugNodes.push(this.mapDrugToNode(drug));
size = 10;
} else if (nodeType === 'virus') {
shape = 'box';
color = '#118AB2';
size = 12;
font = {color: 'white'};
shadow = true;
} else if (nodeType === 'drug') {
shape = 'ellipse';
color = '#26b28b';
size = 6;
}
for (const network of result.networks) {
for (const edge of network.ppEdges) {
edges.push(this.mapProteinProteinInteractionToEdge(edge));
if (isSeed) {
color = '#c064c7';
}
return {color, shape, size, font, shadow};
}
for (const edge of result.dpEdges) {
edges.push(this.mapDrugProteinInteractionToEdge(edge));
private mapNode(nodeId: any, nodeType?: NodeType, isSeed?: boolean, score?: number): any {
const {shape, color, size, font, shadow} = this.getNodeLooks(nodeId, nodeType, isSeed);
return {
id: nodeId,
label: nodeId,
size, color, shape, font, shadow,
nodeType, isSeed,
};
}
private mapEdge(edge: any): any {
return {
nodes,
edges,
from: `${edge.from}`,
to: `${edge.to}`,
color: {color: '#afafaf', highlight: '#854141'},
};
}
......
......@@ -30,7 +30,6 @@ export class LaunchAnalysisComponent implements OnInit {
public multisteinerStrain = 'SARS_CoV2';
public multisteinerNumTrees = 5;
constructor(public analysis: AnalysisService) {
}
......@@ -44,13 +43,13 @@ export class LaunchAnalysisComponent implements OnInit {
public async startTask() {
const parameters: any = {
proteins: this.analysis.getSelection().map((protein) => protein.proteinAc),
seeds: this.analysis.getSelection().map((protein) => protein.proteinAc),
};
if (this.algorithm === 'dummy') {
// No parameters for dummy
} else if (this.algorithm === 'trustrank') {
parameters.strain = this.trustrankStrain;
parameters.strain_or_drugs = this.trustrankStrain;
parameters.datasets = [];
parameters.ignored_edge_types = [];
parameters.damping_factor = this.trustrankDampingFactor;
......
<div class="content">
<ng-select [items]="datasetItems" bindLabel="label" [virtualScroll]="true" class="custom"
<ng-select [items]="datasetItems" bindLabel="id" [virtualScroll]="true" class="custom"
placeholder="Select..." [ngModel]="selectedDataset" (ngModelChange)="select($event)">
<ng-template ng-option-tmp let-item="item">
{{item.label}} <br/>
......
......@@ -14,10 +14,8 @@ export class SelectDatasetComponent {
@Input() datasetItems: Array<{label: string, datasets: string, data: Array<[string, string]>}>;
public select(selectionItem) {
// console.log(selectionItem);
this.selectedDataset = selectionItem;
this.selectedDatasetChange.emit(selectionItem);
}
}
......@@ -2,26 +2,41 @@
<div class="list is-hoverable">
<a *ngFor="let task of analysis.tasks" class="list-item" [class.is-active]="task.token === token">
<div *ngIf="!task.info.startedAt" (click)="open(task.token)">
<span><b>{{task.info.algorithm}} (Queued)</b></span>
<span class="icon"><i class="fas fa-pause" aria-hidden="true"></i></span><br>
Queue Length: {{task.stats.queueLength}}<br>
Queue Position:{{task.stats.queuePosition}}
<p>
<span class="is-capitalized">{{task.info.algorithm}}</span>
<span class="icon is-pulled-right"><i class="fas fa-pause" aria-hidden="true"></i></span>
</p>
<p>
<small>Queue position: {{task.stats.queuePosition}}/{{task.stats.queueLength}}</small>
</p>
</div>
<div *ngIf="task.info.startedAt && !task.info.done && !task.info.failed" (click)="open(task.token)">
<span><b>{{task.info.algorithm}} ({{task.info.startedAt | date :'short'}})</b></span>
<span class="icon"><i class="fas fa-spinner" aria-hidden="true"></i></span>
<br>
<progress class="progress is-primary" [value]="task.info.progress * 100" max="100"></progress>
<div *ngIf="!task.info.done && !task.info.failed && task.info.startedAt" (click)="open(task.token)">
<p>
<span class="is-capitalized">{{task.info.algorithm}}</span>
<span class="icon is-pulled-right"><i class="fas fa-spinner fa-spin" aria-hidden="true"></i></span>
</p>
<p>
<small>Started {{task.info.startedAt | date :'short'}}</small>
</p>
<progress class="progress is-primary" [value]="task.info.progress * 100" max="100">Test</progress>
</div>
<div *ngIf="task.info.failed && task.info.finishedAt == null">
<span><b>{{task.info.algorithm}} ({{task.info.startedAt | date :'short'}})</b></span>
<span class="icon"><i class="fas fa-exclamation-triangle" aria-hidden="true"></i>
</span>
<div *ngIf="task.info.done" (click)="open(task.token)">
<p>
<span class="is-capitalized">{{task.info.algorithm}}</span>
<span class="icon is-pulled-right"><i class="fas fa-check" aria-hidden="true"></i></span>
</p>
<p>
<small>Finished {{task.info.finishedAt | date :'short'}}</small>
</p>
</div>
<div *ngIf="task.info.done && !task.info.failed" (click)="open(task.token)">
<span><b>{{task.info.algorithm}} ({{task.info.startedAt | date :'short'}})</b></span>
<span class="icon"><i class="fas fa-check" aria-hidden="true"></i>
</span>
<div *ngIf="task.info.failed && task.info.finishedAt == null">
<p>
<span class="is-capitalized">{{task.info.algorithm}}</span>
<span class="icon is-pulled-right"><i class="fas fa-exclamation-triangle" aria-hidden="true"></i></span>
</p>
<p class="has-text-danger">
<small>{{task.info.status}}</small>
</p>
</div>
</a>
</div>
......
.list {
p {
margin-bottom: 0;
}
progress {
margin-top: 5px;
margin-bottom: 5px;
}
}
export type NodeType = 'host' | 'virus' | 'drug';
export interface Protein {
name: string;
proteinAc: string;
......@@ -25,7 +27,7 @@ export interface ProteinViralInteraction {
export interface Task {
token: string;
info: {
algorithm: string;
algorithm: 'trustrank' | 'multisteiner' | 'keypathwayminer';
parameters?: { [key: string]: any };
workerId?: string;
......
......@@ -281,7 +281,7 @@
<app-task-list [(token)]="selectedAnalysisToken"></app-task-list>
</div>
<footer class="card-footer">
<a (click)="analysis.removeAllTasks();" class="card-footer-item has-text-danger">
<a (click)="analysis.removeAllTasks(); selectedAnalysisToken = null;" class="card-footer-item has-text-danger">
<span class="icon">
<i class="fa fa-trash"></i>
</span>
......
......@@ -58,15 +58,19 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit {
public currentDataset = [];
private screenshotArray = [0];
public datasetItems: Array<{ label: string, datasets: string, data: Array<[string, string]> }> = [
{label: 'All', datasets: 'TUM & Krogan', data: [['TUM', 'HCoV'], ['TUM', 'SARS-CoV2'], ['Krogan', 'SARS-CoV2']]},
{label: 'HCoV', datasets: 'TUM', data: [['TUM', 'HCoV']]},
{label: 'CoV2', datasets: 'TUM & Krogan', data: [['TUM', 'SARS-CoV2'], ['Krogan', 'SARS-CoV2']]},
{label: 'CoV2', datasets: 'Krogan', data: [['Krogan', 'SARS-CoV2']]},
{label: 'CoV2', datasets: 'TUM', data: [['TUM', 'SARS-CoV2']]}];
public selectedDataset = this.datasetItems[0];
public datasetItems: Array<{ id: string, label: string, datasets: string, data: Array<[string, string]> }> = [
{
id: 'All (TUM & Krogan)',
label: 'All',
datasets: 'TUM & Krogan',
data: [['TUM', 'HCoV'], ['TUM', 'SARS-CoV2'], ['Krogan', 'SARS-CoV2']]
},
{id: 'HCoV (TUM)', label: 'HCoV', datasets: 'TUM', data: [['TUM', 'HCoV']]},
{id: 'CoV2 (TUM & Krogan)', label: 'CoV2', datasets: 'TUM & Krogan', data: [['TUM', 'SARS-CoV2'], ['Krogan', 'SARS-CoV2']]},
{id: 'CoV2 (Krogan)', label: 'CoV2', datasets: 'Krogan', data: [['Krogan', 'SARS-CoV2']]},
{id: 'CoV2 (TUM)', label: 'CoV2', datasets: 'TUM', data: [['TUM', 'SARS-CoV2']]}];
public selectedDataset = this.datasetItems[3];
@ViewChild('network', {static: false}) networkEl: ElementRef;
......@@ -132,8 +136,8 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit {
async ngAfterViewInit() {
if (!this.network) {
this.selectedDataset = this.datasetItems[4];
await this.createNetwork(this.datasetItems[4].data);
this.selectedDataset = this.datasetItems[3];
await this.createNetwork(this.selectedDataset.data);
}
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment