Skip to content
Snippets Groups Projects
Commit 02074689 authored by Julian Matschinske's avatar Julian Matschinske Committed by Mhaned Oubounyt
Browse files

Protein selection

parent 8bed0cdc
No related branches found
No related tags found
No related merge requests found
import {Injectable} from '@angular/core';
import {ProteinGroup} from './pages/protein-network';
import {Subject} from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class AnalysisService {
private selectedProteins = new Map<string, ProteinGroup>();
private selectSubject = new Subject<{protein: ProteinGroup, selected: boolean}>();
constructor() {
}
addProtein(protein: ProteinGroup) {
if (!this.inSelection(protein)) {
this.selectedProteins.set(`${protein.groupId}`, protein);
this.selectSubject.next({protein, selected: true});
}
}
inSelection(protein: ProteinGroup): boolean {
return this.selectedProteins.has(`${protein.groupId}`);
}
removeProtein(protein: ProteinGroup) {
if (this.selectedProteins.delete(`${protein.groupId}`)) {
this.selectSubject.next({protein, selected: false});
}
}
getSelection(): ProteinGroup[] {
return Array.from(this.selectedProteins.values());
}
getCount(): number {
return this.selectedProteins.size;
}
subscribe(cb: (protein: ProteinGroup, selected: boolean) => void) {
this.selectSubject.subscribe((event) => {
cb(event.protein, event.selected);
});
}
}
......@@ -10,6 +10,7 @@ import {ExplorerPageComponent} from './pages/explorer-page/explorer-page.compone
import {AboutPageComponent} from './pages/about-page/about-page.component';
import {HomePageComponent} from './pages/home-page/home-page.component';
import {HttpClientModule} from '@angular/common/http';
import {ProteinAnalysisComponent} from './components/protein-analysis/protein-analysis.component';
@NgModule({
declarations: [
......@@ -17,6 +18,7 @@ import {HttpClientModule} from '@angular/common/http';
ExplorerPageComponent,
AboutPageComponent,
HomePageComponent,
ProteinAnalysisComponent,
],
imports: [
BrowserModule,
......
<div class="modal" [class.is-active]="show">
<div class="modal-background"></div>
<div class="modal-card">
<header class="modal-card-head">
<p class="modal-card-title">Launch Protein Analysis</p>
<button class="delete" aria-label="close" (click)="close()"></button>
</header>
<section class="modal-card-body">
<h4 class="title is-4">Selection</h4>
<table class="table">
<thead>
<tr>
<td>AC</td>
<td>Actions</td>
</tr>
</thead>
<tbody>
<tr *ngFor="let p of analysis.getSelection()">
<td>{{p.name}}</td>
<td>
<button (click)="analysis.removeProtein(p)" class="button is-small is-danger">
<i class="fa fa-trash"></i>
</button>
</td>
</tr>
</tbody>
</table>
</section>
<footer class="modal-card-foot">
<button class="button is-success">
<span class="icon"><i class="fa fa-play"></i></span>
<span>Multi Steiner</span>
</button>
<button class="button is-success">
<span class="icon"><i class="fa fa-play"></i></span>
<span>Key Pathway Miner</span>
</button>
</footer>
</div>
</div>
import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
import {AnalysisService} from '../../analysis.service';
@Component({
selector: 'app-protein-analysis',
templateUrl: './protein-analysis.component.html',
styleUrls: ['./protein-analysis.component.scss']
})
export class ProteinAnalysisComponent implements OnInit {
@Input()
public show = false;
@Output()
public showChange = new EventEmitter<boolean>();
constructor(public analysis: AnalysisService) {
}
ngOnInit(): void {
}
public close() {
this.show = false;
this.showChange.emit(this.show);
}
}
<app-protein-analysis [(show)]="showAnalysisDialog"></app-protein-analysis>
<div class="content explorer">
<div class="content bar-left">
......@@ -103,6 +105,26 @@
<div class="content bar-right">
<div class="card bar">
<header class="card-header">
<p class="card-header-title">
<span class="icon">
<i class="fas fa-flask" aria-hidden="true"></i>
</span> Analysis
</p>
</header>
<div class="card-content">
<button (click)="showAnalysisDialog = true" class="button is-success" [disabled]="analysis.getCount() === 0">
<span class="icon">
<i class="fa fa-list"></i>
</span>
<span>
Open Protein Selection
</span>
</button>
</div>
</div>
<div class="card bar">
<header class="card-header">
<p class="card-header-title">
......@@ -145,6 +167,8 @@
<figure class="image">
<img src="assets/boxplot.png" alt="Boxplots">
</figure>
<button class="button" *ngIf="!inSelection(proteinGroup)" (click)="addToSelection(proteinGroup)">Select for analysis</button>
<button class="button" *ngIf="inSelection(proteinGroup)" (click)="removeFromSelection(proteinGroup)">Remove from analysis</button>
</div>
</div>
</div>
......
import {AfterViewInit, Component, ElementRef, OnInit, ViewChild} from '@angular/core';
import {ActivatedRoute, Router} from '@angular/router';
import {Effect, ProteinNetwork} from '../protein-network';
import {Effect, ProteinGroup, ProteinNetwork} from '../protein-network';
import {HttpClient} from '@angular/common/http';
import {ApiService} from '../../api.service';
import {AnalysisService} from '../../analysis.service';
declare var vis: any;
......@@ -19,7 +20,6 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit {
public proteinGroup = '';
public proteinNames: Array<string> = [];
public proteinACs: Array<string> = [];
public baitNames: Array<string> = [];
public baitProteins: Array<{ checked: boolean; data: Effect }> = [];
......@@ -39,18 +39,18 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit {
private dumpPositions = false;
public physicsEnabled = false;
public showAnalysisDialog = false;
@ViewChild('network', {static: false}) networkEl: ElementRef;
constructor(private http: HttpClient, private route: ActivatedRoute, private router: Router, private api: ApiService) {
this.groupId = 'IFI16';
constructor(private http: HttpClient,
private route: ActivatedRoute,
private router: Router,
private api: ApiService,
public analysis: AnalysisService) {
this.geneNames.push('IFI16');
this.proteinNames.push('Gamma-interface-inducible protein 16');
this.proteinACs.push('Q16666');
this.baitNames.push('Bait Protein 1');
this.baitNames.push('Bait Protein 2');
this.baitNames.push('Bait Protein 3');
this.baitNames.push('Bait Protein 4');
this.baitNames.push('Bait Protein 5');
this.route.queryParams.subscribe(async (params) => {
this.dumpPositions = params.dumpPositions;
......@@ -79,6 +79,23 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit {
// this.zoomToNode(proteinGroup)
this.showDetails = true;
});
this.analysis.subscribe((protein, selected) => {
const nodeId = `pg_${protein.groupId}`;
if (selected) {
const node = this.nodeData.nodes.get(nodeId);
if (node) {
node.color = '#c42eff';
this.nodeData.nodes.update(node);
}
} else {
const node = this.nodeData.nodes.get(nodeId);
if (node) {
node.color = '#e2b600';
this.nodeData.nodes.update(node);
}
}
});
}
ngOnInit() {
......@@ -104,7 +121,7 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit {
this.filterNodes();
}
public zoomToNode(id: string) {
private zoomToNode(id: string) {
const coords = this.network.getPositions(id)[id];
this.network.moveTo({
position: {x: coords.x, y: coords.y},
......@@ -117,9 +134,11 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit {
return this.groupId;
}
public async openSummary(groupId: string) {
public async openSummary(groupId: string, zoom: boolean) {
await this.router.navigate(['explorer'], {queryParams: {proteinGroup: groupId}});
this.zoomToNode(this.proteinGroup);
if (zoom) {
this.zoomToNode(this.proteinGroup);
}
}
public async closeSummary() {
......@@ -170,7 +189,7 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit {
console.log(id);
if (id.length > 0) {
console.log('clicked node:', id);
this.openSummary(id[0]);
this.openSummary(id[0], false);
}
});
......@@ -239,17 +258,21 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit {
});
}
private mapProteinGroupToNode(proteinGroup: any): any {
private mapProteinGroupToNode(proteinGroup: ProteinGroup): any {
let color = '#e2b600';
if (this.analysis.inSelection(proteinGroup)) {
color = '#c42eff';
}
return {
id: `pg_${proteinGroup.groupId}`,
label: `${proteinGroup.name}`,
size: 10, font: '5px', color: '#e2b600', shape: 'ellipse', shadow: false,
size: 10, font: '5px', color, shape: 'ellipse', shadow: false,
x: proteinGroup.x,
y: proteinGroup.y
};
}
private mapEffectToNode(effect: any): any {
private mapEffectToNode(effect: Effect): any {
return {
id: `eff_${effect.name}`,
label: `${effect.name}`,
......@@ -260,7 +283,7 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit {
}
private mapEdge(edge: any): any {
return {from: `pg_${edge.groupId}`, to: `eff_${edge.effectName}`, color: { color: '#afafaf', highlight: '#854141' }};
return {from: `pg_${edge.groupId}`, to: `eff_${edge.effectName}`, color: {color: '#afafaf', highlight: '#854141'}};
}
private mapDataToNodes(data: ProteinNetwork): { nodes: any[], edges: any[] } {
......@@ -291,4 +314,34 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit {
return x - Math.floor(x);
}
// Selection
// TODO: Improve usage of group ids, revise this after models have been changed to just protein
inSelection(groupIdStr: string): boolean {
if (!this.proteinData || !groupIdStr) {
return false;
}
const groupId = Number(groupIdStr.split('_')[1]);
const protein = this.proteinData.getProteinGroup(groupId);
return this.analysis.inSelection(protein);
}
addToSelection(groupIdStr: string) {
if (!groupIdStr) {
return;
}
const groupId = Number(groupIdStr.split('_')[1]);
const protein = this.proteinData.getProteinGroup(groupId);
this.analysis.addProtein(protein);
}
removeFromSelection(groupIdStr: string) {
if (!groupIdStr) {
return;
}
const groupId = Number(groupIdStr.split('_')[1]);
const protein = this.proteinData.getProteinGroup(groupId);
this.analysis.removeProtein(protein);
}
}
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