{"spec_id":"line-cycle-seasonal","library":"echarts","language":"javascript","code":"// anyplot.ai\n// line-cycle-seasonal: Cycle Plot (Seasonal Subseries)\n// Library: echarts 5.5.1 | JavaScript 22.22.3\n// Quality: 89/100 | Created: 2026-06-15\n\nconst t = window.ANYPLOT_TOKENS;\n\n// Simple deterministic LCG for synthetic data (no seeded RNG in browser)\nlet seed = 42;\nfunction lcg() {\n  seed = (seed * 1664525 + 1013904223) & 0xffffffff;\n  return (seed >>> 0) / 0xffffffff;\n}\n\n// Data: Monthly electricity demand (TWh) for a regional grid, 2018–2023\nconst MONTHS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];\nconst YEARS = [2018, 2019, 2020, 2021, 2022, 2023];\nconst NY = YEARS.length; // 6\nconst SPACING = 10; // x-units per month group (6 data points + 4 unit gap)\n\n// Seasonal model: amplitude 9 TWh, peak in Jan (m=0), upward trend 0.8 TWh/yr\nconst monthlyData = MONTHS.map(function(_, m) {\n  var base = 38 + 9 * Math.cos(2 * Math.PI * m / 12);\n  return YEARS.map(function(_, y) {\n    return +((base + 0.8 * y + (lcg() - 0.5) * 2.5)).toFixed(1);\n  });\n});\n\n// Seasonal means (one per month, averaged over all years)\nconst means = monthlyData.map(function(data) {\n  return +(data.reduce(function(sum, v) { return sum + v; }, 0) / NY).toFixed(2);\n});\n\n// Build series data with null separators between month groups\nconst trendData = [];\nconst meanData = [];\n\nMONTHS.forEach(function(_, m) {\n  var xStart = m * SPACING;\n  var xEnd = m * SPACING + NY - 1;\n  // Trend line: 6 chronological data points per month\n  monthlyData[m].forEach(function(v, y) { trendData.push([xStart + y, v]); });\n  trendData.push(null); // break line between groups\n  // Mean line: horizontal segment spanning the group width\n  meanData.push([xStart, means[m]], [xEnd, means[m]], null);\n});\n\n// Month label positions (center of each group)\nconst monthCenters = MONTHS.map(function(_, m) { return m * SPACING + (NY - 1) / 2; });\n\n// Title with scaled font size (67-char baseline → scale down for longer titles)\nconst titleText = 'Monthly Electricity Demand · line-cycle-seasonal · javascript · echarts · anyplot.ai';\nconst titleFontSize = Math.max(14, Math.round(22 * 67 / titleText.length));\n\nconst chart = echarts.init(document.getElementById('container'));\n\nchart.setOption({\n  animation: false,\n  backgroundColor: 'transparent',\n\n  title: {\n    text: titleText,\n    subtext: '2018–2023  ·  slope of each group reveals within-month trend  ·  bar marks seasonal mean',\n    left: 'center',\n    top: 16,\n    textStyle: { color: t.ink, fontSize: titleFontSize, fontWeight: 'bold' },\n    subtextStyle: { color: t.inkSoft, fontSize: 13 },\n    itemGap: 8,\n  },\n\n  legend: {\n    data: ['Monthly demand', 'Seasonal mean'],\n    bottom: 18,\n    textStyle: { color: t.inkSoft, fontSize: 13 },\n    itemGap: 30,\n    selectedMode: false,\n  },\n\n  grid: { left: 90, right: 45, top: 120, bottom: 68 },\n\n  xAxis: {\n    type: 'value',\n    min: -1.5,\n    max: 11 * SPACING + NY + 0.5, // 116.5 — clear of last data point (x=115)\n    axisLabel: {\n      customValues: monthCenters,\n      formatter: function(v) {\n        // customValues ensures v is always a month center; derive index for safety\n        var m = Math.round((v - (NY - 1) / 2) / SPACING);\n        return (m >= 0 && m < 12) ? MONTHS[m] : '';\n      },\n      color: t.inkSoft,\n      fontSize: 14,\n    },\n    axisTick: { show: false },\n    axisLine: { lineStyle: { color: t.inkSoft } },\n    splitLine: { show: false },\n  },\n\n  yAxis: {\n    type: 'value',\n    name: 'Electricity Demand (TWh)',\n    nameLocation: 'middle',\n    nameGap: 58,\n    nameTextStyle: { color: t.inkSoft, fontSize: 13 },\n    axisLabel: { color: t.inkSoft, fontSize: 13 },\n    axisLine: { show: false },\n    axisTick: { show: false },\n    splitLine: { lineStyle: { color: t.grid } },\n    scale: true,\n  },\n\n  series: [\n    {\n      name: 'Monthly demand',\n      type: 'line',\n      data: trendData,\n      connectNulls: false,\n      lineStyle: { color: t.palette[0], width: 2.5 },\n      itemStyle: { color: t.palette[0] },\n      showSymbol: true,\n      symbolSize: 7,\n      symbol: 'circle',\n      emphasis: { disabled: true },\n    },\n    {\n      name: 'Seasonal mean',\n      type: 'line',\n      data: meanData,\n      connectNulls: false,\n      lineStyle: { color: t.palette[1], width: 4 },\n      itemStyle: { color: t.palette[1] },\n      showSymbol: false,\n      emphasis: { disabled: true },\n    },\n  ],\n});\n"}