{"spec_id":"density-basic","library":"chartjs","language":"javascript","code":"// anyplot.ai\n// density-basic: Basic Density Plot\n// Library: chartjs 4.4.7 | JavaScript 22.23.2\n// Quality: 90/100 | Created: 2026-08-24\n\nconst t = window.ANYPLOT_TOKENS;\n\n// --- Deterministic PRNG (mulberry32) ----------------------------------------\nfunction mulberry32(seed) {\n  return function () {\n    seed |= 0;\n    seed = (seed + 0x6d2b79f5) | 0;\n    let x = Math.imul(seed ^ (seed >>> 15), 1 | seed);\n    x = (x + Math.imul(x ^ (x >>> 7), 61 | x)) ^ x;\n    return ((x ^ (x >>> 14)) >>> 0) / 4294967296;\n  };\n}\nconst rand = mulberry32(42);\n\nfunction randomNormal() {\n  const u1 = Math.max(rand(), 1e-9);\n  const u2 = rand();\n  return Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2);\n}\n\n// --- Data: daily commute times (minutes), right-skewed ----------------------\nconst n = 400;\nconst commuteMinutes = [];\nfor (let i = 0; i < n; i++) {\n  const minutes = Math.exp(3.1 + 0.35 * randomNormal());\n  commuteMinutes.push(Math.max(4, minutes));\n}\n\n// --- Kernel density estimate (Gaussian kernel, Silverman bandwidth) --------\nconst mean = commuteMinutes.reduce((a, b) => a + b, 0) / n;\nconst variance =\n  commuteMinutes.reduce((a, b) => a + (b - mean) ** 2, 0) / (n - 1);\nconst std = Math.sqrt(variance);\nconst bandwidth = 1.06 * std * Math.pow(n, -1 / 5);\n\nconst dataMin = Math.min(...commuteMinutes);\nconst dataMax = Math.max(...commuteMinutes);\nconst pad = (dataMax - dataMin) * 0.15;\nconst gridStart = Math.max(0, Math.floor((dataMin - pad) / 5) * 5);\nconst gridEnd = Math.ceil((dataMax + pad) / 5) * 5;\nconst gridSize = 200;\n\nfunction gaussianKernel(u) {\n  return Math.exp(-0.5 * u * u) / Math.sqrt(2 * Math.PI);\n}\n\nconst densityPoints = [];\nfor (let i = 0; i <= gridSize; i++) {\n  const x = gridStart + ((gridEnd - gridStart) * i) / gridSize;\n  let sum = 0;\n  for (let j = 0; j < n; j++) {\n    sum += gaussianKernel((x - commuteMinutes[j]) / bandwidth);\n  }\n  densityPoints.push({ x, y: sum / (n * bandwidth) });\n}\n\nconst maxDensity = Math.max(...densityPoints.map((p) => p.y));\n\n// --- Rug plot: individual observations along the baseline -------------------\nconst rugY = -0.07 * maxDensity;\nconst rugPoints = commuteMinutes.map((minutes) => ({ x: minutes, y: rugY }));\n\n// --- Fill color (Imprint brand green at low alpha) --------------------------\nfunction hexToRgba(hex, alpha) {\n  const r = parseInt(hex.slice(1, 3), 16);\n  const g = parseInt(hex.slice(3, 5), 16);\n  const b = parseInt(hex.slice(5, 7), 16);\n  return `rgba(${r}, ${g}, ${b}, ${alpha})`;\n}\n\n// --- Mount -------------------------------------------------------------------\nconst canvas = document.createElement(\"canvas\");\ndocument.getElementById(\"container\").appendChild(canvas);\n\n// --- Chart ---------------------------------------------------------------\nnew Chart(canvas, {\n  data: {\n    datasets: [\n      {\n        type: \"line\",\n        label: \"Density estimate\",\n        data: densityPoints,\n        borderColor: t.palette[0],\n        backgroundColor: hexToRgba(t.palette[0], 0.25),\n        borderWidth: 3.5,\n        pointRadius: 0,\n        tension: 0.35,\n        fill: \"origin\",\n      },\n      {\n        type: \"scatter\",\n        label: \"Observations\",\n        data: rugPoints,\n        pointStyle: \"line\",\n        rotation: 90,\n        radius: 9,\n        borderColor: hexToRgba(t.palette[0], 0.45),\n        borderWidth: 1.5,\n      },\n    ],\n  },\n  options: {\n    responsive: true,\n    maintainAspectRatio: false,\n    animation: false,\n    plugins: {\n      title: {\n        display: true,\n        text: \"density-basic · javascript · chartjs · anyplot.ai\",\n        color: t.ink,\n        font: { size: 22 },\n      },\n      legend: { display: false },\n    },\n    scales: {\n      x: {\n        type: \"linear\",\n        min: gridStart,\n        max: gridEnd,\n        ticks: { color: t.inkSoft, font: { size: 14 } },\n        grid: { display: false },\n        title: {\n          display: true,\n          text: \"Commute Time (minutes)\",\n          color: t.ink,\n          font: { size: 16 },\n        },\n      },\n      y: {\n        min: rugY * 1.6,\n        max: maxDensity * 1.15,\n        ticks: { color: t.inkSoft, font: { size: 14 } },\n        grid: { color: t.grid },\n        title: {\n          display: true,\n          text: \"Density\",\n          color: t.ink,\n          font: { size: 16 },\n        },\n      },\n    },\n  },\n});\n"}