Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/maxolyzer #300

Merged
merged 8 commits into from
Sep 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/app/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Modules
import {NgModule} from '@angular/core';
import { MAT_TABS_CONFIG } from '@angular/material/tabs';
import {BrowserModule} from '@angular/platform-browser';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
import {RoutingModule} from './app-routing.module';
Expand Down Expand Up @@ -36,7 +37,7 @@ import {SafeHtmlPipe} from './shared/pipes/sanitize.pipe';
RoutingModule,
SearchModule
],
providers: [SearchService, NewsService],
providers: [SearchService, NewsService, { provide: MAT_TABS_CONFIG, useValue: { animationDuration: '0ms' } }],
bootstrap: [AppComponent]
})
export class AppModule {
Expand Down
3 changes: 1 addition & 2 deletions src/app/browser/browser.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {GlobalMaterialModules} from '../shared/modules/global.module';
// Services
import {SearchService} from '../shared/search/service/search.service';
import { AnnotationService } from './services/annotation/annotation.service';
import {TermService} from './services/term/term.service';
import {GeneService} from './services/gene/gene.service';
import {OntologyService} from './services/ontology/ontology.service';
// Components
Expand All @@ -32,7 +31,7 @@ import {ProfileSearchComponent} from './pages/profile-search/profile-search.comp
GlobalMaterialModules,
ExtrasModule
],
providers: [SearchService, TermService, GeneService, DialogService,
providers: [SearchService, GeneService, DialogService,
OntologyService, AnnotationService],
declarations: [TermComponent, DiseaseComponent,
GeneComponent,
Expand Down
12 changes: 12 additions & 0 deletions src/app/browser/models/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ export interface PhenotypeAssociation {
diseases: any[];
genes: any[];
assays: any[];
medicalActions: any[];
}

export interface GeneAssociation {
Expand All @@ -148,10 +149,21 @@ export interface DiseaseAssociation {
disease: Disease;
categories: {};
genes: any[];
medicalActions: MedicalActionSourceExtended[];
}

export enum EntityType {
PHENOTYPE,
DISEASE,
GENE
}

export interface MedicalActionSourceExtended extends SimpleTerm{
relations: string[];
sources: string[];
}

export interface MedicalActionTargetExtended extends SimpleTerm {
targets: string[];
sources: string[];
}
5 changes: 0 additions & 5 deletions src/app/browser/pages/disease/disease.component.css
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,3 @@
.mat-row {
border-bottom-color: rgba(0, 0, 0, 0.25) !important;
}


.source .material-icons,.material-icons-outlined {
font-size: 12px;
}
85 changes: 74 additions & 11 deletions src/app/browser/pages/disease/disease.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@
<mat-card class="item-summary mat-elevation-z6">
<mat-card-content>
<span class="item-title">{{disease.name}}&nbsp;</span>
<a *ngIf="disease.mondoId" class="item-id" [href]="getExternalTermIdUrlFromId(disease.mondoId)" target="_blank">
<a *ngIf="disease.mondoId" class="item-id" [href]="utilityService.getExternalTermIdUrlFromId(disease.mondoId)" target="_blank">
{{disease.mondoId}}
<mat-icon>open_in_new</mat-icon>
</a>
<a class="item-id" [href]="getExternalTermIdUrlFromId(disease.id)" target="_blank">
<a class="item-id" [href]="utilityService.getExternalTermIdUrlFromId(disease.id)" target="_blank">
{{disease.id}}
<mat-icon>open_in_new</mat-icon>
</a>
Expand Down Expand Up @@ -74,19 +74,19 @@ <h3 class="category-title">{{catTermSource.catLabel}}
<mat-header-cell *matHeaderCellDef>Source(s)</mat-header-cell>
<mat-cell [ngClass]="{'source-cell': row.metadata.sources.length > 1}" *matCellDef="let row">
<ng-container *ngFor="let source of row.metadata.sources">
<div class="source" *ngIf="isTermIdExpected(source,'PMID')">
<a [href]="getExternalTermIdUrlFromId(source)" target="_blank">
<div class="source" *ngIf="utilityService.isTermIdExpected(source,'PMID')">
<a [href]="utilityService.getExternalTermIdUrlFromId(source)" target="_blank">
PubMed <i class="material-icons-outlined">library_books</i>
</a>
</div>
<div class="source" *ngIf="isTermIdExpected(source, 'BOOKSHELF')">
<div class="source" *ngIf="utilityService.isTermIdExpected(source, 'BOOKSHELF')">
<a [href]="source" target="_blank">
Gene Review <i class="material-icons-outlined">library_books</i>
</a>
</div>
<div class="source" *ngIf="!isTermIdExpected(source, 'PMID') && !isTermIdExpected(source, 'BOOKSHELF')">
<a [href]="getExternalTermIdUrlFromId(source)" target="_blank">
<span>{{getDiseaseDatabaseName(source)}} &nbsp;</span>
<div class="source" *ngIf="!utilityService.isTermIdExpected(source, 'PMID') && !utilityService.isTermIdExpected(source, 'BOOKSHELF')">
<a [href]="utilityService.getExternalTermIdUrlFromId(source)" target="_blank">
<span>{{utilityService.getDiseaseDatabaseName(source)}} &nbsp;</span>
<i class="material-icons">open_in_new</i>
</a>
</div>
Expand Down Expand Up @@ -130,15 +130,78 @@ <h3 class="category-title">{{catTermSource.catLabel}}
<mat-cell *matCellDef="let row">{{row.name}}</mat-cell>
</ng-container>
</mat-table>

<mat-paginator #genePaginator [pageSizeOptions]="[50, 100, 500]"></mat-paginator>
<div class="associationsPaging">
<p>{{geneDataSource.data.length}} gene associations.
</p>
</div>
</div>
</div>
</div>

<!-- no results found -->
<div class="container center" [hidden]="geneDataSource?.data.length !== 0">
<h4>No gene results found for "{{query}}"</h4>
<h4>No gene results found for {{query}}</h4>
</div>

</mat-tab>
<!-- Medical Actions Tab -->
<mat-tab label="Medical Actions">
<!--<div class="tab-content">-->
<div [hidden]="medicalActionsDataSource?.data.length === 0">
<div class="tab-output-container">
<!-- Gene Association Table -->
<div class="associations gene-association">
<mat-table [dataSource]="medicalActionsDataSource" matSort>
<mat-header-row *matHeaderRowDef="medicalActionColumns; sticky: true"></mat-header-row>
<mat-row *matRowDef="let row; columns: medicalActionColumns;"></mat-row>
<ng-container matColumnDef="id">
<mat-header-cell *matHeaderCellDef>MaXo Id</mat-header-cell>
<mat-cell *matCellDef="let row">
{{row.id}}
</mat-cell>
</ng-container>
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef>MaXo Name</mat-header-cell>
<mat-cell *matCellDef="let row">{{row.name}}</mat-cell>
</ng-container>
<ng-container matColumnDef="relations">
<mat-header-cell *matHeaderCellDef>Relation</mat-header-cell>
<mat-cell *matCellDef="let row">
<ng-container *ngIf="row.relations.length == 1">
{{row.relations[0]}}
</ng-container>
<ng-container *ngIf="row.relations.length > 1">
{{row.relations.join(" and ")}}
</ng-container>
</mat-cell>
</ng-container>
<ng-container matColumnDef="targets">
<mat-header-cell *matHeaderCellDef>Target</mat-header-cell>
<mat-cell *matCellDef="let row">
<ng-container *ngIf="row.targets.length > 0">
<div *ngFor="let target of row.targets">
<div *ngIf="utilityService.isTermIdExpected(target.id,'HP')">
<a routerLink="/browse/term/{{target.id}}">{{target.id}}</a>
</div>
<div *ngIf="utilityService.isTermIdExpected(target.id,'OMIM')">
{{target.id}}
</div>
</div>
</ng-container>
</mat-cell>
</ng-container>
</mat-table>
<div class="associationsPaging">
<p>{{medicalActionsDataSource.data.length}} medical actions.
</p>
</div>
</div>
</div>
</div>

<!-- no results found -->
<div class="container center" [hidden]="medicalActionsDataSource?.data.length !== 0">
<h4>No medical action results found for {{query}}</h4>
</div>

</mat-tab>
Expand Down
34 changes: 7 additions & 27 deletions src/app/browser/pages/disease/disease.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import {ActivatedRoute, Router} from '@angular/router';
import {MatTableDataSource} from '@angular/material/table';
import {MatSort} from '@angular/material/sort';
import {MatPaginator} from '@angular/material/paginator';
import { Disease, SimpleTerm, Term, TermCategory } from '../../models/models';
import { UtilityService } from '../../../shared/utility/utility.service';
import { Disease, MedicalActionSourceExtended, SimpleTerm, Term, TermCategory } from '../../models/models';
import { AnnotationService } from '../../services/annotation/annotation.service';
import {DialogService} from '../../../shared/dialog-excel-download/dialog.service';

Expand All @@ -19,8 +20,10 @@ export class DiseaseComponent {
termColumns = ['id', 'name', 'metadata.onset', 'metadata.frequency', 'metadata.sources'];
hasTerms = false;
geneColumns = ['id', 'name'];
termDataSource: MatTableDataSource<Term>;
medicalActionColumns = ['id', 'name', 'relations', 'targets']
medicalActionsDataSource: MatTableDataSource<MedicalActionSourceExtended>;
geneDataSource: MatTableDataSource<SimpleTerm>;

isLoading = true;
catTermSources: TermCategory[] = [];
@ViewChild(MatSort) sort: MatSort;
Expand All @@ -29,6 +32,7 @@ export class DiseaseComponent {

constructor(private route: ActivatedRoute,
public dialogService: DialogService, public annotationService: AnnotationService,
public utilityService: UtilityService,
private router: Router) {
this.route.params.subscribe((params) => {
this.query = params.id;
Expand All @@ -44,6 +48,7 @@ export class DiseaseComponent {
this.setCatTermsDBSource(data.categories);
this.geneDataSource = new MatTableDataSource(data.genes);
this.geneDataSource.paginator = this.genePaginator;
this.medicalActionsDataSource = new MatTableDataSource(data.medicalActions);
this.isLoading = false;
}, (error) => {
const errorString = 'Could not find requested disease id.';
Expand Down Expand Up @@ -88,31 +93,6 @@ export class DiseaseComponent {
});
}

getExternalTermIdUrlFromId(termId?: string) {
if(!termId){
return '';
}
const sourceParts = termId.split(':');
if (this.isTermIdExpected(termId, "OMIM")) {
return `https://omim.org/entry/${sourceParts[1]}`;
} else if (this.isTermIdExpected(termId, "ORPHA")) {
return `https://www.orpha.net/consor/cgi-bin/OC_Exp.php?Lng=EN&Expert=${sourceParts[1]}`
} else if (this.isTermIdExpected(termId, "MONDO")){
return `https://monarchinitiative.org/disease/${termId}`;
} else if(this.isTermIdExpected(termId, "PMID")){
return `https://www.ncbi.nlm.nih.gov/pubmed/${sourceParts[1]}`;
}
}

isTermIdExpected(diseaseId: string, expected: string) {
return diseaseId != "" && diseaseId != null && expected != "" && expected != null
? diseaseId.toUpperCase().includes(expected) : false;
}

getDiseaseDatabaseName(diseaseId){
return diseaseId != "" && diseaseId != null ? diseaseId.split(':')[0] : '';
}

applyGeneFilter(filterValue: string) {
filterValue = filterValue.trim(); // Remove whitespace
filterValue = filterValue.toLowerCase(); // MatTableDataSource defaults to lowercase matches
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
import { async, ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';

import {ProfileSearchComponent} from './profile-search.component';
import {SearchService} from "../../../shared/search/service/search.service";
Expand All @@ -11,10 +11,10 @@ describe('ProfileSearchComponent', () => {
let component: ProfileSearchComponent;
let fixture: ComponentFixture<ProfileSearchComponent>;

beforeEach(async(() => {
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [ProfileSearchComponent],
providers: [SearchService, TermService],
providers: [SearchService],
imports: [HttpClientTestingModule, GlobalMaterialModules, NoopAnimationsModule]
})
.compileComponents();
Expand Down
4 changes: 4 additions & 0 deletions src/app/browser/pages/term/term.component.css
Original file line number Diff line number Diff line change
Expand Up @@ -233,3 +233,7 @@ img.mat-chip-avatar::before {
.translate-btn .material-icons {
font-size: 18px;
}

.source-hover {
text-decoration: none;
}
69 changes: 67 additions & 2 deletions src/app/browser/pages/term/term.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ <h3 class="card-title">Hierarchy</h3>
<!-- TABS -->
<div class="hpo-group-tab" *ngIf="term">
<mat-tab-group selectedIndex="0" class="term-details-tab-group mat-elevation-z6">
<!-- Disease association -->
<!-- Disease Association -->
<mat-tab label="Disease Associations">
<div [hidden]="diseaseAssocCount === 0">
<div class="tab-output-container">
Expand Down Expand Up @@ -174,7 +174,7 @@ <h4>Ontology Annotation Network Error. <a href="https://github.com/TheJacksonLab
</mat-tab>

<!-- Gene Association -->
<mat-tab label="Gene Associations">
<mat-tab label="Gene Associations [Inferred]">
<div [hidden]="geneAssocCount === 0">
<div class="tab-output-container">
<div class="filter-container">
Expand Down Expand Up @@ -223,6 +223,71 @@ <h4>Ontology Annotation Network Error. <a href="https://github.com/TheJacksonLab
</div>
</mat-tab>

<!-- Medical Action Association -->
<mat-tab label="Medical Actions">
<div [hidden]="medicalActionDisplayCount === 0">
<div class="tab-output-container">
<mat-progress-bar *ngIf="assocLoading" class="loading-result-details" color="primary"
mode="indeterminate">
</mat-progress-bar>

<div [hidden]="assocLoading" class="associations medical-actions-association">
<mat-table [dataSource]="medicalActionSource">
<mat-header-row *matHeaderRowDef="medicalActionColumns; sticky: true"></mat-header-row>
<mat-row *matRowDef="let row; columns: medicalActionColumns;"></mat-row>
<ng-container matColumnDef="id">
<mat-header-cell *matHeaderCellDef>MaXo Id</mat-header-cell>
<mat-cell *matCellDef="let row">
{{row.id}}
</mat-cell>
</ng-container>
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef> MaXo Name</mat-header-cell>
<mat-cell *matCellDef="let row">
{{row.name}}
</mat-cell>
</ng-container>
<ng-container matColumnDef="relation">
<mat-header-cell *matHeaderCellDef> Relation</mat-header-cell>
<mat-cell *matCellDef="let row">
<ng-container *ngIf="row.relations.length == 1">
{{row.relations[0]}}
</ng-container>
<ng-container *ngIf="row.relations.length > 1">
{{row.relations.join(" and ")}}
</ng-container>
</mat-cell>
</ng-container>
<ng-container matColumnDef="source">
<mat-header-cell *matHeaderCellDef> Sources</mat-header-cell>
<mat-cell *matCellDef="let row; let i = index">
<div *ngFor="let source of row.sources">
<div class="source" *ngIf="utilityService.isTermIdExpected(source,'PMID')">
<a class="source-hover" [href]="utilityService.getExternalTermIdUrlFromId(source)" target="_blank">
PubMed <i class="material-icons-outlined">library_books</i>&nbsp;&nbsp;
</a>
<a *ngIf="row.sources.length > 4">
({{row.sources.length - 4}} more).
</a>
</div>
</div>
</mat-cell>
</ng-container>
</mat-table>

<!-- paging: associations subset count -->
<div *ngIf="!assocLoading" class="associationsPaging">
<p>{{medicalActionDisplayCount}} medical actions.
</p>
</div>
</div>
</div>
</div>
<div class="container center" [hidden]="medicalActionDisplayCount !== 0">
<h4>No medical actions found for <strong>{{term.id}}</strong></h4>
</div>
</mat-tab>

<!-- Loinc Association -->
<div>
<mat-tab label="LOINC Associations">
Expand Down
Loading