Skip to content

Commit

Permalink
feat: Integrate new GTEx and clinvar information as done for VarFish (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
gromdimon authored Sep 14, 2023
1 parent 83540c2 commit d836edb
Show file tree
Hide file tree
Showing 20 changed files with 2,329 additions and 446 deletions.
1,773 changes: 1,364 additions & 409 deletions frontend/package-lock.json

Large diffs are not rendered by default.

25 changes: 14 additions & 11 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,35 +17,38 @@
"@mdi/font": "^7.2.96",
"pinia": "^2.1.6",
"resize-observer-polyfill": "^1.5.1",
"vega": "^5.25.0",
"vega-embed": "^6.22.2",
"vue": "^3.3.4",
"vue-router": "^4.2.4",
"vuetify": "^3.3.14"
"vuetify": "^3.3.16"
},
"devDependencies": {
"@pinia/testing": "^0.1.3",
"@rushstack/eslint-patch": "^1.3.3",
"@tsconfig/node18": "^18.2.1",
"@tsconfig/node18": "^18.2.2",
"@types/jsdom": "^21.1.2",
"@types/node": "^20.5.6",
"@vitejs/plugin-vue": "^4.3.3",
"@types/node": "^20.6.0",
"@vitejs/plugin-vue": "^4.3.4",
"@vitejs/plugin-vue-jsx": "^3.0.2",
"@vitest/coverage-istanbul": "^0.34.3",
"@vitest/coverage-istanbul": "^0.34.4",
"@vue/eslint-config-prettier": "^8.0.0",
"@vue/eslint-config-typescript": "^11.0.3",
"@vue/test-utils": "^2.4.1",
"@vue/tsconfig": "^0.4.0",
"eslint": "^8.47.0",
"eslint": "^8.49.0",
"eslint-plugin-vue": "^9.17.0",
"jsdom": "^22.1.0",
"npm-check-updates": "^16.13.1",
"npm-check-updates": "^16.14.2",
"npm-run-all": "^4.1.5",
"prettier": "^3.0.2",
"typescript": "~5.2.2",
"vite": "^4.3.9",
"prettier": "^3.0.3",
"typescript": "^5.2.2",
"vite": "^4.4.9",
"vite-plugin-vuetify": "^1.0.2",
"vitest": "^0.32.4",
"vitest-canvas-mock": "^0.3.3",
"vitest-fetch-mock": "^0.2.2",
"vue-cli-plugin-vuetify": "~2.5.8",
"vue-tsc": "^1.6.5"
"vue-tsc": "^1.8.11"
}
}
21 changes: 21 additions & 0 deletions frontend/src/api/__tests__/annonars.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,27 @@ describe.concurrent('Annonars Client', () => {
expect(JSON.stringify(result)).toEqual(JSON.stringify({ status: 400 }))
})

it('fetches gene clinvar info correctly', async () => {
fetchMocker.mockResponseOnce(JSON.stringify(BRCA1geneInfo))

const client = new AnnonarsClient()
const result = await client.fetchGeneClinvarInfo('BRCA1')
expect(JSON.stringify(result)).toEqual(JSON.stringify(BRCA1geneInfo))
})

it('fails to fetch gene clinvar info with wrong HGNC id', async () => {
fetchMocker.mockResponse((req) => {
if (req.url.includes('hgnc_id=BRCA1')) {
return Promise.resolve(JSON.stringify(BRCA1geneInfo))
}
return Promise.resolve(JSON.stringify({ status: 400 }))
})

const client = new AnnonarsClient()
const result = await client.fetchGeneClinvarInfo('123')
expect(JSON.stringify(result)).toEqual(JSON.stringify({ status: 400 }))
})

it('fetches genes correctly', async () => {
fetchMocker.mockResponseOnce(JSON.stringify(EMPSearchInfo))

Expand Down
7 changes: 7 additions & 0 deletions frontend/src/api/annonars.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,13 @@ export class AnnonarsClient {
return await response.json()
}

async fetchGeneClinvarInfo(hgncId: string): Promise<any> {
const response = await fetch(`${this.apiBaseUrl}genes/clinvar?hgnc_id=${hgncId}`, {
method: 'GET'
})
return await response.json()
}

async fetchGenes(query: string): Promise<any> {
const response = await fetch(`${this.apiBaseUrl}genes/search?${query}`, {
method: 'GET'
Expand Down
3 changes: 3 additions & 0 deletions frontend/src/assets/__tests__/BRCA1ClinVar.json
Git LFS file not shown
4 changes: 2 additions & 2 deletions frontend/src/assets/__tests__/BRCA1GeneInfo.json
Git LFS file not shown
136 changes: 136 additions & 0 deletions frontend/src/components/ClinVarFreqPlot.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
<script setup lang="ts">
import { computed } from 'vue'
import VegaPlot from '@/components/VegaPlot.vue'
const coarseClinsigLabels = ['benign', 'uncertain', 'pathogenic']
const bucketLabels = [
'no frequency',
'<0.00001',
'<0.00025',
'<0.0005',
'<0.0001',
'<0.00025',
'<0.0005',
'<0.001',
'<0.0025',
'<0.005',
'<0.01',
'<0.025',
'<0.05',
'<0.1',
'<0.25',
'<0.5',
'<1.0'
]
export interface CountsRecord {
/** Coarse clinical significance ID */
coarse_clinsig: number
/** Counts per bucket */
counts: number[]
}
export interface Props {
/** Gene symbol */
geneSymbol: string
/** Expression records */
perFreqCounts: CountsRecord[]
}
const props = withDefaults(defineProps<Props>(), {})
const vegaData = computed(() => {
const values = []
for (const record of props?.perFreqCounts || []) {
for (let i = 0; i < record.counts.length; i++) {
if (record.counts[i] > 0) {
values.push({
coarseClinsig: coarseClinsigLabels[record.coarse_clinsig],
coarseClinsigNo: record.coarse_clinsig,
freqBucket: bucketLabels[i],
freqBucketNo: i,
value: record.counts[i]
})
}
}
}
if (values.length) {
return values
} else {
return null
}
})
const vegaLayer = [
{
mark: { type: 'bar', tooltip: true }
},
{
mark: {
type: 'text',
align: 'center',
baseline: 'middle',
dy: -10
},
encoding: {
text: { field: 'value', type: 'quantitative', fontSize: 8 }
}
}
]
const vegaEncoding = {
x: {
field: 'freqBucket',
title: 'population frequency',
type: 'nominal',
sort: bucketLabels,
axis: { labelAngle: 45 }
},
y: {
field: 'value',
scale: { type: 'log' },
title: 'variant count',
axis: {
grid: false,
tickExtra: false
}
},
xOffset: {
field: 'coarseClinsig',
type: 'nominal',
sort: coarseClinsigLabels
},
color: {
field: 'coarseClinsig',
title: 'clinical sig.',
type: 'nominal',
sort: coarseClinsigLabels,
scale: {
domain: coarseClinsigLabels,
range: ['#5d9936', '#f5c964', '#b05454']
}
}
}
/** Ref to the VegaPlot (for testing). */
// const vegaPlotRef = ref(null)
</script>

<template>
<figure class="figure border rounded pl-2 pt-2 mr-3 w-100 col">
<figcaption class="figure-caption text-center">
Population frequency of ClinVar variants
</figcaption>
<VegaPlot
:data-values="vegaData as any"
:encoding="vegaEncoding"
:mark="false"
:layer="vegaLayer"
:width="800"
:height="300"
renderer="svg"
/>
</figure>
</template>
Loading

0 comments on commit d836edb

Please sign in to comment.