<template>
<div>
<div id="chart">
<apexchart
type="violin"
height="460"
:options="chartOptions"
:series="series"
></apexchart>
</div>
</div>
</template>
<script>
import VueApexCharts from 'vue-apexcharts'
// Build a Gaussian density profile + raw observations for a group.
// The sample template seeds Math.random, so this renders identically across reloads.
function gaussianViolin(mean, sd, n) {
var density = []
for (var v = mean - 3 * sd; v <= mean + 3 * sd; v += sd / 6) {
var z = (v - mean) / sd
density.push([Math.round(v * 10) / 10, Math.exp(-0.5 * z * z)])
}
var points = []
for (var k = 0; k < n; k++) {
// Box–Muller transform on two uniform samples
var u1 = Math.random(),
u2 = Math.random()
var g = Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2)
points.push(mean + g * sd)
}
return { density: density, points: points }
}
export default {
components: {
apexchart: VueApexCharts,
},
data: function () {
return {
series: [
{
name: 'Latency',
data: [
{ x: 'Auth', y: gaussianViolin(120, 18, 400) },
{ x: 'Search', y: gaussianViolin(210, 35, 500) },
{ x: 'Checkout', y: gaussianViolin(160, 22, 350) },
{ x: 'Recommend', y: gaussianViolin(260, 45, 300) },
],
},
],
chartOptions: {
chart: {
type: 'violin',
height: 460,
},
title: {
text: 'Response time distribution by service (ms)',
},
plotOptions: {
bar: {
horizontal: true,
distributed: true,
},
violin: {
normalize: 'group',
// dots in a darker shade of each violin's colour, no outline (strokeWidth: 0)
points: { show: true, size: 3, jitter: 0.9, strokeWidth: 0 },
},
},
colors: ['#14b8a6', '#6366f1', '#f59e0b', '#ef4444'],
stroke: { width: 1, colors: ['#888'] },
legend: { show: false },
xaxis: {
title: { text: 'Response time (ms)' },
},
},
}
},
}
</script>
<style>
#chart {
max-width: 760px;
margin: 20px auto;
}
</style>