Skip to content

Commit d25622f

Browse files
committed
Add a complex viewer section on the gene pages
Refs #2559
1 parent 5567df3 commit d25622f

8 files changed

Lines changed: 157 additions & 0 deletions

‎src/app/app.module.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ import { ReferenceShortListComponent } from './reference-short-list/reference-sh
7272
import { TranscriptSequenceSelectComponent } from './transcript-sequence-select/transcript-sequence-select.component';
7373
import { ProteinPropertiesComponent } from './protein-properties/protein-properties.component';
7474
import { ProteinFeaturesComponent } from './protein-features/protein-features.component';
75+
import { ComplexViewerComponent } from './complex-viewer/complex-viewer.component';
7576
import { GeneSubsetViewComponent } from './gene-subset-view/gene-subset-view.component';
7677
import { TranscriptViewComponent } from './transcript-view/transcript-view.component';
7778
import { InterproMatchesComponent } from './interpro-matches/interpro-matches.component';
@@ -248,6 +249,7 @@ export class PomBaseUrlSerializer extends DefaultUrlSerializer {
248249
TranscriptSequenceSelectComponent,
249250
ProteinPropertiesComponent,
250251
ProteinFeaturesComponent,
252+
ComplexViewerComponent,
251253
GeneSubsetViewComponent,
252254
TranscriptViewComponent,
253255
InterproMatchesComponent,
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
.complex-info {
2+
font-size: 110%;
3+
}
4+
5+
.complex-select, .complex-info div {
6+
padding-bottom: 0.5em;
7+
}
8+
9+
.complex-view-frame {
10+
width: 800px;
11+
height: 450px;
12+
}
13+
14+
.complex-view-frame iframe {
15+
width: 780px;
16+
height: 420px;
17+
}
18+
19+
.complex-container {
20+
margin-bottom: 1.5em;
21+
}
22+
23+
.complex-name {
24+
font-weight: bold;
25+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<fieldset *ngIf="complexes.length > 0" class="annotation-table">
2+
<legend>
3+
Protein complexes
4+
</legend>
5+
6+
<div class="complex-select" *ngIf="complexes.length > 1">
7+
Select a complex containing {{geneDetails.name || geneDetails.uniquename}}:
8+
<select title="Select a complex" [(ngModel)]="currentComplex"
9+
(change)="complexChanged()">
10+
<option *ngFor = "let complex of complexes" [ngValue]="complex">
11+
{{complex.complex_uniquename}} <span *ngIf="complex.complex_name">{{complex.complex_name}}</span>
12+
</option>
13+
</select>
14+
</div>
15+
16+
<div class="complex-container">
17+
<div class="complex-info">
18+
<div *ngIf="complexes.length == 1">{{geneDetails.name || geneDetails.uniquename}} is a part of protein
19+
complex {{currentComplex.complex_uniquename}}
20+
<span class="complex-name" *ngIf="currentComplex.complex_name">"{{currentComplex.complex_name}}"</span></div>
21+
<div>View details at <a href="{{complexPortalUrl(currentComplex.complex_uniquename)}}">Complex Portal</a></div>
22+
</div>
23+
24+
<div class="complex-view-frame">
25+
<iframe [src]="getIFrameURL(currentComplex.complex_uniquename)" frameborder="0" scrolling="no"
26+
id="complex-viewer" class="embedded-complex-viewer" #complexvieweriframe>
27+
</iframe>
28+
</div>
29+
</div>
30+
</fieldset>
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { ComponentFixture, TestBed } from '@angular/core/testing';
2+
3+
import { ComplexViewerComponent } from './complex-viewer.component';
4+
5+
describe('ComplexViewerComponent', () => {
6+
let component: ComplexViewerComponent;
7+
let fixture: ComponentFixture<ComplexViewerComponent>;
8+
9+
beforeEach(async () => {
10+
await TestBed.configureTestingModule({
11+
imports: [ComplexViewerComponent]
12+
})
13+
.compileComponents();
14+
15+
fixture = TestBed.createComponent(ComplexViewerComponent);
16+
component = fixture.componentInstance;
17+
fixture.detectChanges();
18+
});
19+
20+
it('should create', () => {
21+
expect(component).toBeTruthy();
22+
});
23+
});
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { Component, OnInit, OnChanges, Input,
2+
ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
3+
import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';
4+
import { GeneDetails, ProteinComplexDetails } from '../pombase-api.service';
5+
import { getXrfWithPrefix } from '../config';
6+
7+
@Component({
8+
selector: 'app-complex-viewer',
9+
templateUrl: './complex-viewer.component.html',
10+
styleUrl: './complex-viewer.component.css',
11+
changeDetection: ChangeDetectionStrategy.OnPush,
12+
standalone: false
13+
})
14+
export class ComplexViewerComponent implements OnInit, OnChanges {
15+
@Input() geneDetails: GeneDetails;
16+
17+
complexes: Array<ProteinComplexDetails> = [];
18+
currentComplexUniquename?: string = undefined;
19+
currentComplex?: ProteinComplexDetails = undefined;
20+
21+
constructor(private changeDetectorRef: ChangeDetectorRef,
22+
private sanitizer: DomSanitizer) { }
23+
24+
complexPortalUrl(complexId: string): string {
25+
const xrfDetails = getXrfWithPrefix('ComplexPortal', complexId)!;
26+
return xrfDetails.url;
27+
}
28+
29+
getIFrameURL(complexId: string): SafeResourceUrl {
30+
const rawUrl = '/complex_viewer/' + complexId;
31+
return this.sanitizer.bypassSecurityTrustResourceUrl(rawUrl);
32+
}
33+
34+
complexChanged() {
35+
this.changeDetectorRef.detectChanges();
36+
}
37+
38+
ngOnInit() {
39+
}
40+
41+
ngOnChanges() {
42+
if (this.geneDetails) {
43+
this.complexes = this.geneDetails.complexes;
44+
this.currentComplex = this.complexes[0];
45+
} else {
46+
this.complexes = [];
47+
this.currentComplex = undefined;
48+
}
49+
}
50+
}

‎src/app/gene-details/gene-details.component.html‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,11 @@
215215
(intersection)="intersect('transcript_view', $event.intersect)"
216216
[geneDetails]="geneDetails"></app-transcript-view>
217217

218+
<app-complex-viewer id="complex_viewer"
219+
*ngIf="geneDetails!.complexes.length > 0" intersectionObserver
220+
(intersection)="intersect('complex_viewer', $event.intersect)"
221+
[geneDetails]="geneDetails"></app-complex-viewer>
222+
218223
<app-transcript-sequence-select *ngIf="isConfiguredOrganism" id="transcript-sequence"
219224
intersectionObserver
220225
(intersection)="intersect('transcript-sequence', $event.intersect)"

‎src/app/gene-details/gene-details.component.ts‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,13 @@ export class GeneDetailsComponent implements OnInit {
344344
});
345345
}
346346

347+
if (this.geneDetails && this.geneDetails.complexes.length > 0) {
348+
this.menuItems.push({
349+
id: 'complex_viewer',
350+
displayName: 'Protein complexes',
351+
});
352+
}
353+
347354
seqSubItems.push({
348355
id: 'transcript-sequence',
349356
displayName: 'Sequence',

‎src/app/pombase-api.service.ts‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ export type ChromosomeShortMap = {[uniquename: string]: ChromosomeShort};
1515
export type FeatureTypeSummaryMap = { [featureTypeName: string]: FeatureTypeSummary };
1616
export type GoCamMap = { [gocamid: GoCamModelId]: GoCamSummary };
1717

18+
export type ComplexPortalId = string;
19+
1820
type ReferenceDetailsMap = { [referenceUniquename: string]: ReferenceDetails };
1921

2022
type TermIdTermMap = { [termid: string]: TermShort };
@@ -639,6 +641,12 @@ export interface AssignedByPeptideRange {
639641
assigned_by: string;
640642
}
641643

644+
export interface ProteinComplexDetails {
645+
complex_uniquename: ProteinComplexId;
646+
complex_name?: string;
647+
genes: Array<GeneUniquename>;
648+
}
649+
642650
export class GeneDetails {
643651
uniquename: string;
644652
name: string;
@@ -667,6 +675,7 @@ export class GeneDetails {
667675
tfexplorer_chipseq_identifier: string;
668676
tfexplorer_ipms_identifier: string;
669677
pdb_entries: Array<PDBEntry>;
678+
complexes: Array<ProteinComplexDetails>;
670679
gocams: Array<GoCamIdAndTitle>;
671680
characterisation_status?: string;
672681
location: ChromosomeLocation;
@@ -827,6 +836,8 @@ export type GoCamModelId = string;
827836
export type GoCamModelTitle = string;
828837
export type GoCamDirection = 'Incoming' |'IncomingConstitutivelyUpstream'|'Outgoing'|'None';
829838

839+
export type ProteinComplexId = string;
840+
830841
export interface GoCamIdAndTitle {
831842
gocam_id: string;
832843
title?: string;
@@ -1365,6 +1376,10 @@ export class PombaseAPIService {
13651376
json.transcripts = [];
13661377
}
13671378

1379+
if (!json.complexes) {
1380+
json.complexes = [];
1381+
}
1382+
13681383
for (let fieldName of ['cv_annotations',
13691384
'genes_by_uniquename', 'genotypes_by_uniquename',
13701385
'alleles_by_uniquename', 'references_by_uniquename',

0 commit comments

Comments
 (0)