{"spec_id":"acf-pacf","library":"muix","language":"javascript","code":"// anyplot.ai\n// acf-pacf: Autocorrelation and Partial Autocorrelation (ACF/PACF) Plot\n// Library: muix 9.16.0 | JavaScript 22.23.3\n// Quality: 84/100 | Updated: 2026-10-23\n\nimport { BarChart } from \"@mui/x-charts/BarChart\";\nimport { ChartsReferenceLine } from \"@mui/x-charts/ChartsReferenceLine\";\n\nconst t = window.ANYPLOT_TOKENS;\n\n// Constants\nconst MAX_LAG = 30; // number of lags shown in both panels\nconst Y_PAD = 0.15; // share of the value span added above and below each panel\n\n// Columns: set these to your data's column names\nconst VALUE = \"Daily Temperature Anomaly (°C)\"; // role: value\n\n// Data: replace this block with your own records, one object per row\n// 300 days of temperature anomalies with AR(2) persistence:\n// x_t = 0.65 * x_{t-1} + 0.15 * x_{t-2} + e_t\nconst data = (() => {\n  function lcgRng(seed: number) {\n    let s = seed >>> 0;\n    return () => {\n      s = (Math.imul(s, 1664525) + 1013904223) >>> 0;\n      return s / 4294967296;\n    };\n  }\n\n  function randn(rng: () => number) {\n    const u = Math.max(rng(), 1e-10);\n    return Math.sqrt(-2 * Math.log(u)) * Math.cos(2 * Math.PI * rng());\n  }\n\n  const rng = lcgRng(42);\n  const count = 300;\n  const series = [0, randn(rng) * 0.5];\n  for (let i = 2; i < count; i += 1) {\n    series.push(0.65 * series[i - 1] + 0.15 * series[i - 2] + randn(rng));\n  }\n  return series.map((v) => ({ [VALUE]: v }));\n})();\n\n// Plot: reads only data and the constants above\nconst ts = data.map((d) => d[VALUE]);\nconst N = ts.length;\n\nconst mu = ts.reduce((a, b) => a + b, 0) / N;\nconst cx = ts.map((x) => x - mu);\nconst c0 = cx.reduce((s, v) => s + v * v, 0) / N;\n\n// Sample ACF for lags 0..MAX_LAG\nconst rho: number[] = [];\nfor (let h = 0; h <= MAX_LAG; h += 1) {\n  let s = 0;\n  for (let i = h; i < N; i += 1) s += cx[i] * cx[i - h];\n  rho.push(s / (N * c0));\n}\n\n// PACF via the Durbin–Levinson recursion\nconst pacf = [1, rho[1]];\nlet phi = [rho[1]];\nfor (let k = 2; k <= MAX_LAG; k += 1) {\n  let num = rho[k];\n  let den = 1;\n  for (let j = 0; j < k - 1; j += 1) {\n    num -= phi[j] * rho[k - 1 - j];\n    den -= phi[j] * rho[j + 1];\n  }\n  const pkk = den !== 0 ? num / den : 0;\n  pacf.push(pkk);\n  const next = Array(k).fill(0);\n  next[k - 1] = pkk;\n  for (let j = 0; j < k - 1; j += 1) next[j] = phi[j] - pkk * phi[k - 2 - j];\n  phi = next;\n}\n\n// 95% CI: +/- 1.96 / sqrt(N)\nconst CI = 1.96 / Math.sqrt(N);\n\nconst round4 = (v: number) => Math.round(v * 10000) / 10000;\n\n// Share the exact 0..MAX_LAG axis across both panels so every lag lines up\n// vertically; PACF starts at lag 1 (null at lag 0).\nconst sharedLags = Array.from({ length: MAX_LAG + 1 }, (_, i) => String(i));\nconst acfData = rho.map(round4);\nconst pacfData: (number | null)[] = [null, ...pacf.slice(1).map(round4)];\n\n// Each panel's y range covers its bars and the +/- CI band, padded by Y_PAD.\nconst acfLo = Math.min(-CI, ...acfData);\nconst acfHi = Math.max(CI, ...acfData);\nconst acfLimits = { min: acfLo - Y_PAD * (acfHi - acfLo), max: acfHi + Y_PAD * (acfHi - acfLo) };\nconst pacfVals = pacfData.filter((v): v is number => v != null);\nconst pacfLo = Math.min(-CI, ...pacfVals);\nconst pacfHi = Math.max(CI, ...pacfVals);\nconst pacfLimits = { min: pacfLo - Y_PAD * (pacfHi - pacfLo), max: pacfHi + Y_PAD * (pacfHi - pacfLo) };\n\nexport default function Chart() {\n  const W = window.ANYPLOT_SIZE.width;\n  const H = window.ANYPLOT_SIZE.height;\n\n  const TITLE_H = 54;\n  const PANEL_H = Math.floor((H - TITLE_H - 6) / 2);\n\n  const barColor = t.palette[0];\n\n  const ciLineStyle = {\n    stroke: t.inkSoft,\n    strokeDasharray: \"7 4\",\n    strokeWidth: 1.5,\n    strokeOpacity: 0.85,\n  };\n\n  const zeroLineStyle = {\n    stroke: t.inkSoft,\n    strokeWidth: 0.9,\n    strokeOpacity: 0.55,\n  };\n\n  const tickStyle = { fontSize: 14, fill: t.inkSoft };\n  const labelStyle = { fontSize: 15, fill: t.ink };\n\n  const axisLineSx = {\n    \"& .MuiChartsAxis-line\": { stroke: t.inkSoft },\n    \"& .MuiChartsAxis-tick\": { stroke: t.inkSoft },\n  };\n\n  const xAxisBase = {\n    scaleType: \"band\" as const,\n    categoryGapRatio: 0.9,\n    tickLabelStyle: tickStyle,\n  };\n\n  const yAxisBase = {\n    width: 72,\n    tickMinStep: 0.25,\n    tickLabelStyle: tickStyle,\n    labelStyle,\n  };\n\n  return (\n    <div\n      style={{\n        width: W,\n        height: H,\n        background: t.pageBg,\n        display: \"flex\",\n        flexDirection: \"column\",\n        fontFamily: \"'Roboto', 'Helvetica Neue', Arial, sans-serif\",\n      }}\n    >\n      <div\n        style={{\n          height: TITLE_H,\n          display: \"flex\",\n          alignItems: \"center\",\n          justifyContent: \"center\",\n          fontSize: 22,\n          fontWeight: 600,\n          color: t.ink,\n          letterSpacing: 0.15,\n        }}\n      >\n        Daily Temperature Anomaly · acf-pacf · javascript · muix · anyplot.ai\n      </div>\n\n      {/* ACF panel */}\n      <div style={{ height: PANEL_H, flexShrink: 0 }}>\n        <BarChart\n          width={W}\n          height={PANEL_H}\n          skipAnimation\n          disableHitArea\n          hideLegend\n          colors={[barColor]}\n          xAxis={[{ ...xAxisBase, height: 36, data: sharedLags }]}\n          yAxis={[{ ...yAxisBase, label: \"ACF\", ...acfLimits }]}\n          series={[{ data: acfData, label: \"ACF\" }]}\n          margin={{ top: 18, bottom: 12, left: 60, right: 65 }}\n          sx={axisLineSx}\n        >\n          <ChartsReferenceLine\n            y={CI}\n            lineStyle={ciLineStyle}\n            label=\"95% CI\"\n            labelStyle={{ fontSize: 11, fill: t.inkSoft }}\n            labelAlign=\"end\"\n          />\n          <ChartsReferenceLine y={-CI} lineStyle={ciLineStyle} />\n          <ChartsReferenceLine y={0} lineStyle={zeroLineStyle} />\n        </BarChart>\n      </div>\n\n      {/* PACF panel */}\n      <div style={{ flex: 1 }}>\n        <BarChart\n          width={W}\n          height={PANEL_H}\n          skipAnimation\n          disableHitArea\n          hideLegend\n          colors={[barColor]}\n          xAxis={[\n            {\n              ...xAxisBase,\n              height: 54,\n              data: sharedLags,\n              label: \"Lag\",\n              labelStyle,\n            },\n          ]}\n          yAxis={[{ ...yAxisBase, label: \"PACF\", ...pacfLimits }]}\n          series={[{ data: pacfData, label: \"PACF\" }]}\n          margin={{ top: 12, bottom: 20, left: 60, right: 65 }}\n          sx={axisLineSx}\n        >\n          <ChartsReferenceLine y={CI} lineStyle={ciLineStyle} />\n          <ChartsReferenceLine y={-CI} lineStyle={ciLineStyle} />\n          <ChartsReferenceLine y={0} lineStyle={zeroLineStyle} />\n        </BarChart>\n      </div>\n    </div>\n  );\n}\n"}