Skip to content
Snippets Groups Projects
rloopr-results.vue 10.8 KiB
Newer Older
<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>

    <div v-show="rloopList">
      <heatchart
        v-if="heatmapData"
        :data="heatmapData"
        y-axis-title="Count (R-loop)"
        @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 results</th>
            <th class="text-center">Export</th>
            <th v-if="sequence">Sequence info</th>
          </tr>
          <tr>
            <td>
              Rloops found: {{ analysisInfo.resultCount | number(0) }}
              <br />
              <span v-if="sequence">
                (Overall R-loop length / Sequence length) for <em>RIZ 3G cluster (m1)</em>:
                <b>{{ ((totalRloopLenM1 / sequence.length) * 100) | number(2) }} %</b>
              </span>
              <br />
              <span v-if="sequence">
                (Overall R-loop length / Sequence length) for <em>RIZ 4G cluster (m2)</em>:
                <b>{{ ((totalRloopLenM2 / sequence.length) * 100) | number(2) }} %</b>
              </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>

      <pagination ref="pagination" @pageChange="reload" :page-size="10">
        <table class="table table-striped table-hover">
          <tbody>
            <tr>
              <th>
                <sort-toggle @sort="sortSequences" crit="position" :current="currentSort">Position</sort-toggle>
              </th>
              <th>
                <sort-toggle @sort="sortSequences" crit="length" :current="currentSort">Length</sort-toggle>
              </th>
              <th>
                Model
              </th>
              <th>
                <sort-toggle @sort="sortSequences" crit="strand" :current="currentSort">Strand</sort-toggle>
              </th>
              <th>RIZ</th>
              <th>
                <sort-toggle @sort="sortSequences" crit="rizGRichness" :current="currentSort">
                  RIZ Guanine richness
                </sort-toggle>
              </th>
              <th>linker</th>
              <th>REZ</th>
              <th>
                <sort-toggle @sort="sortSequences" crit="rloopGRichness" :current="currentSort">
                  R-loop Guanine richness
                </sort-toggle>
              </th>
              <th>
                <sort-toggle @sort="sortSequences" crit="g3" :current="currentSort">3G clusters</sort-toggle>
              </th>
              <th>
                <sort-toggle @sort="sortSequences" crit="g4" :current="currentSort">4G clusters</sort-toggle>
              </th>
              <th>
                <sort-toggle @sort="sortSequences" crit="gn" :current="currentSort">
                  5G clusters and larger
                </sort-toggle>
              </th>
            </tr>
            <template v-for="rloop in rloopList">
              <tr>
                <td>
                  {{ rloop.position | number(0) }}
                </td>
                <td>
                  {{ rloop.length }}
                </td>
                <td>
                  {{ rloop.model }}
                </td>
                <td>
                  {{ rloop.strand }}
                </td>
                <td class="sequence text-monospace text-bold">
                  <highlight :sequence="rloop.riz"></highlight>
                </td>
                <td class="sequence text-monospace">{{ (rloop.rizGRichness * 100) | number(2) }} %</td>
                <td class="sequence text-monospace">
                  {{ rloop.linker.length | number(0) }}
                </td>
                <td class="text-center">
                  <span class="toggle fa fa-search" @click="toggleDetails(rloop)" title="Toggle details"></span>
                </td>
                <td class="sequence text-monospace">{{ (rloop.rloopGRichness * 100) | number(2) }} %</td>
                <td class="sequence text-monospace">
                  {{ rloop.g3cnt | number(0) }}
                </td>
                <td class="sequence text-monospace">
                  {{ rloop.g4cnt | number(0) }}
                </td>
                <td class="sequence text-monospace">
                  {{ rloop.gncnt | number(0) }}
                </td>
              </tr>
              <tr v-if="rloop.ui.showRez">
                <td colspan="8" class="details">
                  <div class="row">
                    <div class="col-10">
                      REZ sequence:
                      <br />
                      <highlight class="sequence text-monospace text-bold" :sequence="rloop.rez"></highlight>
                    </div>
                    <div class="col-2">
                      <button class="btn btn-primary btn-block btn-sm" @click="toggleDetails(rloop)">
                        Close
                      </button>
                    </div>
                  </div>
                </td>
              </tr>
            </template>
          </tbody>
        </table>
      </pagination>

      <div v-show="rloopList && rloopList.length == 0">
        <p class="alert alert-warning">
          No R-loops 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,
      rloopList: null,
      avgRloopLen: null,
      totalRloopLenM1: null,
      totalRloopLenM2: 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/rloopr/' + this.analysisInfo.id + '/rloops', {
          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, 'showRez', false)
          this.rloopList = response.data.items
          this.countNucleic()
        })
    },
    toggleDetails(rloop) {
      rloop.ui.showRez = !rloop.ui.showRez
    },
    getAvgRizLen() {
      return this.$http.get('analyse/rloopr/' + this.analysisInfo.id + '/average/length').then(response => {
        this.avgRloopLen = response.data
      })
    },
    getTotalRloopLenM1() {
      return this.$http.get('analyse/rloopr/' + this.analysisInfo.id + '/total/length/m1').then(response => {
        this.totalRloopLenM1 = response.data
      })
    },
    getTotalRloopLenM2() {
      return this.$http.get('analyse/rloopr/' + this.analysisInfo.id + '/total/length/m2').then(response => {
        this.totalRloopLenM2 = 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/rloopr/${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/rloopr/${this.analysisInfo.id}/rloopr.csv`
    },
    downloadBED() {
      return `${this.$http.defaults.baseURL}analyse/rloopr/${this.analysisInfo.id}/rloopr.bedgraph`
    },
  },
  mounted() {
    this.reload()
    this.getTotalRloopLenM1()
    this.getTotalRloopLenM2()
    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>