// 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([v, 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 }
}

var options = {
  series: [
    {
      name: 'Measurement',
      data: [
        { x: 'Group A', y: gaussianViolin(50, 8, 400) },
        { x: 'Group B', y: gaussianViolin(62, 5, 600) },
        { x: 'Group C', y: gaussianViolin(45, 12, 250) },
        { x: 'Group D', y: gaussianViolin(55, 6, 500) },
        { x: 'Group E', y: gaussianViolin(48, 10, 350) },
        { x: 'Group F', y: gaussianViolin(58, 7, 450) },
        { x: 'Group G', y: gaussianViolin(52, 9, 300) },
      ],
    },
  ],
  chart: {
    type: 'violin',
    height: 420,
  },
  title: {
    text: 'Distribution by group',
  },
  plotOptions: {
    violin: {
      bandwidthScale: 1,
      points: {
        show: false, // density curve only — no jitter overlay
      },
    },
  },
}

var chart = new ApexCharts(document.querySelector('#chart'), options)
chart.render()
Basic Violin - JavaScript Violin Charts | ApexCharts.js | ApexCharts.js