Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@
"@lumino/widgets": "2.7.5",
"@mdi/js": "7.4.47",
"@vueuse/core": "14.1.0",
"apexcharts": "3.54.1",
"axios": "1.15.0",
"dedent": "1.7.2",
"echarts": "^6.0.0",
"enumify": "2.0.0",
"graphiql": "4.1.2",
"graphql": "16.13.2",
Expand All @@ -49,7 +49,6 @@
"vue-i18n": "11.1.12",
"vue-router": "5.0.6",
"vue-the-mask": "0.11.1",
"vue3-apexcharts": "1.8.0",
"vuetify": "3.11.8",
"vuex": "4.1.0"
},
Expand Down
225 changes: 128 additions & 97 deletions src/components/cylc/analysis/BoxPlot.vue
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</v-btn>
</div>
</Teleport>
<VueApexCharts
type="boxPlot"
:options="chartOptions"
:series="series"
:height="105 + series[0].data.length * 60"
width="95%"
class="d-flex justify-center"
/>
<div ref="chart" :style="{ height: `${100 + series[0].data.length * 50}px`, width: '100%' }" class="flex-grow-1" />
<v-pagination
v-model="page"
:length="numPages"
Expand All @@ -57,10 +50,15 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</template>

<script>
import { computed } from 'vue'
import VueApexCharts from 'vue3-apexcharts'
import * as echarts from 'echarts/core'
import { BoxplotChart } from 'echarts/charts'
import {
GridComponent,
TooltipComponent,
ToolboxComponent
} from 'echarts/components'
import { CanvasRenderer } from 'echarts/renderers'
import {
mdiDownload,
mdiSortReverseVariant,
mdiSortVariant,
} from '@mdi/js'
Expand All @@ -73,12 +71,18 @@ import {
useInitialOptions
} from '@/utils/initialOptions'

echarts.use([
BoxplotChart,
GridComponent,
TooltipComponent,
ToolboxComponent,
CanvasRenderer
])

export default {
name: 'BoxPlot',

components: {
VueApexCharts,
},
components: {},

emits: [updateInitialOptionsEvent],

Expand Down Expand Up @@ -128,89 +132,112 @@ export default {

const reducedAnimation = useReducedAnimation()

const chartOptions = computed(() => ({
chart: {
defaultLocale: 'en',
locales: [
{
name: 'en',
options: {
toolbar: {
exportToSVG: 'Download SVG',
exportToPNG: 'Download PNG',
menu: 'Download'
}
}
}
],
animations: {
enabled: reducedAnimation.value ? false : props.animate,
easing: 'easeinout',
speed: 300,
animateGradually: {
enabled: true,
delay: 150,
},
dynamicAnimation: {
enabled: true,
speed: 350,
},
},
fontFamily: 'inherit',
toolbar: {
tools: {
download: `<svg class="w-100 h-100"><path d="${mdiDownload}"></path></svg>`,
},
},
},
tooltip: {
custom ({ seriesIndex, dataPointIndex, w }) {
const max = formatDuration(w.globals.seriesCandleC[seriesIndex][dataPointIndex], { allowZeros: true })
const q3 = formatDuration(w.globals.seriesCandleL[seriesIndex][dataPointIndex], { allowZeros: true })
const med = formatDuration(w.globals.seriesCandleM[seriesIndex][dataPointIndex], { allowZeros: true })
const q1 = formatDuration(w.globals.seriesCandleH[seriesIndex][dataPointIndex], { allowZeros: true })
const min = formatDuration(w.globals.seriesCandleO[seriesIndex][dataPointIndex], { allowZeros: true })
return `
<div class="pa-2">
<div>Maximum: ${max}</div>
<div>Q3: ${q3} </div>
<div>Median: ${med}</div>
<div>Q1: ${q1}</div>
<div>Minimum: ${min}</div>
</div>
`
},
},
plotOptions: {
bar: {
horizontal: true,
},
boxPlot: {
colors: {
upper: '#6DD5C2',
lower: '#6AA4F1',
},
},
},
xaxis: {
title: {
text: `${upperFirst(props.timingOption)} time`,
},
labels: {
formatter: (value) => formatDuration(value, { allowZeros: true })
},
},
}))

return {
sortBy,
page,
sortDesc,
chartOptions,
reducedAnimation,
}
},

data () {
return {
chart: null
}
},

mounted () {
this.$nextTick(() => {
this.initChart()
})
this.resizeObserver = new ResizeObserver(() => {
this.chart?.resize()
this.updateChart()
})
this.resizeObserver.observe(this.$refs.chart)
window.addEventListener('resize', this.handleResize)
},

beforeUnmount () {
this.resizeObserver?.disconnect()
window.removeEventListener('resize', this.handleResize)
this.chart?.dispose()
},

watch: {
series: {
handler: 'updateChart',
deep: true
},
chartOptions: 'updateChart',
numPages () {
// Clamp page number
this.page = Math.min(this.numPages, this.page)
}
},

computed: {
chartOptions () {
return {
animation: !this.reducedAnimation && this.animate,
tooltip: {
trigger: 'item',
formatter: (params) => {
const [min, q1, med, q3, max] = params.value.slice(1)
return `
<div class="pa-2">
<div>Maximum: ${formatDuration(max, { allowZeros: true })}</div>
<div>Q3: ${formatDuration(q3, { allowZeros: true })}</div>
<div>Median: ${formatDuration(med, { allowZeros: true })}</div>
<div>Q1: ${formatDuration(q1, { allowZeros: true })}</div>
<div>Minimum: ${formatDuration(min, { allowZeros: true })}</div>
</div>
`
}
},
grid: {
left: '0%',
right: '5%',
top: '3%',
bottom: '12%',
containLabel: true
},
toolbox: {
feature: {
saveAsImage: { title: 'Download' }
}
},
xAxis: {
type: 'value',
name: `${upperFirst(this.timingOption)} time`,
nameLocation: 'middle',
nameGap: 30,
scale: true,
axisLabel: {
formatter: (value) => formatDuration(value, { allowZeros: true })
}
},
yAxis: {
type: 'category',
data: this.series[0].data.map(d => d.x),
axisLabel: {
interval: 0,
overflow: 'truncate',
width: 150,
}
},
series: [
{
type: 'boxplot',
data: this.series[0].data.map(d => d.y),
itemStyle: {
color: '#6AA4F1',
borderColor: '#6DD5C2'
}
}
]
}
},
series () {
const sortedTasks = [...this.tasks].sort(this.compare)
const startIndex = Math.max(0, this.itemsPerPage * (this.page - 1))
Expand Down Expand Up @@ -249,14 +276,18 @@ export default {
},
},

watch: {
numPages () {
// Clamp page number
this.page = Math.min(this.numPages, this.page)
}
},

methods: {
initChart () {
this.chart = echarts.init(this.$refs.chart)
this.updateChart()
},
updateChart () {
if (!this.chart) return
this.chart.setOption(this.chartOptions, true)
},
handleResize () {
this.chart?.resize()
},
/**
* @param {string|number} a
* @param {string|number} b
Expand All @@ -276,7 +307,7 @@ export default {
</script>

<style>
.apexcharts-text {
.echarts-text {
font-size: 0.9rem;
}
</style>
Loading