{"spec_id":"acf-pacf","library":"echarts","language":"javascript","code":"// anyplot.ai\n// acf-pacf: Autocorrelation and Partial Autocorrelation (ACF/PACF) Plot\n// Library: echarts 5.5.1 | JavaScript 22.22.3\n// Quality: 88/100 | Created: 2026-06-10\n\n//# anyplot-orientation: landscape\nconst t = window.ANYPLOT_TOKENS;\n\n// Seeded LCG for deterministic data generation\nlet _seed = 42;\nfunction _lcg() {\n  _seed = (Math.imul(_seed, 1664525) + 1013904223) >>> 0;\n  return _seed / 0x100000000;\n}\nfunction _randn() {\n  const u1 = _lcg() + 1e-10, u2 = _lcg();\n  return Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2);\n}\n\n// Generate AR(2) time series: x_t = 0.6*x_{t-1} + 0.25*x_{t-2} + ε_t\n// Represents daily temperature anomaly residuals (°C)\nconst N = 300;\nconst series = new Array(N).fill(0);\nfor (let i = 2; i < N; i++) {\n  series[i] = 0.6 * series[i - 1] + 0.25 * series[i - 2] + _randn();\n}\n\nconst MAX_LAG = 35;\nconst ci = 1.96 / Math.sqrt(N);\n\n// Sample ACF at lags 0..MAX_LAG\nconst acfMean = series.reduce((s, v) => s + v, 0) / N;\nconst acfDenom = series.reduce((s, v) => s + (v - acfMean) ** 2, 0);\nconst acf = Array.from({ length: MAX_LAG + 1 }, (_, k) => {\n  let num = 0;\n  for (let i = k; i < N; i++) num += (series[i] - acfMean) * (series[i - k] - acfMean);\n  return num / acfDenom;\n});\n\n// Sample PACF at lags 1..MAX_LAG via Durbin-Levinson recursion\nconst pacf = [acf[1]];\nlet phi = [acf[1]];\nfor (let k = 2; k <= MAX_LAG; k++) {\n  let num = acf[k], den = 1;\n  for (let j = 0; j < k - 1; j++) {\n    num -= phi[j] * acf[k - 1 - j];\n    den -= phi[j] * acf[j + 1];\n  }\n  const pkk = num / den;\n  const next = new Array(k);\n  for (let j = 0; j < k - 1; j++) next[j] = phi[j] - pkk * phi[k - 2 - j];\n  next[k - 1] = pkk;\n  phi = next;\n  pacf.push(pkk);\n}\n\n// Color tokens: palette[0] = ACF green #009E73, palette[1] = PACF lavender #C475FD\nconst SIG_ACF    = t.palette[0];\nconst INSIG_ACF  = \"rgba(0,158,115,0.28)\";\nconst SIG_PACF   = t.palette[1];\nconst INSIG_PACF = \"rgba(196,117,253,0.28)\";\n\n// Shared 36-slot category axis (lags 0–35) for both panels so bars align vertically\nconst lagLabels = Array.from({ length: MAX_LAG + 1 }, (_, i) => String(i));\n\nconst acfBarData = acf.map((v, i) => ({\n  value: +v.toFixed(4),\n  itemStyle: { color: (i === 0 || Math.abs(v) > ci) ? SIG_ACF : INSIG_ACF }\n}));\n\n// Prepend null at lag-0 slot so PACF panel columns align with ACF panel\nconst pacfBarData = [{ value: null, itemStyle: { color: \"transparent\" } }].concat(\n  pacf.map((v) => ({\n    value: +v.toFixed(4),\n    itemStyle: { color: Math.abs(v) > ci ? SIG_PACF : INSIG_PACF }\n  }))\n);\n\n// Init chart\nconst chart = echarts.init(document.getElementById(\"container\"));\n\nchart.setOption({\n  animation: false,\n  color: t.palette,\n  backgroundColor: \"transparent\",\n\n  title: {\n    text: \"acf-pacf · javascript · echarts · anyplot.ai\",\n    subtext: \"AR(2) daily temperature anomalies  ·  N = 300  ·  95% CI shown\",\n    left: \"center\",\n    top: 16,\n    textStyle:    { color: t.ink,     fontSize: 22, fontWeight: \"600\" },\n    subtextStyle: { color: t.inkSoft, fontSize: 14  }\n  },\n\n  // Two stacked grids (1600 × 900 CSS canvas)\n  grid: [\n    { left: 85, right: 50, top: 78,  bottom: 472 }, // ACF\n    { left: 85, right: 50, top: 470, bottom: 62  }  // PACF\n  ],\n\n  xAxis: [\n    {\n      gridIndex: 0,\n      type: \"category\",\n      data: lagLabels,\n      axisLabel: { show: false },\n      axisLine:  { lineStyle: { color: t.inkSoft } },\n      axisTick:  { show: false },\n      splitLine: { show: false }\n    },\n    {\n      gridIndex: 1,\n      type: \"category\",\n      data: lagLabels,\n      name: \"Lag\",\n      nameLocation: \"middle\",\n      nameGap: 38,\n      nameTextStyle: { color: t.ink, fontSize: 15, fontWeight: \"500\" },\n      axisLabel: { color: t.inkSoft, fontSize: 13 },\n      axisLine:  { lineStyle: { color: t.inkSoft } },\n      axisTick:  { show: false },\n      splitLine: { show: false }\n    }\n  ],\n\n  yAxis: [\n    {\n      gridIndex: 0,\n      type: \"value\",\n      name: \"ACF\",\n      nameLocation: \"middle\",\n      nameGap: 52,\n      nameTextStyle: { color: t.ink, fontSize: 15, fontWeight: \"500\" },\n      min: -0.35,\n      max: 1.05,\n      interval: 0.25,\n      axisLabel: { color: t.inkSoft, fontSize: 13, formatter: v => v.toFixed(2) },\n      axisLine:  { show: true, lineStyle: { color: t.inkSoft } },\n      splitLine: { lineStyle: { color: t.grid } }\n    },\n    {\n      gridIndex: 1,\n      type: \"value\",\n      name: \"PACF\",\n      nameLocation: \"middle\",\n      nameGap: 52,\n      nameTextStyle: { color: t.ink, fontSize: 15, fontWeight: \"500\" },\n      min: -0.40,\n      max: 0.85,\n      interval: 0.25,\n      axisLabel: { color: t.inkSoft, fontSize: 13, formatter: v => v.toFixed(2) },\n      axisLine:  { show: true, lineStyle: { color: t.inkSoft } },\n      splitLine: { lineStyle: { color: t.grid } }\n    }\n  ],\n\n  series: [\n    {\n      type: \"bar\",\n      xAxisIndex: 0,\n      yAxisIndex: 0,\n      data: acfBarData,\n      barWidth: 3,\n      markLine: {\n        silent: true,\n        symbol: \"none\",\n        label: { show: false },\n        data: [\n          { yAxis: 0,   lineStyle: { color: t.inkSoft, type: \"solid\",  width: 1.5 } },\n          { yAxis: ci,  lineStyle: { color: t.amber,   type: \"dashed\", width: 2   } },\n          { yAxis: -ci, lineStyle: { color: t.amber,   type: \"dashed\", width: 2   } }\n        ]\n      }\n    },\n    {\n      type: \"bar\",\n      xAxisIndex: 1,\n      yAxisIndex: 1,\n      data: pacfBarData,\n      barWidth: 3,\n      markLine: {\n        silent: true,\n        symbol: \"none\",\n        label: { show: false },\n        data: [\n          { yAxis: 0,   lineStyle: { color: t.inkSoft, type: \"solid\",  width: 1.5 } },\n          { yAxis: ci,  lineStyle: { color: t.amber,   type: \"dashed\", width: 2   } },\n          { yAxis: -ci, lineStyle: { color: t.amber,   type: \"dashed\", width: 2   } }\n        ]\n      }\n    }\n  ]\n});\n"}