Skip to content

Commit

Permalink
Merge pull request #1 from molgenis/feat/persons
Browse files Browse the repository at this point in the history
fix: trios
  • Loading branch information
bartcharbon authored Jun 8, 2020
2 parents f1a769e + 8f22996 commit 144e47c
Show file tree
Hide file tree
Showing 13 changed files with 284 additions and 71 deletions.
2 changes: 1 addition & 1 deletion public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title><%= htmlWebpackPlugin.options.title %></title>
<title>VCF Report</title>
<!-- blank embedded favicon -->
<link rel="icon" href="data:image/x-icon;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQEAYAAABPYyMiAAAABmJLR0T///////8JWPfcAAAACXBIWXMAAABIAAAASABGyWs+AAAAF0lEQVRIx2NgGAWjYBSMglEwCkbBSAcACBAAAeaR9cIAAAAASUVORK5CYII=" type="image/x-icon">
</head>
Expand Down
51 changes: 41 additions & 10 deletions src/App.vue
Original file line number Diff line number Diff line change
@@ -1,37 +1,68 @@
<template>
<div id="app">
<Header :samples="samples" :sample="sample" @change="sample = $event" />
<b-container fluid>
<b-alert v-if="reportRecords < totalRecords" show dismissible variant="warning">
{{ $t('variantWarning', [reportRecords, totalRecords]) }}
</b-alert>
<b-alert v-if="reportSamples < totalSamples" show dismissible variant="warning">
{{ $t('sampleWarning', [reportSamples, totalSamples]) }}
</b-alert>
<SampleNav/>
<Alerts v-if="nrAlerts > 0" class="mt-3" :report-records="reportRecords" :total-records="totalRecords" :report-samples="reportSamples" :total-samples="totalSamples"/>
<Report class="mt-3" :samples="samples" :sample="sample" :metadata="metadata" />
<Footer v-if="metadata" class="mt-3" :app="metadata.app" />
</b-container>
</div>
</template>

<script>
import SampleNav from "./components/SampleNav";
import Header from "./components/Header";
import Alerts from "./components/Alerts";
import Report from "./components/Report";
import Footer from "./components/Footer";
export default {
name: 'App',
components: {SampleNav},
components: {Header, Alerts, Report, Footer},
data: function () {
return {
metadata: null,
samples: null,
sample: null,
reportRecords: null,
totalRecords: null,
reportSamples: null,
totalSamples: null
}
},
computed: {
nrAlerts: function () {
let nrAlerts = 0
if(this.reportRecords < this.totalRecords) {
++nrAlerts
}
if(this.reportSamples < this.totalSamples) {
++nrAlerts
}
return nrAlerts
}
},
async created() {
this.metadata = await this.$api.getMeta()
const records = await this.$api.get('records', {size: 0})
this.reportRecords = records.page.totalElements
this.totalRecords = records.total
const samples = await this.$api.get('samples', {size: 0})
const samples = await this.$api.get('samples')
let sampleIndex = {}
samples.items.forEach(sample => {
sampleIndex[sample.person.individualId] = sample.index
})
this.samples = samples.items.filter(sample => sample.index !== -1).map(sample => ({
...sample.person, ...{
individual_idx: sampleIndex[sample.person.individualId],
paternal_idx: sampleIndex[sample.person.paternalId],
maternal_idx: sampleIndex[sample.person.maternalId]
}
}))
this.sample = this.samples.length > 0 ? this.samples[0] : null
this.reportSamples = samples.page.totalElements
this.totalSamples = samples.total
}
Expand Down
22 changes: 22 additions & 0 deletions src/components/Alerts.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<template>
<div>
<b-alert v-if="reportRecords < totalRecords" show dismissible variant="warning">
{{ $t('variantWarning', [reportRecords, totalRecords]) }}
</b-alert>
<b-alert v-if="reportSamples < totalSamples" show dismissible variant="warning">
{{ $t('sampleWarning', [reportSamples, totalSamples]) }}
</b-alert>
</div>
</template>

<script>
export default {
name: 'Alerts',
props: {
reportRecords: Number,
totalRecords: Number,
reportSamples: Number,
totalSamples: Number
},
}
</script>
16 changes: 16 additions & 0 deletions src/components/Footer.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<template>
<b-row class="text-center">
<b-col>
<span class="text-muted">{{ $t('footer', [app.name, app.version, app.args]) }}</span>
</b-col>
</b-row>
</template>

<script>
export default {
name: 'Footer',
props: {
app: Object
}
}
</script>
21 changes: 21 additions & 0 deletions src/components/Header.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<template>
<b-navbar type="light" variant="light">
<b-navbar-brand href="#">{{ $t('brand') }}</b-navbar-brand>
<b-nav-form v-if="samples && samples.length > 1">
<SampleSelect :samples="samples" :sample="sample" @change="$emit('change', $event)"/>
</b-nav-form>
</b-navbar>
</template>

<script>
import SampleSelect from "./SampleSelect";
export default {
name: 'Header',
components: {SampleSelect},
props: {
samples: Array,
sample: Object
}
}
</script>
59 changes: 47 additions & 12 deletions src/components/RecordTable.vue
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,17 @@
:current-page="page.currentPage"
:per-page="page.perPage"
:empty-text="$t('emptyTableMessage')"
:key="sample"
:key="sample.familyId + sample.individualId"
>
<template v-slot:head()="data">
{{ $t(data.label) }}
</template>
<template v-slot:cell(pos)="data">
{{ data.item.c + ':' + data.item.p }}
<a v-if="genomeBrowserDb" :href="'https://genome-euro.ucsc.edu/cgi-bin/hgTracks?db=' + encodeURIComponent(genomeBrowserDb) + '&position=' + encodeURIComponent('chr' + data.item.c + ':' + Math.max(0, (data.item.p - 500)) + '-' + (data.item.p + 500))" target="_blank">
{{ data.item.c + ':' + numberWithCommas(data.item.p) }}
<b-icon-box-arrow-in-up-right class="ml-1" />
</a>
<span v-else>{{ data.item.c + ':' + numberWithCommas(data.item.p) }}</span>
</template>
<template v-slot:cell(id)="data">
<span v-for="(id, index) in data.item.i" :key="id">
Expand All @@ -65,24 +69,24 @@
</span>
</template>
<template v-slot:cell(sample)="data">
<span v-for="(alt, index) in data.item.s[sample.id].gt.a" :key="index">
<span v-for="(alt, index) in data.item.s[sample.individual_idx].gt.a" :key="index">
<span v-for="(nuc, index) in alt.split('')" :key="index"
:class="{'nuc': true, 'nuc-a': nuc === 'A', 'nuc-c': nuc === 'C', 'nuc-t': nuc === 'T', 'nuc-g': nuc === 'G'}">{{ nuc }}</span>
<span v-if="index < data.item.s[sample.id].gt.a.length - 1"> {{ data.item.s[sample.id].gt.p ? '|' : '/'}} </span>
<span v-if="index < data.item.s[sample.individual_idx].gt.a.length - 1"> {{ data.item.s[sample.individual_idx].gt.p ? '|' : '/'}} </span>
</span>
</template>
<template v-slot:cell(father)="data">
<span v-for="(alt, index) in data.item.s[sample.father].gt.a" :key="index">
<span v-for="(alt, index) in data.item.s[sample.paternal_idx].gt.a" :key="index">
<span v-for="(nuc, index) in alt.split('')" :key="index"
:class="{'nuc': true, 'nuc-a': nuc === 'A', 'nuc-c': nuc === 'C', 'nuc-t': nuc === 'T', 'nuc-g': nuc === 'G'}">{{ nuc }}</span>
<span v-if="index < data.item.s[sample.father].gt.a.length - 1"> {{ data.item.s[sample.father].gt.p ? '|' : '/'}} </span>
<span v-if="index < data.item.s[sample.paternal_idx].gt.a.length - 1"> {{ data.item.s[sample.paternal_idx].gt.p ? '|' : '/'}} </span>
</span>
</template>
<template v-slot:cell(mother)="data">
<span v-for="(alt, index) in data.item.s[sample.mother].gt.a" :key="index">
<span v-for="(alt, index) in data.item.s[sample.maternal_idx].gt.a" :key="index">
<span v-for="(nuc, index) in alt.split('')" :key="index"
:class="{'nuc': true, 'nuc-a': nuc === 'A', 'nuc-c': nuc === 'C', 'nuc-t': nuc === 'T', 'nuc-g': nuc === 'G'}">{{ nuc }}</span>
<span v-if="index < data.item.s[sample.mother].gt.a.length - 1"> {{ data.item.s[sample.mother].gt.p ? '|' : '/'}} </span>
<span v-if="index < data.item.s[sample.maternal_idx].gt.a.length - 1"> {{ data.item.s[sample.maternal_idx].gt.p ? '|' : '/'}} </span>
</span>
</template>
<template v-slot:cell(qual)="data">
Expand All @@ -109,6 +113,7 @@
export default {
name: 'RecordTable',
props: {
genomeAssembly: String,
sample: Object
},
data: function () {
Expand All @@ -119,7 +124,7 @@
sortDesc: false,
page: {
currentPage: 1,
perPage: 200
perPage: 20
}
}
},
Expand All @@ -130,10 +135,35 @@
{key: 'id', label: 'id'},
{key: 'ref', label: 'ref'},
this.sample ? {key: 'sample', label: 'sample'} : {key: 'alt', label: 'alt'},
this.sample && this.sample.father ? {key: 'father', label: 'father'} : null,
this.sample && this.sample.mother ? {key: 'mother', label: 'mother'} : null,
this.sample && this.sample.paternalId !== '0' ? {key: 'father', label: 'father'} : null,
this.sample && this.sample.maternalId !== '0' ? {key: 'mother', label: 'mother'} : null,
{key: 'qual', label: 'qual', sortable: true},
{key: 'filter', label: 'filter'}]
},
genomeBrowserDb: function () {
let genomeBrowserDb
switch (this.genomeAssembly) {
case 'NCBI34':
genomeBrowserDb = 'hg16'
break
case 'NCBI35':
genomeBrowserDb = 'hg17'
break
case 'NCBI36':
genomeBrowserDb = 'hg18'
break
case 'GRCh37':
genomeBrowserDb = 'hg19'
break
case 'GRCh38':
genomeBrowserDb = 'hg38'
break
case 'UNKNOWN':
default:
genomeBrowserDb = null
break
}
return genomeBrowserDb
}
},
methods: {
Expand All @@ -146,7 +176,7 @@
}
if (this.sample) {
params.query = {
selector: ['s', this.sample.id, 'gt', 't'],
selector: ['s', this.sample.individual_idx, 'gt', 't'],
operator: '!in',
args: ['hom_r', 'miss']
}
Expand All @@ -160,6 +190,11 @@
clearSearch() {
this.filter = ''
this.$refs.search.focus()
},
numberWithCommas(x) {
let parts = x.toString().split(".");
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
return parts.join(".");
}
},
watch: {
Expand Down
29 changes: 29 additions & 0 deletions src/components/Report.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<template>
<div v-if="samples">
<b-row v-if="sample">
<b-col>
<SampleInfo :sample="sample"/>
</b-col>
</b-row>
<b-row v-if="sample">
<b-col>
<RecordTable :sample="sample" :genome-assembly="metadata.htsFile.genomeAssembly" />
</b-col>
</b-row>
</div>
</template>

<script>
import RecordTable from "./RecordTable";
import SampleInfo from "./SampleInfo";
export default {
name: 'Report',
components: {SampleInfo, RecordTable},
props: {
metadata: Object,
samples: Array,
sample: Object
}
}
</script>
50 changes: 50 additions & 0 deletions src/components/SampleInfo.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<template>
<div>
<b-row v-if="phenotype && phenotype.phenotypicFeaturesList.length > 0">
<b-col cols="1">
<span>{{ $tc('phenotype', 2) }}:</span>
</b-col>
<b-col>
<SamplePheno :phenotype="phenotype"/>
</b-col>
</b-row>
</div>
</template>

<script>
import SamplePheno from "./SamplePheno";
export default {
name: 'SampleInfo',
components: {SamplePheno},
props: {
sample: Object
},
data: function () {
return {
phenotype: null,
}
},
methods: {
loadPhenotypes: async function () {
const params = {
query: {
selector: ['subject', 'id'],
operator: '==',
args: this.sample.individualId
}
}
const phenotypes = await this.$api.get('phenotypes', params)
this.phenotype = phenotypes.items.length > 0 ? phenotypes.items[0] : null
}
},
mounted() {
this.loadPhenotypes(this.sample)
},
watch: {
sample: function (sample) {
this.loadPhenotypes(sample)
}
}
}
</script>
Loading

0 comments on commit 144e47c

Please sign in to comment.