<template> <div> <h2 v-if="sequence"> {{ sequence.name }} <span v-if="sequence.name !== analysisInfo.title">: {{ analysisInfo.title }}</span> <!-- slot for back button --> <slot></slot> </h2> <!-- overview --> <div v-show="zdnaList"> <heatchart v-if="heatmapData" :data="heatmapData" y-axis-title="Count (Z-DNA)" @dataPointClick="showSegment" @onZoom="zoomHeatchart" ></heatchart> <heatmap v-if="heatmapData" :data="heatmapData" @segmentClick="showSegment" :selected="selectedSegment"> </heatmap> <table class="table table-striped table-hover"> <tbody> <tr> <th>Analysis settings</th> <th>Analysis results</th> <th class="text-center">Export</th> <th v-if="sequence">Sequence info</th> </tr> <tr> <td> Minimal window size: {{ analysisInfo.minWindowSize | number(0) }} <br /> Minimal GC percentage: {{ analysisInfo.minGcPercentage }} <br /> Minimal observed/expected CpG: {{ analysisInfo.minObservedToExpectedCpG }} <br /> Minimal island merge gap: {{ analysisInfo.minIslandMergeGap }} <br /> First nucleotide: {{ analysisInfo.firstNucleotide }} <br /> Second nucleotide: {{ analysisInfo.secondNucleotide }} </td> <td> Islands found: {{ analysisInfo.resultCount | number(0) }} <br /> <span v-if="sequence">Frequency: {{ (analysisInfo.resultCount / sequence.length) * 1000 | number(3) }} / 1000 bp</span> </td> <td class="text-center"> <a v-if="downloadToken" :href="downloadCSV()" class="btn btn-primary btn-sm"> <span class="fa fa-cube"></span> CSV </a> <a v-if="downloadToken" :href="downloadBED()" class="btn btn-primary btn-sm"> <span class="fa fa-bed"></span> BedGraph </a> </td> <td v-if="sequence"> {{ sequence.name }} <br /> {{ sequence.length | number(0) }} bp <br /> GC: {{ GCCount }} ({{ GCRate | number(1) }}%) </td> </tr> </tbody> </table> <!-- list of results --> <pagination ref="pagination" @pageChange="reload" :page-size="10"> <table class="table table-striped table-hover"> <tbody> <tr> <th> <sort-toggle @sort="sortSequences" crit="start" :current="currentSort">Start</sort-toggle> </th> <th> <sort-toggle @sort="sortSequences" crit="end" :current="currentSort">End</sort-toggle> </th> <th>Sequence</th> <th> <sort-toggle @sort="sortSequences" crit="gcPerc" :current="currentSort"> GC Percentage </sort-toggle> </th> <th> <sort-toggle @sort="sortSequences" crit="observedToExpectedCpG" :current="currentSort"> Observer/expected CpG </sort-toggle> </th> <th class="text-center"> <sort-toggle @sort="sortSequences" crit="length" :current="currentSort">Length</sort-toggle> </th> </tr> <template v-for="zdna in zdnaList"> <tr> <td> {{ zdna.position | number(0) }} </td> <td> {{ zdna.end }} </td> <td class="sequence text-monospace text-bold"> <highlight :sequence="zdna.sequence.slice(0, 20)+'...'"></highlight> </td> <td class="sequence text-monospace">{{ zdna.gcPerc | number(3) }}</td> <td class="sequence text-monospace">{{ zdna.observedToExpectedCpG | number(3) }}</td> <td class="text-right"> {{ zdna.length | number }} </td> </tr> </template> </tbody> </table> </pagination> <div v-show="zdnaList && zdnaList.length === 0"> <p class="alert alert-warning"> No CpG islands found. </p> </div> </div> </div> </template> <script> import Formatters from '@/formatters' import SortToggle from '@/components/core/sort-toggle' import Pagination from '@/components/core/pagination' import SequenceStats from '@/components/sequence/helpers/sequence-stats' import Helpers from '@/helpers' import Heatchart from '@/components/core/visualisation/heatchart' import Heatmap from '@/components/core/visualisation/heatmap' import Highlight from '@/components/core/visualisation/highlight' /** * list of results for sequence analysis */ export default { props: ['analysisInfo', 'downloadToken'], data() { return { sequence: null, zdnaList: null, avgZdnaLen: null, totalZdnaLenM1: null, totalZdnaLenM2: null, heatmapData: null, selectedSegment: undefined, sequenceStart: undefined, sequenceLength: undefined, currentSort: { crit: 'position', asc: true, }, } }, methods: { getSequenceInfo() { return this.$http.get('sequence/' + this.analysisInfo.sequenceId).then(response => { this.sequence = response.data.payload }) }, countNucleic() { this.$http.patch('sequence/' + this.analysisInfo.sequenceId + '/nucleic-counts').catch(err => { this.httpError = err }) }, reload() { return this.$http .get('analyse/cpg/' + this.analysisInfo.id + '/cpg', { params: { sort: this.currentSort.crit, order: this.currentSort.asc ? 'ASC' : 'DESC', sequenceStart: this.sequenceStart, sequenceLength: this.sequenceLength, pageSize: this.$refs.pagination.getPageSize(), pageNumber: this.$refs.pagination.getPageCurrent() - 1, }, }) .then(response => { this.$refs.pagination.setPageCount(response.data.page.totalElements) Helpers.setUIState(response.data.items, 'showDetails', false) this.zdnaList = response.data.items this.countNucleic() }) }, toggleDetails(zdna) { zdna.ui.showDetails = !zdna.ui.showDetails }, getAvgRizLen() { return this.$http.get('analyse/cpg/' + this.analysisInfo.id + '/average/length').then(response => { this.avgZdnaLen = response.data }) }, sortSequences(info) { this.currentSort = info this.reload() }, async downloadHeatmap() { const total = this.sequence.length const { sequenceFrom: from = 0, sequenceTo: to = total, analysisInfo } = this const segments = 80 const { data } = await this.$http.get(`analyse/cpg/${analysisInfo.id}/heatmap`, { params: { segments, from, to }, }) this.heatmapData = { ...data, from, to, total } }, /** * click in heatmap * * @param seg */ showSegment(pos, size) { if (this.selectedSegment === pos) { this.selectedSegment = undefined this.sequenceStart = undefined this.sequenceLength = undefined } else { this.selectedSegment = pos this.sequenceStart = Math.floor(pos * size) this.sequenceLength = Math.ceil(size) } this.reload() }, async zoomHeatchart(from, to, onSuccess) { this.sequenceFrom = from this.sequenceTo = to await this.downloadHeatmap() onSuccess() }, downloadCSV() { return `${this.$http.defaults.baseURL}analyse/cpg/${this.analysisInfo.id}/cpg.csv` }, downloadBED() { return `${this.$http.defaults.baseURL}analyse/cpg/${this.analysisInfo.id}/cpg.bedgraph` }, }, mounted() { this.reload() this.getSequenceInfo().then(() => { this.getAvgRizLen().then(() => { this.downloadHeatmap() }) }) }, computed: { GCCount() { return SequenceStats.calcGCCount(this.sequence) }, GCRate() { return SequenceStats.calcGCRate(this.sequence) }, }, components: { highlight: Highlight, 'sort-toggle': SortToggle, pagination: Pagination, heatmap: Heatmap, heatchart: Heatchart, }, filters: { number: Formatters.number, genePos: Formatters.genePos, }, } </script> <style scoped> td, th { padding: 0.5rem; } td.sequence { max-width: 400px; } td.details { max-width: 600px; } td.details .feature { border: 1px solid red; } td .toggle { cursor: pointer; } </style>