{"spec_id":"subplot-mosaic","library":"chartjs","language":"javascript","code":"// anyplot.ai\n// subplot-mosaic: Mosaic Subplot Layout with Varying Sizes\n// Library: chartjs 4.4.7 | JavaScript 22.23.2\n// Quality: 91/100 | Created: 2026-09-09\n\nconst t = window.ANYPLOT_TOKENS;\n\n// --- Data: 30-day weather station dashboard (deterministic LCG) ------------\nfunction lcg(seed) {\n  let state = seed >>> 0;\n  return function () {\n    state = (1103515245 * state + 12345) & 0x7fffffff;\n    return state / 0x7fffffff;\n  };\n}\nconst rand = lcg(11);\n\nconst numDays = 30;\nconst dayLabels = Array.from({ length: numDays }, (_, i) => `Day ${i + 1}`);\nconst temperatures = Array.from({ length: numDays }, (_, i) =>\n  Number((14 + 6 * Math.sin((i / numDays) * Math.PI) + (rand() - 0.5) * 3).toFixed(1))\n);\n\nconst months = [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\"];\nconst rainfallMm = months.map(() => Math.round(40 + rand() * 60));\n\nconst windHumidityPoints = Array.from({ length: 35 }, () => {\n  const windSpeed = Number((5 + rand() * 25).toFixed(1));\n  const humidity = Number(\n    Math.max(20, Math.min(95, 75 - windSpeed * 1.1 + (rand() - 0.5) * 25)).toFixed(1)\n  );\n  return { x: windSpeed, y: humidity };\n});\n\nconst conditionLabels = [\"Sunny\", \"Cloudy\", \"Rainy\", \"Snow\"];\nconst conditionCounts = [13, 9, 6, 2]; // sums to numDays\n\nconst directionLabels = [\"N\", \"E\", \"S\", \"W\"];\nconst directionCounts = [8, 11, 6, 5]; // sums to numDays\n\n// Air-quality tiers use the traffic-light semantic exception (good/warning/bad)\nconst aqiLabels = [\"Good\", \"Moderate\", \"Poor\"];\nconst aqiCounts = [18, 9, 3]; // sums to numDays\nconst aqiColors = [t.palette[0], t.amber, t.palette[4]];\n\n// --- Layout: \"AAA;BBC;DEF\" mosaic string -> CSS grid-template-areas --------\n// Mirrors the ASCII-art mosaic syntax from the spec (e.g. matplotlib's\n// subplot_mosaic \"AB;CC\"): repeated letters span cells, each unique letter\n// becomes one independently-sized Chart.js canvas.\nconst mosaicPattern = \"AAA;BBC;DEF\";\nconst mosaicRows = mosaicPattern.split(\";\");\nconst gridTemplateAreas = mosaicRows.map((row) => `\"${row.split(\"\").join(\" \")}\"`).join(\" \");\n\nconst root = document.createElement(\"div\");\nroot.style.cssText = `\n  width: 100%; height: 100%; box-sizing: border-box;\n  display: flex; flex-direction: column;\n  padding: 22px 26px; background: ${t.pageBg};\n  font-family: -apple-system, \"Segoe UI\", Roboto, sans-serif;\n`;\ndocument.getElementById(\"container\").appendChild(root);\n\nconst header = document.createElement(\"div\");\nheader.textContent = \"subplot-mosaic · javascript · chartjs · anyplot.ai\";\nheader.style.cssText = `\n  color: ${t.ink}; font-size: 22px; font-weight: 600;\n  text-align: center; flex-shrink: 0; margin-bottom: 6px;\n`;\nroot.appendChild(header);\n\nconst caption = document.createElement(\"div\");\ncaption.textContent =\n  \"Mosaic \\\"AAA;BBC;DEF\\\" — the dominant trend spans the full width; supporting panels shrink to match their analytical weight\";\ncaption.style.cssText = `\n  color: ${t.inkSoft}; font-size: 13px; font-style: italic;\n  text-align: center; flex-shrink: 0; margin-bottom: 16px;\n`;\nroot.appendChild(caption);\n\nconst grid = document.createElement(\"div\");\ngrid.style.cssText = `\n  flex: 1; min-height: 0;\n  display: grid; grid-template-columns: repeat(3, 1fr);\n  grid-template-rows: 1.5fr 1.15fr 1fr; grid-template-areas: ${gridTemplateAreas};\n  gap: 20px;\n`;\nroot.appendChild(grid);\n\nfunction makeCell(area) {\n  const cell = document.createElement(\"div\");\n  cell.style.cssText = `\n    grid-area: ${area}; position: relative; min-width: 0; min-height: 0; box-sizing: border-box;\n    background: ${t.elevatedBg}; border-radius: 10px; padding: 14px 18px;\n  `;\n  const canvas = document.createElement(\"canvas\");\n  cell.appendChild(canvas);\n  grid.appendChild(cell);\n  return canvas;\n}\n\nconst titleFont = (size) => ({ display: true, text: \"\", color: t.ink, font: { size, weight: \"600\" }, padding: { bottom: 8 } });\nconst panelTitle = (text, size) => ({ ...titleFont(size), text });\nconst axisTicks = (size) => ({ color: t.inkSoft, font: { size } });\nconst axisTitle = (text, size) => ({ display: true, text, color: t.inkSoft, font: { size } });\n\n// Panel A (dominant, full width): 30-day temperature trend\nnew Chart(makeCell(\"A\"), {\n  type: \"line\",\n  data: {\n    labels: dayLabels,\n    datasets: [\n      {\n        label: \"Avg Temperature\",\n        data: temperatures,\n        borderColor: t.palette[0],\n        backgroundColor: (context) => {\n          const { ctx, chartArea } = context.chart;\n          if (!chartArea) return `${t.palette[0]}00`;\n          const gradient = ctx.createLinearGradient(0, chartArea.top, 0, chartArea.bottom);\n          gradient.addColorStop(0, `${t.palette[0]}40`);\n          gradient.addColorStop(1, `${t.palette[0]}00`);\n          return gradient;\n        },\n        fill: true,\n        borderWidth: 2.5,\n        pointRadius: 0,\n        tension: 0.2,\n      },\n    ],\n  },\n  options: {\n    responsive: true,\n    maintainAspectRatio: false,\n    animation: false,\n    plugins: {\n      title: panelTitle(\"Daily Avg Temperature (30 Days)\", 19),\n      legend: { display: false },\n    },\n    scales: {\n      x: {\n        ticks: { ...axisTicks(11), autoSkip: false, callback: (_v, i) => (i % 5 === 0 ? dayLabels[i] : null) },\n        grid: { display: false },\n      },\n      y: { ticks: axisTicks(12), grid: { color: t.grid }, title: axisTitle(\"°C\", 13) },\n    },\n  },\n});\n\n// Panel B (medium, 2 cols): rainfall by month\nnew Chart(makeCell(\"B\"), {\n  type: \"bar\",\n  data: {\n    labels: months,\n    datasets: [{ label: \"Rainfall\", data: rainfallMm, backgroundColor: t.palette[0], borderWidth: 0 }],\n  },\n  options: {\n    responsive: true,\n    maintainAspectRatio: false,\n    animation: false,\n    plugins: { title: panelTitle(\"Monthly Rainfall\", 16), legend: { display: false } },\n    scales: {\n      x: { ticks: axisTicks(12), grid: { display: false } },\n      y: { ticks: axisTicks(11), grid: { color: t.grid }, title: axisTitle(\"mm\", 12), beginAtZero: true },\n    },\n  },\n});\n\n// Panel C (medium, 1 col): wind speed vs. humidity\nnew Chart(makeCell(\"C\"), {\n  type: \"scatter\",\n  data: {\n    datasets: [{ label: \"Reading\", data: windHumidityPoints, backgroundColor: t.palette[0], pointRadius: 6.5 }],\n  },\n  options: {\n    responsive: true,\n    maintainAspectRatio: false,\n    animation: false,\n    plugins: { title: panelTitle(\"Wind vs. Humidity\", 16), legend: { display: false } },\n    scales: {\n      x: { ticks: axisTicks(11), grid: { color: t.grid }, title: axisTitle(\"Wind (km/h)\", 12) },\n      y: { ticks: axisTicks(11), grid: { color: t.grid }, title: axisTitle(\"Humidity (%)\", 12) },\n    },\n  },\n});\n\n// Panel D (small): weather condition split\nnew Chart(makeCell(\"D\"), {\n  type: \"doughnut\",\n  data: {\n    labels: conditionLabels,\n    datasets: [{ data: conditionCounts, backgroundColor: t.palette.slice(0, 4), borderColor: t.pageBg, borderWidth: 2 }],\n  },\n  options: {\n    responsive: true,\n    maintainAspectRatio: false,\n    animation: false,\n    plugins: {\n      title: panelTitle(\"Conditions\", 14),\n      legend: { position: \"bottom\", labels: { color: t.inkSoft, font: { size: 12 }, boxWidth: 10, boxHeight: 10 } },\n    },\n  },\n});\n\n// Panel E (small): wind direction frequency\nnew Chart(makeCell(\"E\"), {\n  type: \"polarArea\",\n  data: {\n    labels: directionLabels,\n    datasets: [{ data: directionCounts, backgroundColor: t.palette.slice(0, 4).map((c) => `${c}CC`), borderColor: t.pageBg, borderWidth: 1.5 }],\n  },\n  options: {\n    responsive: true,\n    maintainAspectRatio: false,\n    animation: false,\n    plugins: {\n      title: panelTitle(\"Wind Direction\", 14),\n      legend: { position: \"bottom\", labels: { color: t.inkSoft, font: { size: 12 }, boxWidth: 10, boxHeight: 10 } },\n    },\n    scales: { r: { ticks: { display: false }, grid: { color: t.grid }, angleLines: { color: t.grid } } },\n  },\n});\n\n// Panel F (small): air-quality tiers (traffic-light semantic colors)\nnew Chart(makeCell(\"F\"), {\n  type: \"bar\",\n  data: {\n    labels: aqiLabels,\n    datasets: [{ data: aqiCounts, backgroundColor: aqiColors, borderWidth: 0, categoryPercentage: 0.7 }],\n  },\n  options: {\n    indexAxis: \"y\",\n    responsive: true,\n    maintainAspectRatio: false,\n    animation: false,\n    plugins: { title: panelTitle(\"Air Quality Days\", 14), legend: { display: false } },\n    scales: {\n      x: { ticks: axisTicks(12), grid: { color: t.grid }, beginAtZero: true },\n      y: { ticks: axisTicks(12), grid: { display: false } },\n    },\n  },\n});\n"}