Skip to content

Commit

Permalink
- ADD: Added trait view heatmap in addition to radar chart and bubble…
Browse files Browse the repository at this point in the history
… chart.
  • Loading branch information
sebastian-raubach committed Jan 16, 2025
1 parent 2cc6354 commit 8ac1856
Show file tree
Hide file tree
Showing 3 changed files with 196 additions and 8 deletions.
170 changes: 170 additions & 0 deletions src/components/charts/HeatmapChart.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
<template>
<div v-if="plotData && plotData.length > 0">
<BaseChart :id="id" :width="() => 1280" :height="() => height" chartType="plotly" :filename="baseFilename" v-on:resize="update" :supportsPngDownload="true" :supportsSvgDownload="true" v-on:force-redraw="update">
<div slot="chart" ref="chart" />
</BaseChart>
</div>
</template>

<script>
import { mapGetters } from 'vuex'
import BaseChart from '@/components/charts/BaseChart'
import { uuidv4 } from '@/mixins/util'
const Plotly = require('plotly.js/lib/core')
// Only register the chart types we're actually using to reduce the final bundle size
Plotly.register([
require('plotly.js/lib/heatmap')
])
export default {
props: {
plotData: {
type: Array,
default: () => []
},
stats: {
type: Array,
default: () => []
},
baseFilename: {
type: String,
default: 'heatmap-chart'
},
customRange: {
type: Array,
default: () => null
}
},
data: function () {
const id = 'chart-' + uuidv4()
return {
id: id,
isUpdating: false,
height: 600
}
},
computed: {
...mapGetters([
'storeDarkMode'
])
},
watch: {
plotData: {
deep: true,
handler: function () {
this.update()
}
},
stats: function () {
this.update()
}
},
components: {
BaseChart
},
methods: {
update: function () {
if (this.isUpdating) {
return
}
this.isUpdating = true
this.$nextTick(() => {
if (!this.plotData || this.plotData.length < 1) {
return
}
const div = this.$refs.chart
try {
// Plotly.purge(div)
} catch (e) {
// Nothing
}
const data = []
this.height = Math.max(500, this.plotData.length * 175)
const z = []
const customdata = []
const y = this.plotData.map(pd => pd.displayName)
this.plotData.forEach(pd => {
z.push(pd.values)
customdata.push(pd.customdata)
})
if (this.stats && this.stats.length > 0) {
this.stats.forEach(st => {
z.push(st.values)
y.unshift(st.displayName)
customdata.unshift(st.values.map(_ => ''))
})
}
data.push({
z: z,
y: y,
x: this.plotData[0].dims,
type: 'heatmap',
colorscale: 'Viridis',
customdata: customdata,
name: '',
hovertemplate: '%{y}<br>%{customdata}'
})
console.log(name)
if (this.customRange) {
data[0].zauto = false
data[0].zmin = this.customRange[0]
data[0].zmax = this.customRange[1]
}
const layout = {
paper_bgcolor: 'transparent',
plot_bgcolor: 'transparent',
height: this.height,
showlegend: data.length > 1,
xaxis: {
title: { text: null, font: { color: this.storeDarkMode ? 'white' : 'black' } },
tickfont: { color: this.storeDarkMode ? 'white' : 'black' }
},
yaxis: {
showticklabels: false,
title: { text: null, font: { color: this.storeDarkMode ? 'white' : 'black' } },
tickfont: { color: this.storeDarkMode ? 'white' : 'black' }
},
legend: {
bgcolor: 'rgba(0,0,0,0)',
orientation: 'h',
font: { color: this.storeDarkMode ? 'white' : 'black' },
x: 0,
y: 1.1
}
}
const config = {
modeBarButtonsToRemove: ['toImage'],
displayModeBar: true,
responsive: true,
displaylogo: false
}
Plotly.react(div, data, layout, config)
this.isUpdating = false
})
}
},
mounted: function () {
this.update()
}
}
</script>

<style>
</style>
13 changes: 11 additions & 2 deletions src/components/export/TraitRadarChartSelection.vue
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,14 @@
<b-col class="mb-3" :cols="radarCols.cols" :md="radarCols.md" :lg="radarCols.lg" v-for="(data, index) in radarChartDataArray" :key="`radar-chart-data-${index}`">
<h3 v-if="individualCharts">{{ data[0].displayName }}</h3>
<RadarChart :baseFilename="`radar-chart-${datasetIds.join(',')}`" :plotData="data" :stats="plotDataStats" @rotated="e => updateRotation(index, e)" :ref="`radar-chart-${index}`" />
<BalloonChart :baseFilename="`balloon-chart-${datasetIds.join(',')}`" :plotData="data" :stats="plotDataStats" :ref="`radar-chart-${index}`" />
<b-row>
<b-col cols="12" lg="6">
<BalloonChart :baseFilename="`balloon-chart-${datasetIds.join(',')}`" :plotData="data" :stats="plotDataStats" :ref="`baloon-chart-${index}`" />
</b-col>
<b-col cols="12" lg="6">
<HeatmapChart :baseFilename="`balloon-chart-${datasetIds.join(',')}`" :plotData="data" :stats="plotDataStats" :custom-range="[0, 100]" :ref="`heatmap-chart-${index}`" />
</b-col>
</b-row>
</b-col>
</template>
</b-row>
Expand All @@ -47,6 +54,7 @@
import MdiIcon from '@/components/icons/MdiIcon'
import RadarChart from '@/components/charts/RadarChart'
import BalloonChart from '@/components/charts/BalloonChart'
import HeatmapChart from '@/components/charts/HeatmapChart'
import SearchableSelect from '@/components/util/SearchableSelect'
import TrialGermplasmLookup from '@/components/util/TrialGermplasmLookup'
import { apiPostTraitDatasetStats, apiPostTrialsDataTable } from '@/mixins/api/trait'
Expand Down Expand Up @@ -269,7 +277,8 @@ export default {
SearchableSelect,
TrialGermplasmLookup,
RadarChart,
BalloonChart
BalloonChart,
HeatmapChart
},
methods: {
updateRotation: function (indexToSkip, rotation) {
Expand Down
21 changes: 15 additions & 6 deletions src/components/images/ImageNode.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,19 @@
<MdiIcon :path="mdiDelete" />
</b-button>
<b-card-body class="card-image-details">
<b-input-group v-if="storeToken && storeToken.userType && userIsAtLeast(storeToken.userType, USER_TYPE_DATA_CURATOR)" class="mb-2">
<b-textarea rows="3" max-rows="10" class="image-description" v-model="image.imageDescription"/>
<b-input-group-append>
<b-button variant="success" @click="updateImageDescription"><MdiIcon :path="mdiContentSave" /></b-button>
</b-input-group-append>
</b-input-group>
<div v-if="storeToken && storeToken.userType && userIsAtLeast(storeToken.userType, USER_TYPE_DATA_CURATOR)" class="mb-2">
<b-form @submit.prevent>
<b-input-group>
<b-textarea rows="3" max-rows="10" class="image-description" v-model="image.imageDescription"/>
<b-input-group-append>
<b-button variant="success" @click="updateImageDescription"><MdiIcon :path="mdiContentSave" /></b-button>
</b-input-group-append>
</b-input-group>
<b-form-checkbox v-model="image.imageIsReference" @change="updateImageIsReference">{{ $t('tableColumnImageIsReference') }}</b-form-checkbox>
</b-form>
</div>
<div class="mb-2" v-else>{{ image.imageDescription }}</div>
<b-badge variant="info" v-if="image.imageIsReference">{{ $t('tableColumnImageIsReference') }}</b-badge>
<div class="text-muted mb-2" v-if="image.createdOn"><MdiIcon :path="mdiCalendarClock" /> {{ new Date(image.createdOn).toLocaleString() }}</div>
<div class="mb-2" v-if="hasExif">
<b-button @click="$refs.imageExifModal.show()"><MdiIcon :path="mdiImageText" /> {{ $t('buttonShowExif') }}</b-button>
Expand Down Expand Up @@ -114,6 +120,9 @@ export default {
updateImageDescription: function () {
apiPatchImage(this.image)
},
updateImageIsReference: function () {
apiPatchImage(this.image)
},
getSrc: function (size) {
return getImageUrl(this.image.imagePath, {
name: this.image.imagePath,
Expand Down

0 comments on commit 8ac1856

Please sign in to comment.