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

Merge branch 'scores' into 'master'

Scores

See merge request covid-19/frontend!60
parents 9245f123 b6dbd884
No related branches found
No related tags found
No related merge requests found
...@@ -101,58 +101,101 @@ ...@@ -101,58 +101,101 @@
</footer> </footer>
</div> </div>
<div class="content tab-content scrollable" *ngIf="task && task.info.done" [class.is-visible]="tab === 'table'"> <div class="content tab-content scrollable" *ngIf="task && task.info.done" [class.is-visible]="tab === 'table'">
<h4 class="is-4" *ngIf="tableDrugs.length > 0">Drugs</h4> <div class="field has-addons footer-toggle-buttons" *ngIf="tableHasScores">
<p class="control">
<button class="button is-rounded" [class.is-primary]="tableNormalize" (click)="toggleNormalization(true)">
<span class="icon is-small">
<i class="fa fa-ruler-vertical"></i>
</span>
<span>Normalization On</span>
</button>
</p>
<p class="control">
<button class="button is-rounded" [class.is-primary]="!tableNormalize" (click)="toggleNormalization(false)">
<span>Off</span>
</button>
</p>
</div>
<div *ngIf="tableDrugs.length > 0">
<h4 class="is-4">
<span class="icon"><i class="fa fa-capsules"></i></span>
<span>Drugs</span>
</h4>
<a [href]="downloadLink('drugs')" class="button is-primary is-outlined is-pulled-right is-small">
<span class="icon"><i class="fa fa-download"></i></span>
<span>Download</span>
</a>
</div>
<table class="table is-striped" *ngIf="tableDrugs.length > 0"> <table class="table is-striped" *ngIf="tableDrugs.length > 0">
<thead> <thead>
<tr> <tr>
<td>ID</td> <td>ID</td>
<td>Name</td> <td>Name</td>
<td>Status</td> <td>Status</td>
<td>Score</td> <td *ngIf="tableHasScores">Score</td>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr *ngFor="let e of tableDrugs"> <tr *ngFor="let e of tableDrugs">
<td>{{e.drugId}}</td> <td><a href="https://www.drugbank.ca/drugs/{{ e.drugId }}" target="_blank">{{ e.drugId }}</a></td>
<td>{{e.name}}</td> <td>{{e.name}}</td>
<td>{{e.status}}</td> <td>{{e.status}}</td>
<td>{{e.score}}</td> <td *ngIf="tableHasScores">{{e.score}}</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
<h4 class="is-4" *ngIf="tableProteins.length > 0">Proteins</h4> <div *ngIf="tableProteins.length > 0">
<h4 class="is-4">
<span class="icon"><i class="fa fa-dna"></i></span>
<span>Proteins</span>
</h4>
<a [href]="downloadLink('proteins')" class="button is-primary is-outlined is-pulled-right is-small">
<span class="icon"><i class="fa fa-download"></i></span>
<span>Download</span>
</a>
</div>
<table class="table is-striped" *ngIf="tableProteins.length > 0"> <table class="table is-striped" *ngIf="tableProteins.length > 0">
<thead> <thead>
<tr> <tr>
<td>AC</td> <td>AC</td>
<td>Gene</td> <td>Gene</td>
<td>Score</td> <td *ngIf="tableHasScores">Score</td>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr *ngFor="let e of tableProteins"> <tr *ngFor="let e of tableProteins">
<td>{{e.proteinAc}}</td> <td><a href="https://www.uniprot.org/uniprot/{{ e.proteinAc }}" target="_blank">{{ e.proteinAc }}</a></td>
<td>{{e.name}}</td> <td>{{e.name}}</td>
<td>{{e.score}}</td> <td *ngIf="tableHasScores">{{e.score}}</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
<h4 class="is-4" *ngIf="tableViralProteins.length > 0">Viral Proteins</h4> <div *ngIf="tableViralProteins.length > 0">
<h4 class="is-4">
<span class="icon"><i class="fa fa-virus"></i></span>
<span>Viral Proteins</span>
</h4>
<a [href]="downloadLink('viral_proteins')" class="button is-primary is-outlined is-pulled-right is-small">
<span class="icon"><i class="fa fa-download"></i></span>
<span>Download</span>
</a>
</div>
<table class="table is-striped" *ngIf="tableViralProteins.length > 0"> <table class="table is-striped" *ngIf="tableViralProteins.length > 0">
<thead> <thead>
<tr> <tr>
<td>Name</td> <td>Name</td>
<td>Virus Strain</td> <td>Virus Strain</td>
<td>Score</td> <td *ngIf="tableHasScores">Score</td>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr *ngFor="let e of tableViralProteins"> <tr *ngFor="let e of tableViralProteins">
<td>{{e.effectName}}</td> <td>{{e.effectName}}</td>
<td>{{e.virusName}}</td> <td>{{e.virusName}}</td>
<td>{{e.score}}</td> <td *ngIf="tableHasScores">{{e.score}}</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
......
...@@ -20,5 +20,10 @@ div.network { ...@@ -20,5 +20,10 @@ div.network {
&.scrollable { &.scrollable {
overflow-y: auto; overflow-y: auto;
padding-right: 10px;
}
h4 {
margin-top: 60px;
} }
} }
...@@ -17,6 +17,11 @@ import html2canvas from 'html2canvas'; ...@@ -17,6 +17,11 @@ import html2canvas from 'html2canvas';
declare var vis: any; 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)
}
@Component({ @Component({
selector: 'app-analysis-window', selector: 'app-analysis-window',
templateUrl: './analysis-window.component.html', templateUrl: './analysis-window.component.html',
...@@ -42,9 +47,11 @@ export class AnalysisWindowComponent implements OnInit, OnChanges { ...@@ -42,9 +47,11 @@ export class AnalysisWindowComponent implements OnInit, OnChanges {
public showDrugs = false; public showDrugs = false;
public tab = 'network'; public tab = 'network';
public tableDrugs: Array<any> = []; public tableDrugs: Array<Drug & Scored> = [];
public tableProteins: Array<any> = []; public tableProteins: Array<Protein & Scored> = [];
public tableViralProteins: Array<any> = []; public tableViralProteins: Array<ViralProtein & Scored> = [];
public tableNormalize = false;
public tableHasScores = false;
constructor(private http: HttpClient, public analysis: AnalysisService) { constructor(private http: HttpClient, public analysis: AnalysisService) {
} }
...@@ -74,45 +81,38 @@ export class AnalysisWindowComponent implements OnInit, OnChanges { ...@@ -74,45 +81,38 @@ export class AnalysisWindowComponent implements OnInit, OnChanges {
this.nodeData.nodes = new vis.DataSet(nodes); this.nodeData.nodes = new vis.DataSet(nodes);
this.nodeData.edges = new vis.DataSet(edges); this.nodeData.edges = new vis.DataSet(edges);
// Fill tables
result.networks.forEach((network, i) => {
const attributes = result.nodeAttributes[i];
const nodeTypes = attributes.nodeTypes || {};
const nodeDetails = attributes.details || {};
const nodeScores = attributes.scores || {};
const normalizeScore = network.maxScore || 1.0;
network.nodes.forEach((nodeId, j) => {
const nodeType = nodeTypes[nodeId] || this.inferNodeType(nodeId);
const entry = nodeDetails[nodeId] || {};
entry.score = nodeScores[nodeId] || null;
if (entry.score) {
entry.score /= normalizeScore;
}
switch (nodeType) {
case 'drug':
this.tableDrugs.push(entry);
break;
case 'host':
this.tableProteins.push(entry);
break;
case 'virus':
this.tableViralProteins.push(entry);
break;
}
});
});
this.tableDrugs = this.tableDrugs.reverse();
this.tableProteins = this.tableProteins.reverse();
this.tableViralProteins = this.tableViralProteins.reverse();
const container = this.networkEl.nativeElement; const container = this.networkEl.nativeElement;
const options = {}; const options = {};
this.network = new vis.Network(container, this.nodeData, options); this.network = new vis.Network(container, this.nodeData, options);
const promises: Promise<any>[] = [];
promises.push(this.http.get<any>(`${environment.backend}task_result/?token=${this.token}&view=proteins`).toPromise()
.then((table) => {
this.tableProteins = table;
this.tableProteins.forEach((r) => r.rawScore = r.score);
}));
promises.push(this.http.get<any>(`${environment.backend}task_result/?token=${this.token}&view=viral_proteins`).toPromise()
.then((table) => {
this.tableViralProteins = table;
this.tableViralProteins.forEach((r) => r.rawScore = r.score);
}));
promises.push(this.http.get<any>(`${environment.backend}task_result/?token=${this.token}&view=drugs`).toPromise()
.then((table) => {
this.tableDrugs = table;
this.tableDrugs.forEach((r) => r.rawScore = r.score);
}));
await Promise.all(promises);
this.tableHasScores = this.task.info.algorithm === 'trustrank';
if (this.tableHasScores) {
this.toggleNormalization(true);
}
this.network.on('deselectNode', (properties) => { this.network.on('deselectNode', (properties) => {
this.showDetailsChange.emit([false, [null, null, null, null, null, null]]); this.showDetailsChange.emit([false, [null, null, null, null, null, null]]);
}); });
this.network.on('selectNode', (properties) => { this.network.on('selectNode', (properties) => {
const selectedNodes = this.nodeData.nodes.get(properties.nodes); const selectedNodes = this.nodeData.nodes.get(properties.nodes);
if (selectedNodes.length > 0) { if (selectedNodes.length > 0) {
...@@ -169,7 +169,6 @@ export class AnalysisWindowComponent implements OnInit, OnChanges { ...@@ -169,7 +169,6 @@ export class AnalysisWindowComponent implements OnInit, OnChanges {
} else { } else {
this.showDetailsChange.emit([false, [null, null, null, null, null, null]]); this.showDetailsChange.emit([false, [null, null, null, null, null, null]]);
} }
}); });
this.analysis.subscribe((item, selected) => { this.analysis.subscribe((item, selected) => {
...@@ -206,6 +205,42 @@ export class AnalysisWindowComponent implements OnInit, OnChanges { ...@@ -206,6 +205,42 @@ export class AnalysisWindowComponent implements OnInit, OnChanges {
} }
public toggleNormalization(normalize: boolean) {
this.tableNormalize = normalize;
const normalizeFn = (table) => {
let max = 0;
table.forEach(i => {
if (i.rawScore > max) {
max = i.rawScore;
}
});
table.forEach(i => {
i.score = i.rawScore / max;
});
};
const unnormalizeFn = (table) => {
table.forEach(i => {
i.score = i.rawScore;
});
};
if (normalize) {
normalizeFn(this.tableDrugs);
normalizeFn(this.tableProteins);
normalizeFn(this.tableViralProteins);
} else {
unnormalizeFn(this.tableDrugs);
unnormalizeFn(this.tableProteins);
unnormalizeFn(this.tableViralProteins);
}
}
public downloadLink(view: string): string {
return `${environment.backend}task_result/?token=${this.token}&view=${view}&fmt=csv`;
}
public inferNodeType(nodeId: string): 'host' | 'virus' | 'drug' { public inferNodeType(nodeId: string): 'host' | 'virus' | 'drug' {
if (nodeId.indexOf('-') !== -1 || nodeId.indexOf('_') !== -1) { if (nodeId.indexOf('-') !== -1 || nodeId.indexOf('_') !== -1) {
return 'virus'; return 'virus';
......
...@@ -2,7 +2,7 @@ import {Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges ...@@ -2,7 +2,7 @@ import {Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges
import {AnalysisService} from '../../analysis.service'; import {AnalysisService} from '../../analysis.service';
interface Algorithm { interface Algorithm {
slug: string; slug: 'trustrank' | 'keypathwayminer' | 'multisteiner';
name: string; name: string;
} }
...@@ -51,10 +51,12 @@ export class LaunchAnalysisComponent implements OnInit, OnChanges { ...@@ -51,10 +51,12 @@ export class LaunchAnalysisComponent implements OnInit, OnChanges {
ngOnChanges(changes: SimpleChanges): void { ngOnChanges(changes: SimpleChanges): void {
if (this.target === 'drug-target') { if (this.target === 'drug-target') {
this.algorithms = [TRUSTRANK, MULTISTEINER, KEYPATHWAYMINER]; this.algorithms = [MULTISTEINER, TRUSTRANK, KEYPATHWAYMINER];
this.algorithm = MULTISTEINER.slug;
this.trustrankStrain = 'SARS_CoV2'; this.trustrankStrain = 'SARS_CoV2';
} else if (this.target === 'drug') { } else if (this.target === 'drug') {
this.algorithms = [TRUSTRANK]; this.algorithms = [TRUSTRANK];
this.algorithm = TRUSTRANK.slug;
this.trustrankStrain = 'drugs'; this.trustrankStrain = 'drugs';
} }
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment