diff --git a/src/app/analysis.service.ts b/src/app/analysis.service.ts index 0a94fbbb80ae71bc388bf46105b5069fb31abb9d..a1a2b97dbe0328636e028324ddd19cf155aefd6c 100644 --- a/src/app/analysis.service.ts +++ b/src/app/analysis.service.ts @@ -5,7 +5,7 @@ import {environment} from '../environments/environment'; import {toast} from 'bulma-toast'; import {Injectable} from '@angular/core'; -export type AlgorithmType = 'trustrank' | 'keypathwayminer' | 'multisteiner' | 'closeness' | 'degree' | 'proximity'; +export type AlgorithmType = 'trustrank' | 'keypathwayminer' | 'multisteiner' | 'closeness' | 'degree' | 'proximity' | 'betweenness'; export type QuickAlgorithmType = 'quick' | 'super'; export const algorithmNames = { @@ -15,6 +15,7 @@ export const algorithmNames = { closeness: 'Closeness Centrality', degree: 'Degree Centrality', proximity: 'Network Proximity', + betweenness: 'Betweenness Centrality', quick: 'Simple', super: 'Quick-Start', }; @@ -28,6 +29,7 @@ export const TRUSTRANK: Algorithm = {slug: 'trustrank', name: algorithmNames.tru export const CLOSENESS_CENTRALITY: Algorithm = {slug: 'closeness', name: algorithmNames.closeness}; export const DEGREE_CENTRALITY: Algorithm = {slug: 'degree', name: algorithmNames.degree}; export const NETWORK_PROXIMITY: Algorithm = {slug: 'proximity', name: algorithmNames.proximity}; +export const BETWEENNESS_CENTRALITY: Algorithm = {slug: 'betweenness', name: algorithmNames.betweenness}; export const KEYPATHWAYMINER: Algorithm = {slug: 'keypathwayminer', name: algorithmNames.keypathwayminer}; export const MULTISTEINER: Algorithm = {slug: 'multisteiner', name: algorithmNames.multisteiner}; diff --git a/src/app/components/analysis-panel/analysis-panel.component.ts b/src/app/components/analysis-panel/analysis-panel.component.ts index dfc224ea4f41482d795864bfa473218ddc7eae81..1f577b9f405fec8399734af4621591ba01c596b7 100644 --- a/src/app/components/analysis-panel/analysis-panel.component.ts +++ b/src/app/components/analysis-panel/analysis-panel.component.ts @@ -60,7 +60,7 @@ export class AnalysisPanelComponent implements OnInit, OnChanges { @Output() tokenChange = new EventEmitter<string | null>(); @Output() showDetailsChange = new EventEmitter<Wrapper>(); - @Output() visibleItems = new EventEmitter<[any[], [Protein[], ViralProtein[], Drug[]]]>(); + @Output() visibleItems = new EventEmitter<[any[], [Protein[], ViralProtein[], Tissue]]>(); public task: Task | null = null; @@ -332,7 +332,7 @@ export class AnalysisPanelComponent implements OnInit, OnChanges { public emitVisibleItems(on: boolean) { if (on) { - this.visibleItems.emit([this.nodeData.nodes, [this.proteins, this.effects, []]]); + this.visibleItems.emit([this.nodeData.nodes, [this.proteins, this.effects, this.selectedTissue]]); } else { this.visibleItems.emit(null); } @@ -651,44 +651,42 @@ export class AnalysisPanelComponent implements OnInit, OnChanges { updatedNodes.push(node); } this.nodeData.nodes.update(updatedNodes); - return; - } - - this.selectedTissue = tissue; - - const minExp = 0.3; - - this.http.get<Array<{ protein: Protein, level: number }>>( - `${environment.backend}tissue_expression/?tissue=${tissue.id}&token=${this.token}`) - .subscribe((levels) => { - const updatedNodes = []; - const maxExpr = Math.max(...levels.map(lvl => lvl.level)); - for (const lvl of levels) { - const item = getWrapperFromProtein(lvl.protein); - const node = this.nodeData.nodes.get(item.nodeId); - if (!node) { - continue; + } else { + this.selectedTissue = tissue; + const minExp = 0.3; + this.http.get<Array<{ protein: Protein, level: number }>>( + `${environment.backend}tissue_expression/?tissue=${tissue.id}&token=${this.token}`) + .subscribe((levels) => { + const updatedNodes = []; + const maxExpr = Math.max(...levels.map(lvl => lvl.level)); + for (const lvl of levels) { + const item = getWrapperFromProtein(lvl.protein); + const node = this.nodeData.nodes.get(item.nodeId); + if (!node) { + continue; + } + const gradient = lvl.level !== null ? (Math.pow(lvl.level / maxExpr, 1 / 3) * (1 - minExp) + minExp) : -1; + const pos = this.network.getPositions([item.nodeId]); + node.x = pos[item.nodeId].x; + node.y = pos[item.nodeId].y; + Object.assign(node, + NetworkSettings.getNodeStyle( + node.wrapper.type, + node.isSeed, + this.analysis.inSelection(item), + undefined, + undefined, + gradient)); + node.wrapper = item; + node.gradient = gradient; + this.proteins.find(prot => getProteinNodeId(prot) === item.nodeId).expressionLevel = lvl.level; + (node.wrapper.data as Protein).expressionLevel = lvl.level; + updatedNodes.push(node); } - const gradient = lvl.level !== null ? (Math.pow(lvl.level / maxExpr, 1 / 3) * (1 - minExp) + minExp) : -1; - const pos = this.network.getPositions([item.nodeId]); - node.x = pos[item.nodeId].x; - node.y = pos[item.nodeId].y; - Object.assign(node, - NetworkSettings.getNodeStyle( - node.wrapper.type, - node.isSeed, - this.analysis.inSelection(item), - undefined, - undefined, - gradient)); - node.wrapper = item; - node.gradient = gradient; - this.proteins.find(prot => getProteinNodeId(prot) === item.nodeId).expressionLevel = lvl.level; - (node.wrapper.data as Protein).expressionLevel = lvl.level; - updatedNodes.push(node); - } - this.nodeData.nodes.update(updatedNodes); - }); + this.nodeData.nodes.update(updatedNodes); + }); + } + this.emitVisibleItems(true); } } diff --git a/src/app/components/info-tile/info-tile.component.html b/src/app/components/info-tile/info-tile.component.html index 8dbaf9d91da581e9734c131bf687be224dd658c4..abc58f66a7223697bed45c3ac9124236bb2a6c51 100644 --- a/src/app/components/info-tile/info-tile.component.html +++ b/src/app/components/info-tile/info-tile.component.html @@ -55,6 +55,7 @@ <div *ngFor="let link of wrapper.data.trialLinks" class="list-item"> <a [href]="link" target="_blank">{{beautify(link)}}</a> </div> + <small class="list-item"><i>Links provided by WHO</i></small> </div> </div> diff --git a/src/app/dialogs/add-expressed-proteins/add-expressed-proteins.component.html b/src/app/dialogs/add-expressed-proteins/add-expressed-proteins.component.html index 9cf4f5dc7af8a1a704adb6e601bcfcfec329f8b5..47e9217dcffca4afd5a63bcb207adc381f6680cf 100644 --- a/src/app/dialogs/add-expressed-proteins/add-expressed-proteins.component.html +++ b/src/app/dialogs/add-expressed-proteins/add-expressed-proteins.component.html @@ -4,31 +4,56 @@ <header class="modal-card-head"> <p class="modal-card-title"> <span class="icon"><i class="fa fa-dna"></i></span> - Add Expressed Proteins + Add Tissue Proteins </p> <button (click)="close()" class="delete" aria-label="close"></button> </header> <section class="modal-card-body"> - <div class="field"> - <label class="label" for="threshold">Threshold</label> + <div class="notification is-warning" *ngIf="addedCount === 0"> + No host proteins have been selected or added. + </div> + <div class="notification is-warning" *ngIf="addedCount > 0"> + {{addedCount}} host proteins have been selected or added. + </div> + <p *ngIf="!selectedTissue"> + <i> + In order to add proteins expressed in specific tissues, + please select a tissue in the main network window to the bottom. + </i> + </p> + <p *ngIf="selectedTissue" class="mb-3"> + Currently selected tissue: <strong>{{selectedTissue.name}}</strong> + </p> + <div class="field" *ngIf="selectedTissue"> + <label class="label" for="threshold">Threshold (TPM)</label> <div class="control"> <input [ngModel]="threshold" (ngModelChange)="setThreshold($event)" id="threshold" class="input" type="number" placeholder="Threshold" required> </div> <p class="help"> - All proteins above this threshold. + All proteins above this threshold in transcripts per million (TPM) will be added or selected. </p> </div> </section> <footer class="modal-card-foot"> + <button (click)="addProteins();" class="button is-success is-rounded has-tooltip" + data-tooltip="Add all to the selection." + [disabled]="proteins.length === 0 || !selectedTissue || loading"> + <span class="icon"> + <i class="fas fa-plus"></i> + </span> + <span> + Add proteins + </span> + </button> <button (click)="addVisibleProteins();" class="button is-success is-rounded has-tooltip" data-tooltip="Add to selection if they appear in the current network." - [disabled]="proteins.length === 0"> + [disabled]="proteins.length === 0 || !selectedTissue || loading"> <span class="icon"> <i class="fas fa-expand"></i> </span> <span> - Select {{proteins.length}} proteins + Select proteins ({{proteins.length}}) </span> </button> <button (click)="close()" class="button is-rounded has-tooltip" data-tooltip="Close the current window."> diff --git a/src/app/dialogs/add-expressed-proteins/add-expressed-proteins.component.ts b/src/app/dialogs/add-expressed-proteins/add-expressed-proteins.component.ts index 9b9bf3060ed1332a0480b6a5e6138b1e2a317141..6b9e198705199d78463c8278e166f904a1126034 100644 --- a/src/app/dialogs/add-expressed-proteins/add-expressed-proteins.component.ts +++ b/src/app/dialogs/add-expressed-proteins/add-expressed-proteins.component.ts @@ -1,6 +1,8 @@ import {Component, EventEmitter, Input, OnChanges, Output, SimpleChanges} from '@angular/core'; import {AnalysisService} from '../../analysis.service'; -import {Protein} from '../../interfaces'; +import {getWrapperFromProtein, Protein, Tissue} from '../../interfaces'; +import {environment} from '../../../environments/environment'; +import {HttpClient} from '@angular/common/http'; @Component({ selector: 'app-add-expressed-proteins', @@ -17,21 +19,37 @@ export class AddExpressedProteinsComponent implements OnChanges { public visibleNodes: Array<any> = []; @Input() public currentViewProteins: Array<Protein> = []; + @Input() + public selectedTissue: Tissue | null = null; public proteins = []; - public threshold = 5; + public addedCount: number | null = null; + public loading = false; - constructor(private analysis: AnalysisService) { + constructor(private http: HttpClient, private analysis: AnalysisService) { } - public close() { - this.show = false; - this.showChange.emit(this.show); + ngOnChanges(changes: SimpleChanges): void { + this.setThreshold(this.threshold); + } + + public async addProteins() { + this.loading = true; + const result = await this.http.post<any>(`${environment.backend}query_tissue_proteins/`, + {tissueId: this.selectedTissue.id, threshold: this.threshold}).toPromise(); + const items = []; + for (const detail of result) { + items.push(getWrapperFromProtein(detail)); + } + this.addedCount = this.analysis.addItems(items); + this.loading = false; } public addVisibleProteins() { - this.analysis.addExpressedHostProteins(this.visibleNodes, this.currentViewProteins, this.threshold); + this.loading = true; + this.addedCount = this.analysis.addExpressedHostProteins(this.visibleNodes, this.currentViewProteins, this.threshold); + this.loading = false; } public setThreshold(threshold: number) { @@ -42,8 +60,10 @@ export class AddExpressedProteinsComponent implements OnChanges { this.proteins = this.currentViewProteins.filter(p => p.expressionLevel >= threshold); } - ngOnChanges(changes: SimpleChanges): void { - this.setThreshold(this.threshold); + public close() { + this.show = false; + this.showChange.emit(this.show); + this.addedCount = null; } } diff --git a/src/app/dialogs/custom-proteins/custom-proteins.component.html b/src/app/dialogs/custom-proteins/custom-proteins.component.html index 7eb960a1bf9bed70ea79ffa99e8feada0e9e8828..4b9dbad6562df7eb3d5f9617dcf67fa06d4baa27 100644 --- a/src/app/dialogs/custom-proteins/custom-proteins.component.html +++ b/src/app/dialogs/custom-proteins/custom-proteins.component.html @@ -44,7 +44,7 @@ <footer class="modal-card-foot"> <button (click)="addProteins();" class="button is-success is-rounded has-tooltip" data-tooltip="Add all to the selection." - [disabled]="proteins.length === 0"> + [disabled]="proteins.length === 0 || loading"> <span class="icon"> <i class="fa fa-plus"></i> </span> @@ -54,7 +54,7 @@ </button> <button (click)="addVisibleProteins();" class="button is-success is-rounded has-tooltip" data-tooltip="Add to selection if they appear in the current network." - [disabled]="proteins.length === 0"> + [disabled]="proteins.length === 0 || loading"> <span class="icon"> <i class="fas fa-expand"></i> </span> diff --git a/src/app/dialogs/custom-proteins/custom-proteins.component.ts b/src/app/dialogs/custom-proteins/custom-proteins.component.ts index 55bb13ddedb789d650c87f576e0eb41288ac5ff3..a6994260cddbaba0302cadec4b03dfa1fd9cc1fa 100644 --- a/src/app/dialogs/custom-proteins/custom-proteins.component.ts +++ b/src/app/dialogs/custom-proteins/custom-proteins.component.ts @@ -24,6 +24,7 @@ export class CustomProteinsComponent implements OnInit { public itemsFound: Array<Wrapper> = []; public addedCount = 0; public selectOnly = false; + public loading = false; constructor(private http: HttpClient, private analysis: AnalysisService) { } @@ -42,6 +43,7 @@ export class CustomProteinsComponent implements OnInit { } public async addProteins() { + this.loading = true; this.notFound = []; this.itemsFound = []; const proteins = this.proteins; @@ -56,9 +58,11 @@ export class CustomProteinsComponent implements OnInit { this.itemsFound = items; this.addedCount = this.analysis.addItems(items); this.selectOnly = false; + this.loading = false; } public async addVisibleProteins() { + this.loading = true; this.notFound = []; this.itemsFound = []; const proteins = this.proteins; @@ -75,6 +79,7 @@ export class CustomProteinsComponent implements OnInit { this.itemsFound = items; this.addedCount = this.analysis.addVisibleHostProteins(this.visibleNodes, proteinItems); this.selectOnly = true; + this.loading = false; } public changeTextList(textList) { diff --git a/src/app/dialogs/launch-analysis/launch-analysis.component.html b/src/app/dialogs/launch-analysis/launch-analysis.component.html index df64a9f1cb9ed2d0a64b6da3c217a9aa9d36084b..25154731e1ee3180e52b33d52f3d2e442ab81d3a 100644 --- a/src/app/dialogs/launch-analysis/launch-analysis.component.html +++ b/src/app/dialogs/launch-analysis/launch-analysis.component.html @@ -115,9 +115,13 @@ <div class="content"> <h6 class="is-6">About TrustRank</h6> <p> - <a href="https://en.wikipedia.org/wiki/TrustRank" target="_blank">TrustRank</a> - is a node centrality measure that ranks nodes in a network based on how well they are connected to a - (trusted) set of seed nodes (Gyöngyi, Garcia-Molina, and Pedersen 2004). + TrustRank is a node centrality measure that ranks nodes in a network based on how well they are + connected to a (trusted) set of seed nodes. + </p> + <p> + <a href="https://docs.google.com/document/d/1_SRnIx_UC8FR59rMyrf_r45fCIt3naP4t1qefYNp9vk" target="_blank"> + Check the documentation for more info + </a> </p> </div> </div> @@ -194,9 +198,8 @@ <div class="content"> <h6 class="is-6">About Closeness Centrality</h6> <p> - <a href="https://en.wikipedia.org/wiki/Closeness_centrality" target="_blank">Closeness Centrality</a> - is a node centrality measure that ranks the nodes in a network based on the lengths of their shortest - paths to all other nodes in the network (Kaczprowski, Doncheva, and Albrecht 2013). + Closeness Centrality is a node centrality measure that ranks the nodes in a network based on the + lengths of their shortest paths to all other nodes in the network. </p> </div> </div> @@ -250,11 +253,8 @@ <div class="content"> <h6 class="is-6">About Degree Centrality</h6> <p> - <a href="https://en.wikipedia.org/wiki/Centrality#Degree_centrality" target="_blank"> - Degree Centrality - </a> - assigns an importance score based simply on the number of links held by each node. In CoVex, we use - a modified version which does not consider all links but only the neighbouring seeds. + Degree Centrality assigns an importance score based simply on the number of links held by each node. + In CoVex, we use a modified version which does not consider all links but only the neighbouring seeds. </p> </div> </div> @@ -280,28 +280,6 @@ [(value)]="proximityIncludeNonApprovedDrugs"></app-toggle> </div> - <div class="field"> - <label class="label" for="proximity-rss">No. of random seed sets</label> - <div class="control"> - <input [(ngModel)]="proximityNumRandomSeedSets" id="proximity-rss" class="input" type="number" - placeholder="Maximum degree" min="0" max="1" required> - </div> - <p class="help"> - Number of random seed sets for computing Z-scores. - </p> - </div> - - <div class="field"> - <label class="label" for="proximity-rdts">No. of random drug target sets</label> - <div class="control"> - <input [(ngModel)]="proximityNumRandomDrugTargetSets" id="proximity-rdts" class="input" type="number" - placeholder="Maximum degree" min="0" max="1" required> - </div> - <p class="help"> - Number of random drug target sets for computing Z-scores. - </p> - </div> - <div class="field"> <label class="label" for="proximity-md">Maximum degree</label> <div class="control"> @@ -324,6 +302,52 @@ </p> </div> + <div class="box"> + <article class="media"> + <div class="media-left"> + <span class="icon"><i class="fa fa-info"></i></span> + </div> + <div class="media-content"> + <div class="content"> + <h6 class="is-6">About Degree Centrality</h6> + <p> + Degree Centrality uses the average minimum distance from the drug’s targets to all of the selected + seeds as a measure of proximity. + </p> + </div> + </div> + </article> + </div> + + </div> + + <div *ngIf="algorithm==='betweenness'"> + + <div class="field"> + <label class="label" for="proximity-rs">Result size</label> + <div class="control"> + <input [(ngModel)]="betweennessResultSize" id="betweenness-rs" class="input" type="number" + placeholder="Result size" required> + </div> + </div> + + <div class="box"> + <article class="media"> + <div class="media-left"> + <span class="icon"><i class="fa fa-info"></i></span> + </div> + <div class="media-content"> + <div class="content"> + <h6 class="is-6">About Betweenness Centrality</h6> + <p> + Betweenness Centrality ranks the proteins in a network based on how many shortest paths pass through + them. + </p> + </div> + </div> + </article> + </div> + </div> <div *ngIf="algorithm==='keypathwayminer'"> @@ -367,9 +391,8 @@ <div class="content"> <h6 class="is-6">About KeyPathwayMiner</h6> <p> - <a href="https://keypathwayminer.compbio.sdu.dk/keypathwayminer/">KeyPathwayMiner</a> - is a network enrichment tool that identifies condition-specific sub-networks (key pathways) - (Alcaraz et al. 2016). + KeyPathwayMiner is a network enrichment tool that identifies condition-specific sub-networks + (key pathways) (Alcaraz et al. 2016). </p> </div> </div> @@ -446,25 +469,13 @@ [(value)]="multisteinerIncludeViralNonSeeds"></app-toggle> </div> - <div class="box"> - <article class="media"> - <div class="media-left"> - <span class="icon"><i class="fa fa-info"></i></span> - </div> - <div class="media-content"> - <div class="content"> - <h6 class="is-6">About Multi-Steiner</h6> - <p> - The <a href="https://en.wikipedia.org/wiki/Steiner_tree_problem">Steiner tree</a> - problem is a classical combinatorial optimization problem. It asks to find a sub-graph - of minimum size connecting a given set of seed nodes. - </p> - </div> - </div> - </article> - </div> - </div> + + <p class="doc-link"> + <a href="https://docs.google.com/document/d/1_SRnIx_UC8FR59rMyrf_r45fCIt3naP4t1qefYNp9vk" target="_blank"> + Check the documentation for more info + </a> + </p> </section> <footer class="modal-card-foot"> diff --git a/src/app/dialogs/launch-analysis/launch-analysis.component.scss b/src/app/dialogs/launch-analysis/launch-analysis.component.scss index 07fa0d31e0d3f77829ed228285185c1cbe457022..717dbc6cc5486f837779e6c85e938b9773aa77ba 100644 --- a/src/app/dialogs/launch-analysis/launch-analysis.component.scss +++ b/src/app/dialogs/launch-analysis/launch-analysis.component.scss @@ -19,3 +19,8 @@ background-color: blue; } } + +.doc-link { + margin-top: 15px; + font-size: 11px; +} diff --git a/src/app/dialogs/launch-analysis/launch-analysis.component.ts b/src/app/dialogs/launch-analysis/launch-analysis.component.ts index 285d84158a938bcc1de89ffa3bb42eb753e4af4b..640fc9095d631b6ab8b7611637a640b51ad17eb5 100644 --- a/src/app/dialogs/launch-analysis/launch-analysis.component.ts +++ b/src/app/dialogs/launch-analysis/launch-analysis.component.ts @@ -2,7 +2,7 @@ import {Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges import { Algorithm, AlgorithmType, - AnalysisService, CLOSENESS_CENTRALITY, + AnalysisService, BETWEENNESS_CENTRALITY, CLOSENESS_CENTRALITY, DEGREE_CENTRALITY, KEYPATHWAYMINER, MAX_TASKS, MULTISTEINER, NETWORK_PROXIMITY, @@ -58,10 +58,11 @@ export class LaunchAnalysisComponent implements OnInit, OnChanges { public proximityIncludeNonApprovedDrugs = false; public proximityMaxDeg = 0; public proximityHubPenalty = 0.0; - public proximityNumRandomSeedSets = 32; - public proximityNumRandomDrugTargetSets = 32; public proximityResultSize = 20; + // Betweenness Parameters + public betweennessResultSize = 20; + // Keypathwayminer Parameters public keypathwayminerK = 5; @@ -88,7 +89,7 @@ export class LaunchAnalysisComponent implements OnInit, OnChanges { ngOnChanges(changes: SimpleChanges): void { if (this.target === 'drug-target') { - this.algorithms = [MULTISTEINER, KEYPATHWAYMINER, TRUSTRANK, CLOSENESS_CENTRALITY, DEGREE_CENTRALITY]; + this.algorithms = [MULTISTEINER, KEYPATHWAYMINER, TRUSTRANK, CLOSENESS_CENTRALITY, DEGREE_CENTRALITY, BETWEENNESS_CENTRALITY]; this.algorithm = MULTISTEINER.slug; } else if (this.target === 'drug') { this.algorithms = [TRUSTRANK, CLOSENESS_CENTRALITY, DEGREE_CENTRALITY, NETWORK_PROXIMITY]; @@ -141,9 +142,9 @@ export class LaunchAnalysisComponent implements OnInit, OnChanges { parameters.max_deg = this.proximityMaxDeg; } parameters.hub_penalty = this.proximityHubPenalty; - parameters.num_random_seed_sets = this.proximityNumRandomSeedSets; - parameters.num_random_drug_target_sets = this.proximityNumRandomDrugTargetSets; parameters.result_size = this.proximityResultSize; + } else if (this.algorithm === 'betweenness') { + parameters.result_size = this.betweennessResultSize; } else if (this.algorithm === 'keypathwayminer') { parameters.k = this.keypathwayminerK; } else if (this.algorithm === 'multisteiner') { diff --git a/src/app/pages/about-page/about-page.component.html b/src/app/pages/about-page/about-page.component.html index 06ad3b90b58fcfb645c1ff5fb2ce2dbc1ac62474..a0732b1fcd669f8c098a5260eee234b8a54b12ef 100644 --- a/src/app/pages/about-page/about-page.component.html +++ b/src/app/pages/about-page/about-page.component.html @@ -19,15 +19,17 @@ <br> CoVex (Coronavirus Explorer) is a unique online network and systems medicine platform for data analysis that integrates virus-human interactions for SARS-CoV-2 and SARS-CoV-1. It implements different network-based - approaches for the identification of new drug targets and new repurposable drugs. + approaches for the identification of new drug targets and new repurposable drugs.<br> <br> + For instructions and help check the documentation: + <a href="https://docs.google.com/document/d/1_SRnIx_UC8FR59rMyrf_r45fCIt3naP4t1qefYNp9vk">CoVex Documentation</a><br> + <br> + For detailed information please visit our blog: <a href="https://www.exbio.de/exbio-vs-covid-part-1/">ExBio vs Covid</a><br> <br> - For detailed information please visit our blog: <a href="https://www.exbio.de/exbio-vs-covid-part-1/"> https://www.exbio.de/exbio-vs-covid-part-1/</a> - <br> - <br> We are constantly updating and integrating new data as it becomes available. - <br> - If you are interested to make your virus-human interactome data available via our platform, please contact us. + <br> + If you are interested to make your virus-human interactome data available via our platform, please contact + us. </p> <h2 class="subtitle">General workflow of the platform</h2> <ol> @@ -48,7 +50,7 @@ <li>Systems and network medicine: Sepideh Sadegh (sadegh_AT_wzw.tum.de)</li> <li>Web platform: Julian Matschinske (julian.matschinske_AT_wzw.tum.de)</li> <li>Project coordination: Prof. Dr. Jan Baumbach (jan.baumbach_AT_wzw.tum.de)</li> - <li>Lab website: <a href="http://www.exbio.de">http://www.exbio.de</a> </li> + <li>Lab website: <a href="http://www.exbio.de">http://www.exbio.de</a></li> </ul> <br> diff --git a/src/app/pages/explorer-page/explorer-page.component.html b/src/app/pages/explorer-page/explorer-page.component.html index 81b06e2a7d08ac5e4ba62a9c6dd7e944a6187448..9118923b4b373df445a10e80f28584b70a6f429b 100644 --- a/src/app/pages/explorer-page/explorer-page.component.html +++ b/src/app/pages/explorer-page/explorer-page.component.html @@ -8,6 +8,7 @@ </app-custom-proteins> <app-add-expressed-proteins [(show)]="showThresholdDialog" + [selectedTissue]="currentViewSelectedTissue" [visibleNodes]="currentViewNodes" [currentViewProteins]="currentViewProteins"> </app-add-expressed-proteins> @@ -180,7 +181,8 @@ <div class="dropdown-trigger"> <button (click)="expressionExpanded=!expressionExpanded" class="button is-rounded is-primary" [class.is-outlined]="!selectedTissue" - aria-haspopup="true" aria-controls="dropdown-menu"> + aria-haspopup="true" aria-controls="dropdown-menu" + data-tooltip="Tissue expression data is provided by the GTEx project."> <span *ngIf="!selectedTissue">Tissue</span> <span *ngIf="selectedTissue">{{selectedTissue.name}}</span> <span class="icon is-small"> @@ -569,7 +571,7 @@ <i class="fa fa-angle-double-up"></i> </span> <span> - Expressed proteins + Tissue proteins </span> </a> </footer> diff --git a/src/app/pages/explorer-page/explorer-page.component.ts b/src/app/pages/explorer-page/explorer-page.component.ts index ce0a44c7348d75609b51e33ca32d56766a358910..85fa3ed0b02a05ba815cb779eeb6fc2c4b60aba5 100644 --- a/src/app/pages/explorer-page/explorer-page.component.ts +++ b/src/app/pages/explorer-page/explorer-page.component.ts @@ -69,6 +69,7 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit { public currentViewProteins: Protein[]; public currentViewViralProteins: ViralProtein[]; + public currentViewSelectedTissue: Tissue | null = null; public currentViewNodes: any[]; public expressionExpanded = false; @@ -471,15 +472,17 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit { }); } - analysisWindowChanged($event: any) { + analysisWindowChanged($event: [any[], [Protein[], ViralProtein[], Tissue]]) { if ($event) { this.currentViewNodes = $event[0]; this.currentViewProteins = $event[1][0]; this.currentViewViralProteins = $event[1][1]; + this.currentViewSelectedTissue = $event[1][2]; } else { this.currentViewNodes = this.nodeData.nodes; this.currentViewProteins = this.proteins; this.currentViewViralProteins = this.effects; + this.currentViewSelectedTissue = this.selectedTissue; } } @@ -505,6 +508,7 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit { } public selectTissue(tissue: Tissue | null) { + this.expressionExpanded = false; if (!tissue) { this.selectedTissue = null; const updatedNodes = []; @@ -532,45 +536,47 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit { updatedNodes.push(node); } this.nodeData.nodes.update(updatedNodes); - return; - } - - this.selectedTissue = tissue; + } else { + this.selectedTissue = tissue; + + const minExp = 0.3; + + const params = new HttpParams().set('tissue', `${tissue.id}`).set('data', JSON.stringify(this.currentDataset)); + this.http.get<any>( + `${environment.backend}tissue_expression/`, {params}) + .subscribe((levels) => { + const updatedNodes = []; + const maxExpr = Math.max(...levels.map(lvl => lvl.level)); + for (const lvl of levels) { + const item = getWrapperFromProtein(lvl.protein); + const node = this.nodeData.nodes.get(item.nodeId); + if (!node) { + continue; + } + const gradient = lvl.level !== null ? (Math.pow(lvl.level / maxExpr, 1 / 3) * (1 - minExp) + minExp) : -1; + const pos = this.network.getPositions([item.nodeId]); + node.x = pos[item.nodeId].x; + node.y = pos[item.nodeId].y; + Object.assign(node, + NetworkSettings.getNodeStyle( + node.wrapper.type, + node.isSeed, + this.analysis.inSelection(item), + undefined, + undefined, + gradient)); + node.wrapper = item; + node.gradient = gradient; + this.proteins.find(prot => getProteinNodeId(prot) === item.nodeId).expressionLevel = lvl.level; + (node.wrapper.data as Protein).expressionLevel = lvl.level; + updatedNodes.push(node); + } + this.nodeData.nodes.update(updatedNodes); + }); - const minExp = 0.3; + } - const params = new HttpParams().set('tissue', `${tissue.id}`).set('data', JSON.stringify(this.currentDataset)); - this.http.get<any>( - `${environment.backend}tissue_expression/`, {params}) - .subscribe((levels) => { - const updatedNodes = []; - const maxExpr = Math.max(...levels.map(lvl => lvl.level)); - for (const lvl of levels) { - const item = getWrapperFromProtein(lvl.protein); - const node = this.nodeData.nodes.get(item.nodeId); - if (!node) { - continue; - } - const gradient = lvl.level !== null ? (Math.pow(lvl.level / maxExpr, 1 / 3) * (1 - minExp) + minExp) : -1; - const pos = this.network.getPositions([item.nodeId]); - node.x = pos[item.nodeId].x; - node.y = pos[item.nodeId].y; - Object.assign(node, - NetworkSettings.getNodeStyle( - node.wrapper.type, - node.isSeed, - this.analysis.inSelection(item), - undefined, - undefined, - gradient)); - node.wrapper = item; - node.gradient = gradient; - this.proteins.find(prot => getProteinNodeId(prot) === item.nodeId).expressionLevel = lvl.level; - (node.wrapper.data as Protein).expressionLevel = lvl.level; - updatedNodes.push(node); - } - this.nodeData.nodes.update(updatedNodes); - }); + this.currentViewSelectedTissue = this.selectedTissue; } } diff --git a/src/styles.scss b/src/styles.scss index 8329e918f2ffda492864fb4c0d1b1b84d4a720e5..d2b730c504ac0769aa05422298e875e5a919e611 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -234,3 +234,7 @@ body { padding-right: 5px; } } + +.mb-3 { + margin-bottom: 10px; +}