From b4ef2615e2cf9b9671a26f1cbb8e0f26f7deb2f1 Mon Sep 17 00:00:00 2001 From: gromdimon Date: Tue, 26 Sep 2023 17:19:20 +0200 Subject: [PATCH] feat: genome browser --- backend/app/main.py | 4 + frontend/package-lock.json | 6 + frontend/package.json | 1 + frontend/src/api/common.ts | 3 + .../src/components/GenomeBrowser.tracks.ts | 159 ++++++++++++++++++ frontend/src/components/GenomeBrowser.vue | 104 ++++++++++++ .../SvDetails/SvDetailsGenotypeCall.vue | 4 +- frontend/src/views/SvDetailView.vue | 15 +- 8 files changed, 287 insertions(+), 9 deletions(-) create mode 100644 frontend/src/components/GenomeBrowser.tracks.ts create mode 100644 frontend/src/components/GenomeBrowser.vue diff --git a/backend/app/main.py b/backend/app/main.py index 0afde796..397eab18 100644 --- a/backend/app/main.py +++ b/backend/app/main.py @@ -26,6 +26,8 @@ BACKEND_PREFIX_MEHARI = env.get("REEV_BACKEND_PREFIX_MEHARI", "http://mehari:8080") #: Prefix for the backend of viguno service BACKEND_PREFIX_VIGUNO = env.get("REEV_BACKEND_PREFIX_VIGUNO", "http://viguno:8080") +#: Prefix for the backend of nginx service +BACKEND_PREFIX_NGINX = env.get("REEV_BACKEND_PREFIX_NGINX", "http://nginx:8080") #: Path to REEV version file. VERSION_FILE = env.get("REEV_VERSION_FILE", "/VERSION") #: The REEV version from the file (``None`` if to load dynamically from git) @@ -97,6 +99,8 @@ async def reverse_proxy(request: Request) -> Response: backend_url = BACKEND_PREFIX_MEHARI + url.path.replace("/proxy/mehari", "") elif url.path.startswith("/proxy/viguno"): backend_url = BACKEND_PREFIX_VIGUNO + url.path.replace("/proxy/viguno", "") + elif url.path.startswith("/proxy/nginx"): + backend_url = BACKEND_PREFIX_NGINX + url.path.replace("/proxy/nginx", "") if backend_url: backend_url = backend_url + (f"?{url.query}" if url.query else "") diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 46b021f3..1d8b0199 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -10,6 +10,7 @@ "dependencies": { "@mdi/font": "^7.2.96", "@reactgular/chunks": "^1.0.1", + "igv": "^2.15.11", "pinia": "^2.1.6", "resize-observer-polyfill": "^1.5.1", "vega": "^5.25.0", @@ -5754,6 +5755,11 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/igv": { + "version": "2.15.11", + "resolved": "https://registry.npmjs.org/igv/-/igv-2.15.11.tgz", + "integrity": "sha512-oJs6z4ogv1GefIWaMdG5s4jFRuFQ/PjUgrGBMn12SbeeIC/VgHkHr56K5yIaC8ZSyameq/7IFDQaXu0qIu6cpA==" + }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index cfd80d8b..85a96cbe 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -16,6 +16,7 @@ "dependencies": { "@mdi/font": "^7.2.96", "@reactgular/chunks": "^1.0.1", + "igv": "^2.15.11", "pinia": "^2.1.6", "resize-observer-polyfill": "^1.5.1", "vega": "^5.25.0", diff --git a/frontend/src/api/common.ts b/frontend/src/api/common.ts index d98219e9..91f96ca3 100644 --- a/frontend/src/api/common.ts +++ b/frontend/src/api/common.ts @@ -5,3 +5,6 @@ export const API_BASE_PREFIX_ANNONARS = export const API_BASE_PREFIX_MEHARI = import.meta.env.MODE == 'development' ? '//localhost:8080/proxy/mehari' : '/proxy/mehari' + +export const API_BASE_PREFIX_NGINX = + import.meta.env.MODE == 'development' ? '//localhost:8080/proxy/nginx' : '/proxy/nginx' diff --git a/frontend/src/components/GenomeBrowser.tracks.ts b/frontend/src/components/GenomeBrowser.tracks.ts new file mode 100644 index 00000000..9d5fa304 --- /dev/null +++ b/frontend/src/components/GenomeBrowser.tracks.ts @@ -0,0 +1,159 @@ +import { API_BASE_PREFIX_NGINX } from '@/api/common' + +const API_BASE_URL = `${API_BASE_PREFIX_NGINX}/` + +const visibilityWindow = 10000000 + +const hescTadTrack = { + name: 'hESC TADs', + sourceType: 'annotation', + format: 'bed', + visibilityWindow, + url: `${API_BASE_URL}grch37/hesc.bed`, + color: 'gray' +} + +const curatedMmsTrack = { + name: 'Curated MMS', + sourceType: 'annotation', + format: 'bed', + visibilityWindow, + url: `${API_BASE_URL}grch37/patho-mms.bed`, + color: 'red' +} + +// const clinvarTrack = { +// name: 'ClinVar SVs', +// sourceType: 'custom', +// visibilityWindow, +// height: 100, +// displayMode: 'SQUISHED', +// source: { +// url: `/svs/worker/clinvar/grch37/?min_pathogenicity=likely-pathogenic&chromosome=$CHR&begin=$START&end=$END`, +// method: 'GET', +// contentType: 'application/json', +// mappings: { +// chr: 'chromosome', +// start: 'begin', +// }, +// queryable: true, +// }, +// format: 'annotation', +// colorBy: 'pathogenicity', +// colorTable: { +// pathogenic: 'red', +// 'likely-pathogenic': 'orange', +// uncertain: 'blue', +// 'likely-benign': 'gray', +// benign: 'light gray', +// }, +// } + +const duplicationTrack = { + name: 'UCSC Segmental Duplications', + sourceType: 'annotation', + format: 'bed', + visibilityWindow, + url: `${API_BASE_URL}grch37/genomicSuperDups.bed.gz`, + indexURL: `${API_BASE_URL}grch37/genomicSuperDups.bed.gz.tbi`, + color: 'black' +} + +const repeatsTrack = { + name: 'UCSC Repeat Masker', + sourceType: 'annotation', + format: 'bed', + visibilityWindow, + url: `${API_BASE_URL}grch37/rmsk.bed.gz`, + indexURL: `${API_BASE_URL}grch37/rmsk.bed.gz.tbi`, + color: 'black' +} + +const altTrack = { + name: 'UCSC Alt Loci Track', + sourceType: 'annotation', + format: 'bed', + visibilityWindow, + url: `${API_BASE_URL}grch37/altSeqLiftOverPsl.bed.gz`, + indexURL: `${API_BASE_URL}grch37/altSeqLiftOverPsl.bed.gz.tbi`, + color: 'black' +} + +const fixTrack = { + name: 'UCSC Fix Track', + sourceType: 'annotation', + format: 'bed', + visibilityWindow, + url: `${API_BASE_URL}grch37/fixSeqLiftOverPsl.bed.gz`, + indexURL: `${API_BASE_URL}grch37/fixSeqLiftOverPsl.bed.gz.tbi`, + color: 'black' +} + +const bgDbTracks = [ + // { + // title: 'In-House SVs', + // token: 'inhouse', + // }, + { + title: 'gnomad-SV', + token: 'gnomad' + }, + { + title: 'DGV SVs', + token: 'dgv' + }, + { + title: 'DGV GS SVs', + token: 'dgv-gs' + }, + { + title: 'ExAC CNVs', + token: 'exac' + } +].map(({ title, token }) => { + return { + name: title, + sourceType: 'annotation', + format: 'bed', + visibilityWindow, + displayMode: 'SQUISHED', + url: `${API_BASE_URL}grch37/${token}.bed.gz`, + indexURL: `${API_BASE_URL}grch37/${token}.bed.gz.tbi`, + color: 'black' + } +}) +export const publicTracks = [ + duplicationTrack, + repeatsTrack, + altTrack, + fixTrack, + hescTadTrack, + curatedMmsTrack + // clinvarTrack, +].concat(bgDbTracks) + +export const genCaseTrack = (caseUuid: string) => ({ + order: -1, + height: '200', + name: 'Case SVs', + sourceType: 'custom', + visibilityWindow, + source: { + url: `/svs/ajax/fetch-variants/${caseUuid}/?chromosome=$CHR&start=$START&end=$END`, + // url: `https://varfish.bihealth.org/svs/ajax/fetch-variants/7a538a72-f8fb-4d71-a08b-6045f1e983dc/?chromosome=chr15&start=16989370.8&end=26828561.7`, + method: 'GET', + contentType: 'application/json', + mappings: { + chr: 'chromosome' + }, + queryable: true + }, + format: 'annotation', + colorBy: 'sv_type', + colorTable: { + DEL: 'red', + DUP: 'green', + INV: 'blue', + '*': 'black' + } +}) diff --git a/frontend/src/components/GenomeBrowser.vue b/frontend/src/components/GenomeBrowser.vue new file mode 100644 index 00000000..2cb4fbe2 --- /dev/null +++ b/frontend/src/components/GenomeBrowser.vue @@ -0,0 +1,104 @@ + + + diff --git a/frontend/src/components/SvDetails/SvDetailsGenotypeCall.vue b/frontend/src/components/SvDetails/SvDetailsGenotypeCall.vue index 23d26ed5..46bbf685 100644 --- a/frontend/src/components/SvDetails/SvDetailsGenotypeCall.vue +++ b/frontend/src/components/SvDetails/SvDetailsGenotypeCall.vue @@ -52,7 +52,7 @@ const allKeys: ComputedRef = computed(() => { Sample -