diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 65cf8634f227c91367dd5b60316e615235597ce2..adbb49e864436af973f80207c70e5e3a274c5672 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -67,7 +67,7 @@ deploy:prod: image: docker stage: deploy only: - - master + - production when: manual services: - docker:dind diff --git a/src/app/config.ts b/src/app/config.ts index 72b4b9c9d55f58ab8add1ece38b0ae83899ebaec..25cee3f1055a0cfbd3134d4259802ffafc69413f 100644 --- a/src/app/config.ts +++ b/src/app/config.ts @@ -19,6 +19,10 @@ export interface EdgeGroup { color: string; } +export type Identifier = 'hugo'|'uniprot'; + +export type InteractionDatabase = 'omnipath'; + export interface IConfig { legendUrl: string; legendClass: string; @@ -38,7 +42,8 @@ export interface IConfig { showLegendEdges: boolean; nodeGroups: { [key: string]: NodeGroup }; edgeGroups: { [key: string]: EdgeGroup }; - interactions?: 'omnipath'; + interactions?: InteractionDatabase; + identifier?: Identifier; } export const defaultConfig: IConfig = { @@ -58,6 +63,7 @@ export const defaultConfig: IConfig = { showTasks: true, showFooter: true, showLegend: true, + identifier: 'hugo', nodeGroups: { default: { name: 'Default Group', diff --git a/src/app/pages/explorer-page/explorer-page.component.html b/src/app/pages/explorer-page/explorer-page.component.html index 43baf62eaa8aa7dcb86b2a5571cf9c5acebb97de..b4f0603093564ef85cddff13befba1cb2ccc7c4c 100644 --- a/src/app/pages/explorer-page/explorer-page.component.html +++ b/src/app/pages/explorer-page/explorer-page.component.html @@ -191,9 +191,9 @@ </span> <span *ngIf="!selectedWrapper">No item selected</span> <span *ngIf="selectedWrapper"> - <span *ngIf="selectedWrapper.type === 'protein'">Host Protein</span> - <span *ngIf="selectedWrapper.type === 'drug'">Drug</span> - </span> + <span *ngIf="selectedWrapper.type === 'protein'">Host Protein</span> + <span *ngIf="selectedWrapper.type === 'drug'">Drug</span> + </span> </p> <a (click)="collapseDetails = !collapseDetails" data-action="collapse" class="card-header-icon is-hidden-fullscreen" aria-label="more options"> @@ -406,40 +406,40 @@ <i *ngIf="!collapseSelection" class="fas fa-angle-left" aria-hidden="true"></i> </span> - </a> - </header> - <div *ngIf="collapseSelection" class="seed-selection"> - <div class="card-content overflow"> - <table class="table selection-table" *ngIf="analysis.getCount() > 0"> - <thead> - <tr> - <td>Type</td> - <td>Name</td> - <td>Actions</td> - </tr> - </thead> - <tbody> - <tr *ngFor="let p of analysis.getSelection()"> - <td> - </td> - <td>{{p.name}}</td> - <td> - <button (click)="analysis.removeItems([p])" class="button is-small is-danger is-outlined has-tooltip" - data-tooltip="Remove from selection."> - <i class="fa fa-trash"></i> - </button> - </td> - </tr> - </tbody> - </table> - <i *ngIf="analysis.getCount() === 0"> - Double-click on a protein to select it for the analysis. - </i> - </div> + </a> + </header> + <div *ngIf="collapseSelection" class="seed-selection"> + <div class="card-content overflow"> + <table class="table selection-table" *ngIf="analysis.getCount() > 0"> + <thead> + <tr> + <td>Type</td> + <td>Name</td> + <td>Actions</td> + </tr> + </thead> + <tbody> + <tr *ngFor="let p of analysis.getSelection()"> + <td> + </td> + <td>{{p.name}}</td> + <td> + <button (click)="analysis.removeItems([p])" class="button is-small is-danger is-outlined has-tooltip" + data-tooltip="Remove from selection."> + <i class="fa fa-trash"></i> + </button> + </td> + </tr> + </tbody> + </table> + <i *ngIf="analysis.getCount() === 0"> + Double-click on a protein to select it for the analysis. + </i> + </div> - <footer class="card-footer" *ngIf="selectedAnalysisToken"> - <a (click)="analysis.addSeeds(currentViewNodes)" - class="card-footer-item has-text-success" data-tooltip="Add all visible seeds."> + <footer class="card-footer" *ngIf="selectedAnalysisToken"> + <a (click)="analysis.addSeeds(currentViewNodes)" + class="card-footer-item has-text-success" data-tooltip="Add all visible seeds."> <span class="icon"> <i class="fa fa-plus"></i> diff --git a/src/app/pages/explorer-page/explorer-page.component.ts b/src/app/pages/explorer-page/explorer-page.component.ts index 7a909b16cd0cf0078064fbe7a56be2360d840fee..445639f38f5b8e42722bb22b8496de4997f37770 100644 --- a/src/app/pages/explorer-page/explorer-page.component.ts +++ b/src/app/pages/explorer-page/explorer-page.component.ts @@ -19,6 +19,7 @@ import {OmnipathControllerService} from '../../services/omnipath-controller/omni import html2canvas from 'html2canvas'; import {NetworkSettings} from '../../network-settings'; import {defaultConfig, EdgeGroup, IConfig, NodeGroup} from '../../config'; +import {Subscription} from "rxjs"; declare var vis: any; @@ -53,6 +54,9 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit { this.getInteractions(); continue; } + if (key === 'colorPrimary') { + this.setColorPrimary(configObj[key]); + } this.myConfig[key] = configObj[key]; } } @@ -169,10 +173,18 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit { } } + private setColorPrimary(color: string) { + console.log(color); + document.documentElement.style.setProperty('$primary', color); + } + async getInteractions() { const names = this.nodeData.nodes.map( (node) => node.label); - const interactions = await this.omnipath.getInteractions(names); - console.log(interactions) + const nameToNetworkId = {}; + this.nodeData.nodes.map( (node) => nameToNetworkId[node.label] = node.id); + const edges = await this.omnipath.getInteractions(names, this.myConfig.identifier, nameToNetworkId); + + this.nodeData.edges.update(edges); } private getNetwork() { @@ -221,9 +233,6 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit { this.proteinData = new ProteinNetwork(this.proteins, this.edges); this.proteinData.linkNodes(); - // Populate baits - const effectNames = []; - const {nodes, edges} = this.mapDataToNodes(this.proteinData); this.nodeData.nodes = new vis.DataSet(nodes); this.nodeData.edges = new vis.DataSet(edges); diff --git a/src/app/services/omnipath-controller/omnipath-controller.service.ts b/src/app/services/omnipath-controller/omnipath-controller.service.ts index 2b972edae8dab46cb6335917730a6cdef1149a9a..e86fa86c404b843fa02587c739eed7f7383f0835 100644 --- a/src/app/services/omnipath-controller/omnipath-controller.service.ts +++ b/src/app/services/omnipath-controller/omnipath-controller.service.ts @@ -12,7 +12,44 @@ export class OmnipathControllerService { } - public async getInteractions(genes): Promise<any> { + private processOmnipathInteractionData(rawData: string, identifier, nameToNetworkId) { + /** + * Converts the returned tsv-like data from omnipath into interaction-data for the network + */ + // split the lines + const lines = rawData.split('\n'); + // remove header + lines.shift(); + // split the rows and read the interactions + const interactions = []; + lines.forEach((line) => { + // skip empty strings + if (line === '') { + return; + } + const lineValues = line.split('\t'); + let source; + let target; + if (identifier === 'uniprot') { + // entry 1 is always source uniprot ID, entry 2 always target uniprot ID + source = lineValues[0]; + target = lineValues[1]; + } else if (identifier === 'hugo') { + // entry 3 is always source name, entry 4 always target name + source = lineValues[2]; + target = lineValues[3]; + } + interactions.push({from: nameToNetworkId[source], to: nameToNetworkId[target]}); + }); + return interactions; + } + + public async getInteractions(genes, identifier, nameToNetworkId) { + /** + * The Omnipath API returns a confusing HttpErrorResponse but also a status code 200. + * Anyway, the queried data can be found also in the error text + * thus, errors are also catched and their text is returned as valid return value + */ const genesString = genes.join(','); const params = new HttpParams() .set('genesymbols', '1') // return also gene symbols @@ -20,6 +57,11 @@ export class OmnipathControllerService { .set('sources', genesString) .set('targets', genesString) // all interactions between all genes .set('source_target', 'AND'); // for interactions which source in sources 'AND'/ 'OR' target in targets - return this.http.get<any>(`${this.omnipathdb}interactions/`, {params}).toPromise(); + let res = null; + await this.http.get<any>(`${this.omnipathdb}interactions/`, {params}).toPromise() + .then((data) => res = this.processOmnipathInteractionData(data.text, identifier, nameToNetworkId)) + .catch((error) => res = this.processOmnipathInteractionData(error.error.text, identifier, nameToNetworkId)); + + return res; } } diff --git a/src/environments/environment.prod.stage.ts b/src/environments/environment.prod.stage.ts new file mode 100644 index 0000000000000000000000000000000000000000..2dec8afe762c3bba69754df1325f56ba1b89d934 --- /dev/null +++ b/src/environments/environment.prod.stage.ts @@ -0,0 +1,4 @@ +export const environment = { + production: true, + backend: 'https://exbio.wzw.tum.de/drugstone/api/', +}; diff --git a/src/index.html b/src/index.html index 43dc83b1cbcd63d955be426921c31cbbb7562520..7487e01fd91ff203e889fb639b53dbd40710c0c7 100644 --- a/src/index.html +++ b/src/index.html @@ -42,9 +42,10 @@ config='{ "showQuery": false, "legendPos": "right", - "nodeGroups": {"genes": {"type": "gene", "color": "blue", "name": "Genes", "shape": "round"} }, + "nodeGroups": {"genes": {"type": "gene", "color": "blue", "name": "Genes", "shape": "circle"} }, "edgeGroups":{"default": {"color": "grey", "name": "Default Edge Group"}, "custom": {"color": "red", "name": "Custom Edge Group"} }, - "lookupInteractions": true + "lookupInteractions": true, + "colorPrimary": "#0000ff" }' style="height: 100vh"></network-expander> </div> @@ -83,10 +84,7 @@ } ], edges: [ - { - from: '1', - to: '2', - } + ] })); } diff --git a/src/main.ts b/src/main.ts index 19dca936dda9278e949351ea9e550c57f12f8efb..6e7e3153499e6ce1ad3530adf5c96478e86b4a87 100644 --- a/src/main.ts +++ b/src/main.ts @@ -14,16 +14,3 @@ if (environment.production) { platformBrowserDynamic().bootstrapModule(AppModule) // tslint:disable-next-line:no-console .catch(err => console.error(err)); - -const loadPage = (name: string) => { - const xhr = new XMLHttpRequest(); - xhr.open('GET', name, true); - xhr.onreadystatechange = function() { - if (this.readyState !== 4) { return; } - if (this.status !== 200) { return; } // or whatever error handling you want - document.getElementById('example').innerHTML = this.responseText; - }; - xhr.send(); -}; - -loadPage('app-test/icons.html');