{"spec_id":"frequency-polygon-basic","library":"chartjs","language":"javascript","code":"// anyplot.ai\n// frequency-polygon-basic: Frequency Polygon for Distribution Comparison\n// Library: chartjs 4.4.7 | JavaScript 22.23.2\n// Quality: 88/100 | Created: 2026-09-02\n//# anyplot-orientation: landscape\n\nconst t = window.ANYPLOT_TOKENS;\n\n// --- Data (in-memory, deterministic) ----------------------------------------\n// Reaction times (ms) recorded across three experimental conditions in a\n// psychology response-time study.\nfunction makeLcg(seed) {\n  let state = seed;\n  return function lcg() {\n    state = (state * 1664525 + 1013904223) % 4294967296;\n    return state / 4294967296;\n  };\n}\n\nfunction normalSamples(rng, n, mean, std) {\n  const samples = [];\n  for (let i = 0; i < n; i += 2) {\n    const u1 = Math.max(rng(), 1e-9);\n    const u2 = rng();\n    const mag = std * Math.sqrt(-2 * Math.log(u1));\n    samples.push(mean + mag * Math.cos(2 * Math.PI * u2));\n    samples.push(mean + mag * Math.sin(2 * Math.PI * u2));\n  }\n  return samples.slice(0, n);\n}\n\nconst rng = makeLcg(42);\nconst groups = [\n  { name: \"Control\", n: 300, mean: 480, std: 55 },\n  { name: \"Caffeine\", n: 260, mean: 420, std: 48 },\n  { name: \"Sleep-deprived\", n: 240, mean: 545, std: 70 },\n];\nconst groupSamples = groups.map((g) => normalSamples(rng, g.n, g.mean, g.std));\n\n// Shared bin edges across all groups for accurate comparison\nconst binWidth = 25;\nconst allValues = groupSamples.flat();\nconst minVal = Math.floor(Math.min(...allValues) / binWidth) * binWidth;\nconst maxVal = Math.ceil(Math.max(...allValues) / binWidth) * binWidth;\nconst binCount = Math.round((maxVal - minVal) / binWidth);\n\nfunction frequencyPolygon(samples) {\n  const counts = new Array(binCount).fill(0);\n  samples.forEach((v) => {\n    const idx = Math.min(Math.max(Math.floor((v - minVal) / binWidth), 0), binCount - 1);\n    counts[idx] += 1;\n  });\n  const midpoints = counts.map((_, i) => minVal + (i + 0.5) * binWidth);\n  // Extend to zero at both ends to close the polygon shape\n  const points = [{ x: midpoints[0] - binWidth, y: 0 }];\n  counts.forEach((c, i) => points.push({ x: midpoints[i], y: c }));\n  points.push({ x: midpoints[midpoints.length - 1] + binWidth, y: 0 });\n  return points;\n}\n\nconst groupPoints = groupSamples.map((samples) => frequencyPolygon(samples));\nconst dashPatterns = [[], [10, 6], [3, 4]];\n\nconst datasets = groups.map((g, i) => {\n  const points = groupPoints[i];\n  return {\n    label: g.name,\n    data: points,\n    borderColor: t.palette[i],\n    backgroundColor: `${t.palette[i]}26`,\n    borderDash: dashPatterns[i % dashPatterns.length],\n    borderWidth: 3,\n    fill: true,\n    tension: 0,\n    pointRadius: points.map((_, idx) => (idx === 0 || idx === points.length - 1 ? 0 : 4)),\n    pointBackgroundColor: t.palette[i],\n    pointBorderColor: t.pageBg,\n    pointBorderWidth: 1,\n  };\n});\n\n// --- Mount -------------------------------------------------------------------\nconst canvas = document.createElement(\"canvas\");\ndocument.getElementById(\"container\").appendChild(canvas);\n\n// --- Chart -------------------------------------------------------------------\nnew Chart(canvas, {\n  type: \"line\",\n  data: { datasets },\n  options: {\n    responsive: true,\n    maintainAspectRatio: false,\n    animation: false,\n    parsing: false,\n    plugins: {\n      title: {\n        display: true,\n        text: \"frequency-polygon-basic · javascript · chartjs · anyplot.ai\",\n        color: t.ink,\n        font: { size: 22 },\n      },\n      legend: {\n        position: \"top\",\n        labels: { color: t.ink, font: { size: 16 }, usePointStyle: true },\n      },\n    },\n    scales: {\n      x: {\n        type: \"linear\",\n        min: minVal - binWidth / 2,\n        max: maxVal + binWidth / 2,\n        ticks: { color: t.inkSoft, font: { size: 14 } },\n        grid: { display: false },\n        title: { display: true, text: \"Reaction Time (ms)\", color: t.ink, font: { size: 16 } },\n      },\n      y: {\n        beginAtZero: true,\n        ticks: { color: t.inkSoft, font: { size: 14 } },\n        grid: { color: t.grid },\n        title: { display: true, text: \"Frequency (count)\", color: t.ink, font: { size: 16 } },\n      },\n    },\n  },\n});\n"}