{"spec_id":"subplot-grid","library":"highcharts","language":"javascript","code":"// anyplot.ai\n// subplot-grid: Subplot Grid Layout\n// Library: highcharts 12.6.0 | JavaScript 22.23.2\n// Quality: 87/100 | Created: 2026-09-09\n\nconst t = window.ANYPLOT_TOKENS;\n\n// --- Fixed-seed LCG (no seeded RNG in the browser) ----------------------------------\nfunction lcg(seed) {\n  let s = seed;\n  return () => {\n    s = (s * 1664525 + 1013904223) % 4294967296;\n    return s / 4294967296;\n  };\n}\nconst rand = lcg(20260909);\nfunction randNormal(mean, sd) {\n  const u1 = Math.max(rand(), 1e-12);\n  const u2 = rand();\n  return mean + sd * Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2);\n}\n\n// --- Panel 1 data: monthly website visits & new signups, a seasonal trend (combo) --\nconst months = [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\"];\nconst seasonal = [1, 0, -1, -2, -2, -1, 1, 2, 1, 0, 1, 3];\nconst visitsThousands = seasonal.map((s, i) => Math.round(48 + s * 4 + i * 1.4 + randNormal(0, 1.6)));\n// Second series on the SAME month axis (a different, smaller-scale count) so panel 1\n// can demonstrate a shared x-axis with independent y-axes for comparison at different scales.\nconst newSignups = seasonal.map((s, i) => Math.round(180 + s * 12 + i * 3 + randNormal(0, 8)));\n\n// --- Panel 2 data: quarterly revenue by product category (bar) ---------------------\nconst categories = [\"Electronics\", \"Apparel\", \"Home & Garden\", \"Sporting Goods\", \"Books\"];\nconst revenueThousands = [312, 248, 196, 141, 87];\n\n// --- Panel 3 data: product price vs. customer rating (scatter) ---------------------\nconst nProducts = 48;\nconst priceUsd = [];\nconst rating = [];\nfor (let i = 0; i < nProducts; i++) {\n  const price = 8 + 290 * rand();\n  const r = Math.min(5, Math.max(1, 3.1 + 0.0055 * price + randNormal(0, 0.45)));\n  priceUsd.push(Math.round(price * 100) / 100);\n  rating.push(Math.round(r * 10) / 10);\n}\n\n// --- Panel 4 data: order value distribution, right-skewed (histogram via column) ---\nconst nOrders = 600;\nconst orderValues = [];\nfor (let i = 0; i < nOrders; i++) {\n  orderValues.push(Math.exp(randNormal(3.6, 0.55)));\n}\nconst binWidth = 20;\nconst binCount = 12;\nconst binCounts = new Array(binCount).fill(0);\norderValues.forEach((v) => {\n  const idx = Math.min(binCount - 1, Math.floor(v / binWidth));\n  binCounts[idx] += 1;\n});\nconst binLabels = binCounts.map((_, i) => `${i * binWidth}-${(i + 1) * binWidth}`);\n\n// --- Shared chart chrome for every panel --------------------------------------------\nfunction baseOptions(type, panelTitle, xTitle, yTitle) {\n  return {\n    chart: { type, backgroundColor: \"transparent\", animation: false,\n             spacing: [10, 16, 10, 10], style: { fontFamily: \"inherit\" } },\n    credits: { enabled: false },\n    colors: t.palette,\n    title: { text: panelTitle, style: { color: t.ink, fontSize: \"16px\", fontWeight: \"600\" }, margin: 12 },\n    xAxis: { title: { text: xTitle, style: { color: t.inkSoft, fontSize: \"13px\" } },\n             lineColor: t.inkSoft, tickColor: t.inkSoft, gridLineColor: t.grid,\n             labels: { style: { color: t.inkSoft, fontSize: \"12px\" } } },\n    yAxis: { title: { text: yTitle, style: { color: t.inkSoft, fontSize: \"13px\" } },\n             gridLineColor: t.grid, lineColor: t.inkSoft, tickColor: t.inkSoft, tickWidth: 1,\n             labels: { style: { color: t.inkSoft, fontSize: \"12px\" } } },\n    legend: { enabled: false },\n    plotOptions: { series: { animation: false } },\n  };\n}\n\n// Panel 1 — Monthly Visits & New Signups (spline + column combo): SHARED x-axis (both\n// series plot against the same month categories, directly comparable month-to-month)\n// paired with INDEPENDENT y-axes (thousands of visits vs. raw signup counts live on very\n// different scales). Panels 2-4 keep fully independent axes since each visualizes an\n// unrelated variable at its own scale — together the grid demonstrates both modes the\n// spec calls for.\nconst panel1 = baseOptions(\"spline\", \"Monthly Visits & New Signups\", \"Month\", null);\npanel1.xAxis.categories = months;\npanel1.yAxis = [\n  { title: { text: \"Visits (thousands)\", style: { color: t.inkSoft, fontSize: \"13px\" } },\n    gridLineColor: t.grid, lineColor: t.inkSoft, tickColor: t.inkSoft, tickWidth: 1,\n    labels: { style: { color: t.inkSoft, fontSize: \"12px\" } } },\n  { title: { text: \"New signups\", style: { color: t.inkSoft, fontSize: \"13px\" } },\n    gridLineColor: \"transparent\", lineColor: t.inkSoft, tickColor: t.inkSoft, tickWidth: 1,\n    labels: { style: { color: t.inkSoft, fontSize: \"12px\" } }, opposite: true },\n];\npanel1.legend = { enabled: true, itemStyle: { color: t.inkSoft, fontSize: \"12px\" }, itemHoverStyle: { color: t.ink } };\npanel1.tooltip = {\n  shared: true,\n  formatter: function () {\n    const lines = this.points.map((p) => `${p.series.name}: ${p.y}${p.series.name === \"Visits\" ? \"k\" : \"\"}`);\n    return `<b>${this.x}</b><br/>${lines.join(\"<br/>\")}`;\n  },\n};\npanel1.series = [\n  {\n    name: \"Visits\", type: \"spline\", yAxis: 0,\n    data: visitsThousands,\n    color: t.palette[0],\n    lineWidth: 2.5,\n    marker: { radius: 4, fillColor: t.palette[0], lineColor: t.pageBg, lineWidth: 1 },\n  },\n  {\n    name: \"New signups\", type: \"column\", yAxis: 1,\n    data: newSignups,\n    color: t.palette[1],\n    opacity: 0.85,\n    pointPadding: 0.2, groupPadding: 0.15, borderWidth: 0,\n  },\n];\n\n// Panel 2 — Revenue by Product Category (bar): categorical comparison ---------------\nconst panel2 = baseOptions(\"bar\", \"Revenue by Category\", \"Revenue (thousand $)\", null);\npanel2.xAxis.categories = categories;\npanel2.xAxis.title = null;\npanel2.yAxis.gridLineColor = t.grid;\npanel2.tooltip = { formatter: function () { return `${this.point.category}: $${this.y}k`; } };\npanel2.series = [{ name: \"Revenue\", data: revenueThousands, colorByPoint: true }];\n\n// Panel 3 — Price vs. Customer Rating (scatter): correlation between two variables ---\nconst panel3 = baseOptions(\"scatter\", \"Price vs. Customer Rating\", \"Price ($)\", \"Rating (1-5)\");\npanel3.tooltip = {\n  formatter: function () { return `Price: $${this.x.toFixed(2)}<br/>Rating: ${this.y.toFixed(1)}`; },\n};\npanel3.series = [{\n  name: \"Products\",\n  data: priceUsd.map((p, i) => ({ x: p, y: rating[i] })),\n  marker: { symbol: \"circle\", radius: 4.5, fillColor: t.palette[0], lineColor: t.pageBg, lineWidth: 1 },\n}];\n\n// Panel 4 — Order Value Distribution (histogram via binned column) -------------------\nconst panel4 = baseOptions(\"column\", \"Order Value Distribution\", \"Order value ($)\", \"Number of orders\");\npanel4.xAxis.categories = binLabels;\npanel4.xAxis.labels.rotation = -45;\npanel4.plotOptions.column = { pointPadding: 0, groupPadding: 0.04, borderWidth: 0 };\npanel4.tooltip = { formatter: function () { return `$${this.point.category}: ${this.y} orders`; } };\npanel4.series = [{ name: \"Orders\", data: binCounts, color: t.palette[0] }];\n\n// --- Layout: shared header + a configurable, asymmetric grid of independently-mounted panels ---\nconst root = document.getElementById(\"container\");\n\nconst header = document.createElement(\"div\");\nheader.style.cssText = `padding:18px 24px 4px; font-size:22px; font-weight:600; color:${t.ink}; font-family:inherit;`;\nheader.textContent = \"subplot-grid · javascript · highcharts · anyplot.ai\";\nroot.appendChild(header);\n\n// Asymmetric 3-col x 2-row grid: panel 1 (the combo trend chart) spans the full top row\n// as the featured panel, giving the dashboard a clear focal point instead of four\n// equally-weighted cells; the remaining three panels sit side by side below it.\nconst gridCols = 3;\nconst grid = document.createElement(\"div\");\ngrid.style.cssText =\n  `display:grid; grid-template-columns:repeat(${gridCols}, 1fr); grid-template-rows:1fr 1fr; ` +\n  \"gap:16px; margin:4px 20px 20px; height:calc(100% - 62px);\";\nroot.appendChild(grid);\n\nconst panelSpecs = [\n  { id: \"panel-visits\", column: \"1 / -1\", row: \"1\" },\n  { id: \"panel-revenue\", column: \"1\", row: \"2\" },\n  { id: \"panel-price-rating\", column: \"2\", row: \"2\" },\n  { id: \"panel-order-dist\", column: \"3\", row: \"2\" },\n];\npanelSpecs.forEach(({ id, column, row }) => {\n  const cell = document.createElement(\"div\");\n  cell.id = id;\n  cell.style.cssText = `grid-column:${column}; grid-row:${row};`;\n  grid.appendChild(cell);\n});\n\nHighcharts.chart(\"panel-visits\", panel1);\nHighcharts.chart(\"panel-revenue\", panel2);\nHighcharts.chart(\"panel-price-rating\", panel3);\nHighcharts.chart(\"panel-order-dist\", panel4);\n"}