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

Final fixes and features

parent 5bfa186c
No related branches found
No related tags found
No related merge requests found
import {Wrapper, Task, getWrapperFromProtein, getWrapperFromViralProtein} from './interfaces';
import {Wrapper, Task, getWrapperFromProtein, getWrapperFromViralProtein, Protein, ViralProtein} from './interfaces';
import {Subject} from 'rxjs';
import {HttpClient} from '@angular/common/http';
import {environment} from '../environments/environment';
......@@ -121,6 +121,14 @@ export class AnalysisService {
return this.selectedItems.has(wrapper.nodeId);
}
proteinInSelection(protein: Protein): boolean {
return this.inSelection(getWrapperFromProtein(protein));
}
viralProteinInSelection(viralProtein: ViralProtein): boolean {
return this.inSelection(getWrapperFromViralProtein(viralProtein));
}
removeItem(wrapper: Wrapper) {
const item = this.selectedItems.get(wrapper.nodeId);
if (this.selectedItems.delete(wrapper.nodeId)) {
......
......@@ -48,8 +48,7 @@ import {AnalysisService} from './analysis.service';
TableModule,
],
providers: [AnalysisService],
bootstrap: [AppComponent]
bootstrap: [AppComponent],
})
export class AppModule {
}
......@@ -71,48 +71,40 @@
</div>
</div>
<footer class="card-footer toolbar">
<div class="field has-addons">
<p class="control">
<button class="button is-rounded is-success is-rounded" [disabled]="true">
<span class="icon">
<i class="fas fa-cloud-download-alt" aria-hidden="true"></i>
</span>
<span>
Export Results
</span>
</button>
</p>
<p class="control">
<button class="button is-primary is-rounded" [disabled]="true">
<span class="icon">
<i class="fas fa-camera" aria-hidden="true"></i>
</span>
<div class="field">
<p class="control footer-buttons">
<button class="button is-primary is-rounded" (click)="toCanvas()">
<span class="icon">
<i class="fas fa-camera" aria-hidden="true"></i>
</span>
<span>
Screenshot
</span>
Screenshot
</span>
</button>
</p>
<p class="control">
</div>
<div class="field">
<p class="control footer-buttons">
<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>
<span class="icon">
<i class="fas fa-trash" aria-hidden="true"></i>
</span>
<span>
Delete Analysis
</span>
Delete Analysis
</span>
</button>
</p>
</div>
<app-toggle *ngIf="task.info.target === 'drug-target'" class="footer-toggle-buttons" textOn="Drugs On" textOff="Off"
<app-toggle *ngIf="task.info.target === 'drug-target'" class="footer-buttons" textOn="Drugs On" textOff="Off"
[value]="showDrugs" (valueChange)="toggleDrugs($event)" icon="fa-capsules"></app-toggle>
<app-toggle class="footer-toggle-buttons" textOn="Animation On" textOff="Off"
<app-toggle class="footer-buttons" textOn="Animation On" textOff="Off"
[value]="physicsEnabled" (valueChange)="updatePhysicsEnabled($event)" icon="fa-wind"></app-toggle>
</footer>
</div>
<div class="content tab-content scrollable" *ngIf="task && task.info.done" [class.is-visible]="tab === 'table'">
<div class="field has-addons footer-toggle-buttons" *ngIf="tableHasScores">
<div class="field has-addons" *ngIf="tableHasScores">
<p class="control">
<button class="button is-rounded" [class.is-primary]="tableNormalize" (click)="toggleNormalization(true)">
<span class="icon is-small">
......@@ -164,7 +156,7 @@
<td><a href="https://www.drugbank.ca/drugs/{{ e.drugId }}" target="_blank">{{ e.drugId }}</a></td>
<td>{{e.name}}</td>
<td>{{e.status}}</td>
<td *ngIf="tableHasScores">{{e.score || ''}}</td>
<td *ngIf="tableHasScores">{{e.score ? (e.score | number) : ''}}</td>
</tr>
</ng-template>
</p-table>
......@@ -179,11 +171,16 @@
<span>Download</span>
</a>
</div>
<p-table *ngIf="tableProteins.length > 0" [value]="tableProteins">
<p-table *ngIf="tableProteins.length > 0" selectionMode="multiple"
[value]="tableProteins" [selection]="tableSelectedProteins" dataKey="proteinAc"
(selectionChange)="tableProteinSelection($event)">
<ng-template pTemplate="header">
<tr>
<th class="checkbox-col">
<p-tableHeaderCheckbox></p-tableHeaderCheckbox>
</th>
<th [pSortableColumn]="'proteinAc'">
AC
UniProt Code
<p-sortIcon [field]="'proteinAc'"></p-sortIcon>
</th>
<th [pSortableColumn]="'name'">
......@@ -198,9 +195,12 @@
</ng-template>
<ng-template pTemplate="body" let-e>
<tr>
<td>
<p-tableCheckbox [value]="e"></p-tableCheckbox>
</td>
<td><a href="https://www.uniprot.org/uniprot/{{ e.proteinAc }}" target="_blank">{{ e.proteinAc }}</a></td>
<td>{{e.name}}</td>
<td *ngIf="tableHasScores">{{e.score || ''}}</td>
<td *ngIf="tableHasScores">{{e.score ? (e.score | number) : ''}}</td>
</tr>
</ng-template>
</p-table>
......@@ -215,28 +215,36 @@
<span>Download</span>
</a>
</div>
<p-table *ngIf="tableViralProteins.length > 0" [value]="tableViralProteins">
<p-table *ngIf="tableViralProteins.length > 0" selectionMode="multiple"
[value]="tableViralProteins" [selection]="tableSelectedViralProteins" dataKey="effectId"
(selectionChange)="tableViralProteinSelection($event)">
<ng-template pTemplate="header">
<tr>
<td [pSortableColumn]="'effectName'">
<th class="checkbox-col">
<p-tableHeaderCheckbox></p-tableHeaderCheckbox>
</th>
<th [pSortableColumn]="'effectName'">
Name
<p-sortIcon [field]="'effectName'"></p-sortIcon>
</td>
<td [pSortableColumn]="'virusName'">
</th>
<th [pSortableColumn]="'virusName'">
Virus Strain
<p-sortIcon [field]="'virusName'"></p-sortIcon>
</td>
<td *ngIf="tableHasScores" [pSortableColumn]="'score'">
</th>
<th *ngIf="tableHasScores" [pSortableColumn]="'score'">
Score
<p-sortIcon [field]="'score'"></p-sortIcon>
</td>
</th>
</tr>
</ng-template>
<ng-template pTemplate="body" let-e>
<tr>
<td>
<p-tableCheckbox [value]="e"></p-tableCheckbox>
</td>
<td>{{e.effectName}}</td>
<td>{{e.virusName}}</td>
<td *ngIf="tableHasScores">{{e.score || ''}}</td>
<td *ngIf="tableHasScores">{{e.score ? (e.score | number) : ''}}</td>
</tr>
</ng-template>
</p-table>
......
......@@ -31,3 +31,7 @@ div.network {
.table-header {
margin-bottom: 50px;
}
.checkbox-col {
width: 50px;
}
......@@ -13,8 +13,19 @@ import {HttpClient, HttpErrorResponse} from '@angular/common/http';
import {environment} from '../../../environments/environment';
import {AnalysisService, algorithmNames} from '../../analysis.service';
import {
Protein, Task, ViralProtein, Drug, Wrapper, WrapperType,
getWrapperFromProtein, getWrapperFromDrug, getWrapperFromViralProtein, getNodeIdsFromPDI, getNodeIdsFromPPI
Protein,
Task,
ViralProtein,
Drug,
Wrapper,
WrapperType,
getWrapperFromProtein,
getWrapperFromDrug,
getWrapperFromViralProtein,
getNodeIdsFromPDI,
getNodeIdsFromPPI,
getViralProteinNodeId,
getProteinNodeId
} from '../../interfaces';
import html2canvas from 'html2canvas';
import {toast} from 'bulma-toast';
......@@ -59,7 +70,9 @@ export class AnalysisWindowComponent implements OnInit, OnChanges {
public tableDrugs: Array<Drug & Scored> = [];
public tableProteins: Array<Protein & Scored> = [];
public tableSelectedProteins: Array<Protein & Scored> = [];
public tableViralProteins: Array<ViralProtein & Scored> = [];
public tableSelectedViralProteins: Array<ViralProtein & Scored> = [];
public tableNormalize = false;
public tableHasScores = false;
......@@ -98,12 +111,17 @@ export class AnalysisWindowComponent implements OnInit, OnChanges {
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);
this.tableSelectedProteins = [];
this.tableProteins.forEach((r) => {
r.rawScore = r.score;
if (this.analysis.proteinInSelection(r)) {
this.tableSelectedProteins.push(r);
}
});
}));
promises.push(this.http.get<any>(`${environment.backend}task_result/?token=${this.token}&view=viral_proteins`).toPromise()
.then((table) => {
......@@ -156,8 +174,31 @@ export class AnalysisWindowComponent implements OnInit, OnChanges {
}
});
this.analysis.subscribe((item, selected) => {
if (item.type === 'host') {
// TODO: Refactor!
const found = this.tableSelectedProteins.findIndex((i) => getProteinNodeId(i) === item.nodeId);
const tableItem = this.tableProteins.find((i) => getProteinNodeId(i) === item.nodeId);
if (selected && found === -1 && tableItem) {
this.tableSelectedProteins.push(tableItem);
}
if (!selected && found !== -1 && tableItem) {
this.tableSelectedProteins.splice(found, 1);
}
this.tableSelectedProteins = [...this.tableSelectedProteins];
} else if (item.type === 'virus') {
// TODO: Refactor!
const found = this.tableSelectedViralProteins.findIndex((i) => getViralProteinNodeId(i) === item.nodeId);
const tableItem = this.tableViralProteins.find((i) => getViralProteinNodeId(i) === item.nodeId);
if (selected && found === -1 && tableItem) {
this.tableSelectedViralProteins.push(tableItem);
}
if (!selected && found !== -1 && tableItem) {
this.tableSelectedViralProteins.splice(found, 1);
}
this.tableSelectedViralProteins = [...this.tableSelectedViralProteins];
}
const node = this.nodeData.nodes.get(item.nodeId);
if (!node) {
return;
......@@ -192,10 +233,6 @@ export class AnalysisWindowComponent implements OnInit, OnChanges {
this.emitVisibleItems(false);
}
export() {
}
public toggleNormalization(normalize: boolean) {
this.tableNormalize = normalize;
......@@ -351,9 +388,9 @@ export class AnalysisWindowComponent implements OnInit, OnChanges {
this.drugNodes = [];
this.drugEdges = [];
if (this.showDrugs) {
const proteinAcs = this.proteins.map((protein) => protein.proteinAc);
// tslint:disable-next-line:max-line-length
const result = await this.http.get<any>(`${environment.backend}drug_interactions/?proteins=${JSON.stringify(proteinAcs)}`).toPromise().catch((err: HttpErrorResponse) => {
const result = await this.http.get<any>(
`${environment.backend}drug_interactions/?token=${this.token}`).toPromise().catch(
(err: HttpErrorResponse) => {
// simple logging, but you can do a lot more, see below
toast({
message: 'An error occured while fetching the drugs.',
......@@ -396,7 +433,6 @@ export class AnalysisWindowComponent implements OnInit, OnChanges {
}
}
public updatePhysicsEnabled(bool: boolean) {
this.physicsEnabled = bool;
this.network.setOptions({
......@@ -409,21 +445,48 @@ export class AnalysisWindowComponent implements OnInit, OnChanges {
});
}
public screenshot() {
const elem = document.getElementById(this.indexscreenshot.toString());
html2canvas(elem).then((canvas) => {
const generatedImage1 = canvas.toDataURL('image/png').replace('image/png', 'image/octet-stream');
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 = generatedImage1;
a.download = `Resulting_Network.png`;
a.href = generatedImage;
a.download = `Network.png`;
a.click();
});
}
public updateshowdrugs(bool) {
this.drugstatus = bool;
public tableProteinSelection(e) {
const oldSelection = [...this.tableSelectedProteins];
this.tableSelectedProteins = e;
for (const i of this.tableSelectedProteins) {
const wrapper = getWrapperFromProtein(i);
if (oldSelection.indexOf(i) === -1) {
this.analysis.addItem(wrapper);
}
}
for (const i of oldSelection) {
const wrapper = getWrapperFromProtein(i);
if (this.tableSelectedProteins.indexOf(i) === -1) {
this.analysis.removeItem(wrapper);
}
}
}
public tableViralProteinSelection(e) {
const oldSelection = [...this.tableSelectedViralProteins];
this.tableSelectedViralProteins = e;
for (const i of this.tableSelectedViralProteins) {
const wrapper = getWrapperFromViralProtein(i);
if (oldSelection.indexOf(i) === -1) {
this.analysis.addItem(wrapper);
}
}
for (const i of oldSelection) {
const wrapper = getWrapperFromViralProtein(i);
if (this.tableSelectedViralProteins.indexOf(i) === -1) {
this.analysis.removeItem(wrapper);
}
}
}
}
......@@ -148,7 +148,7 @@
</p>
</header>
<div class="card-content">
<div class="card-image" id="0">
<div class="card-image" id="canvas-content">
<div class="parent">
<div class="network center image1" #network>
<button class="button is-loading center" alt="Snow">Loading</button>
......@@ -164,7 +164,7 @@
<i class="fas fa-camera" aria-hidden="true"></i>
</span> <span>Screenshot</span>
</button>
<app-toggle class="footer-toggle-buttons" textOn="Animation On" textOff="Off" [value]="physicsEnabled" (valueChange)="updatePhysicsEnabled($event)" icon="fa-wind"></app-toggle>
<app-toggle class="footer-buttons" textOn="Animation On" textOff="Off" [value]="physicsEnabled" (valueChange)="updatePhysicsEnabled($event)" icon="fa-wind"></app-toggle>
</footer>
</div>
</div>
......
......@@ -63,7 +63,6 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit {
public selectedAnalysisToken: string | null = null;
public currentDataset = [];
private screenshotArray = [0];
public currentViewProteins: Protein[];
public currentViewEffects: ViralProtein[];
......@@ -417,15 +416,12 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit {
}
public toCanvas() {
this.screenshotArray.forEach((key, index) => {
const elem = document.getElementById(index.toString());
html2canvas(elem).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();
});
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();
});
}
......
......@@ -12,7 +12,7 @@ $danger: #EF476F;
$link: $primary;
$info: $primary;
@import "~bulma/bulma.sass";
@import "~primeng/resources/primeng.css";
@import "~primeng/resources/primeng.min.css";
@import "~primeicons/primeicons.css";
html {
......@@ -174,7 +174,7 @@ div.field.has-addons.add-remove-toggle {
color: $danger;
}
.footer-toggle-buttons {
.footer-buttons {
margin-left: 20px;
margin-right: 10px;
}
......@@ -192,3 +192,8 @@ body {
margin: 0;
font-family: Roboto, "Helvetica Neue", sans-serif;
}
.ui-chkbox-box {
border: 1px solid black !important;
}
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