{"spec_id":"line-cycle-seasonal","library":"muix","language":"javascript","code":"// anyplot.ai\n// line-cycle-seasonal: Cycle Plot (Seasonal Subseries)\n// Library: muix 7.29.1 | JavaScript 22.22.3\n// Quality: 87/100 | Created: 2026-06-15\n\nimport { LineChart } from \"@mui/x-charts/LineChart\";\n\nconst t = window.ANYPLOT_TOKENS;\n\n// --- Data: monthly online retail sales ($ billion), 2014–2023 ---\n// Cycle plot: 12 month groups, each with 10 chronological year observations.\n// Null-position gaps between groups create visual separation.\n\nconst MONTHS = [\"Jan\",\"Feb\",\"Mar\",\"Apr\",\"May\",\"Jun\",\"Jul\",\"Aug\",\"Sep\",\"Oct\",\"Nov\",\"Dec\"];\nconst N_YEARS = 10;  // 2014–2023\nconst GAP = 2;       // null-gap bands between month groups\n\n// Seasonal multipliers (low in winter, peak in holiday season)\nconst SEASONAL = [0.72, 0.75, 0.88, 0.85, 0.87, 0.82, 0.84, 0.87, 0.90, 0.95, 1.10, 1.45];\n\n// Center index within each group — tick label placed at year 2018 (index 4)\nconst CENTER_IDX = 4;\n\nconst xCategories: string[] = [];\nconst tickPositions: string[] = [];\nconst salesValues: (number | null)[] = [];\nconst meanValues: (number | null)[] = [];\n\nMONTHS.forEach((month, m) => {\n  const yearVals: number[] = [];\n\n  for (let yi = 0; yi < N_YEARS; yi++) {\n    const trend = 3.5 * Math.pow(1.08, yi);  // ~8% annual growth baseline\n    const noise = (((m * 7 + yi * 13) % 17) - 8) * 0.04;  // deterministic ±0.32 B\n    const val = trend * SEASONAL[m] + noise;\n    yearVals.push(val);\n\n    const cat = `${month}_${2014 + yi}`;\n    xCategories.push(cat);\n    salesValues.push(val);\n\n    if (yi === CENTER_IDX) tickPositions.push(cat);\n  }\n\n  for (let g = 0; g < GAP; g++) {\n    xCategories.push(`__gap_${m}_${g}`);\n    salesValues.push(null);\n  }\n\n  const mean = yearVals.reduce((s, v) => s + v, 0) / N_YEARS;\n  for (let yi = 0; yi < N_YEARS; yi++) {\n    meanValues.push(mean);\n  }\n  for (let g = 0; g < GAP; g++) {\n    meanValues.push(null);\n  }\n});\n\n// Title is 75 chars — scale from 22px: round(22 × 67/75) ≈ 20px\nconst TITLE =\n  \"Monthly Retail Sales · line-cycle-seasonal · javascript · muix · anyplot.ai\";\n\n// --- Chart ---\nexport default function Chart() {\n  const { width, height } = window.ANYPLOT_SIZE;\n  const titleH = 52;\n\n  return (\n    <div\n      style={{\n        width,\n        height,\n        display: \"flex\",\n        flexDirection: \"column\",\n        fontFamily: \"system-ui, -apple-system, sans-serif\",\n      }}\n    >\n      {/* Title — wrapper div, MUI X community has no built-in title slot */}\n      <div\n        style={{\n          height: titleH,\n          padding: \"14px 60px 0\",\n          fontSize: 20,\n          fontWeight: 600,\n          color: t.ink,\n          letterSpacing: \"0.01em\",\n          flexShrink: 0,\n        }}\n      >\n        {TITLE}\n      </div>\n\n      <LineChart\n        width={width}\n        height={height - titleH}\n        skipAnimation\n        colors={[t.palette[0], t.palette[1]]}\n        grid={{ horizontal: true }}\n        sx={{\n          // Remove axis spine lines for a cleaner frameless look\n          \"& .MuiChartsAxis-line\": { display: \"none\" },\n          // Remove tick marks, keep labels\n          \"& .MuiChartsAxis-tick\": { display: \"none\" },\n          // Subtle horizontal grid using theme grid token\n          \"& .MuiChartsGrid-horizontalLine\": {\n            stroke: t.grid,\n            strokeWidth: 1,\n          },\n        }}\n        xAxis={[{\n          scaleType: \"band\",\n          data: xCategories,\n          // Tick labels only at center of each month group (e.g. \"Jan_2018\")\n          tickInterval: tickPositions,\n          valueFormatter: (val: string) => val.split(\"_\")[0],\n          tickLabelStyle: { fontSize: 14 },\n        }]}\n        yAxis={[{\n          label: \"Online Retail Sales ($ billion)\",\n          labelStyle: { fontSize: 14 },\n          tickLabelStyle: { fontSize: 13 },\n          min: 2,\n        }]}\n        series={[\n          {\n            data: salesValues,\n            label: \"Monthly Sales\",\n            showMark: false,\n            connectNulls: false,\n          },\n          {\n            data: meanValues,\n            label: \"Seasonal Mean\",\n            showMark: false,\n            connectNulls: false,\n          },\n        ]}\n        margin={{ top: 16, right: 40, bottom: 72, left: 84 }}\n      />\n    </div>\n  );\n}\n"}