{"spec_id":"rug-basic","library":"chartjs","language":"javascript","code":"// anyplot.ai\n// rug-basic: Basic Rug Plot\n// Library: chartjs 4.4.7 | JavaScript 22.23.1\n// Quality: 91/100 | Created: 2026-07-25\n\nconst t = window.ANYPLOT_TOKENS;\n\n// --- Data (in-memory, deterministic fixed-seed LCG) -------------------------\n// Reaction times (ms) from a two-alternative choice task: most responses are\n// fast, a slower \"lapse\" cluster shows attentional dips, and a handful of\n// outliers sit far past the main mass. The rug marks the exact position of\n// every trial; the translucent histogram behind it gives the shape context\n// that binning alone would hide the individual points for.\nfunction lcg(seed) {\n  let state = seed >>> 0;\n  return function () {\n    state = (1664525 * state + 1013904223) >>> 0;\n    return state / 4294967296;\n  };\n}\nconst rand = lcg(42);\nfunction gaussian(mean, sd) {\n  const u1 = Math.max(rand(), 1e-9);\n  const u2 = rand();\n  const z = Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2);\n  return mean + z * sd;\n}\n\nconst reactionTimes = [];\nfor (let i = 0; i < 140; i++) reactionTimes.push(Math.max(140, gaussian(320, 42)));\nfor (let i = 0; i < 75; i++) reactionTimes.push(Math.max(140, gaussian(560, 65)));\nreactionTimes.push(880, 905, 930, 860, 950); // slow outliers\n\nconst binWidth = 25;\nconst binStart = Math.floor(Math.min(...reactionTimes) / binWidth) * binWidth;\nconst binEnd = Math.ceil(Math.max(...reactionTimes) / binWidth) * binWidth;\nconst binCount = (binEnd - binStart) / binWidth;\nconst counts = new Array(binCount).fill(0);\nreactionTimes.forEach((v) => {\n  const idx = Math.min(binCount - 1, Math.floor((v - binStart) / binWidth));\n  counts[idx]++;\n});\nconst histogram = counts.map((count, i) => ({ x: binStart + (i + 0.5) * binWidth, y: count }));\n\nconst maxCount = Math.max(...counts);\nconst yMax = Math.ceil((maxCount * 1.15) / 10) * 10;\nconst yMin = -Math.ceil(maxCount * 0.22);\nconst rugY = -Math.ceil(maxCount * 0.11);\nconst rugPoints = reactionTimes.map((v) => ({ x: v, y: rugY }));\n\n// --- Mount -------------------------------------------------------------------\nconst canvas = document.createElement(\"canvas\");\ndocument.getElementById(\"container\").appendChild(canvas);\n\n// --- Chart ---------------------------------------------------------------\nconst title = \"Reaction Times in a Cognitive Task · rug-basic · javascript · chartjs · anyplot.ai\";\nconst titleFontSize = Math.round(22 * Math.min(1, 67 / title.length));\n\nnew Chart(canvas, {\n  data: {\n    datasets: [\n      {\n        type: \"bar\",\n        label: \"Trial count (25 ms bins)\",\n        data: histogram,\n        backgroundColor: `${t.inkSoft}40`, // translucent context shape, not a data series\n        borderWidth: 0,\n        barThickness: \"flex\",\n        categoryPercentage: 1.0,\n        barPercentage: 0.95,\n        order: 2,\n      },\n      {\n        type: \"scatter\",\n        label: \"Individual trials (rug)\",\n        data: rugPoints,\n        pointStyle: \"line\",\n        rotation: 90,\n        pointRadius: 15,\n        borderWidth: 2.5,\n        borderColor: `${t.palette[0]}B3`, // brand green, semi-transparent for overlap density\n        backgroundColor: \"transparent\",\n        order: 1,\n      },\n    ],\n  },\n  options: {\n    responsive: true,\n    maintainAspectRatio: false,\n    animation: false,\n    plugins: {\n      title: {\n        display: true,\n        text: title,\n        color: t.ink,\n        font: { size: titleFontSize },\n        padding: { bottom: 20 },\n      },\n      legend: {\n        display: true,\n        position: \"top\",\n        align: \"end\",\n        labels: { color: t.inkSoft, font: { size: 14 }, boxWidth: 20, boxHeight: 3 },\n      },\n      tooltip: { enabled: false },\n    },\n    scales: {\n      x: {\n        type: \"linear\",\n        title: { display: true, text: \"Reaction Time (ms)\", color: t.ink, font: { size: 16 } },\n        ticks: { color: t.inkSoft, font: { size: 14 } },\n        grid: { display: false },\n        border: { color: t.inkSoft },\n      },\n      y: {\n        min: yMin,\n        max: yMax,\n        title: { display: true, text: \"Trial Count\", color: t.ink, font: { size: 16 } },\n        ticks: {\n          color: t.inkSoft,\n          font: { size: 14 },\n          callback: (value) => (value < 0 ? \"\" : value),\n        },\n        grid: { color: t.grid, drawTicks: false },\n        border: { display: false },\n      },\n    },\n  },\n});\n"}