{"spec_id":"acf-pacf","library":"matplotlib","language":"python","code":"\"\"\" anyplot.ai\nacf-pacf: Autocorrelation and Partial Autocorrelation (ACF/PACF) Plot\nLibrary: matplotlib 3.10.9 | Python 3.13.13\nQuality: 92/100 | Updated: 2026-06-10\n\"\"\"\n\nimport os\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom matplotlib.collections import LineCollection\nfrom matplotlib.lines import Line2D\nfrom statsmodels.tsa.stattools import acf, pacf\n\n\n# Theme tokens (Imprint palette — see prompts/default-style-guide.md)\nTHEME = os.getenv(\"ANYPLOT_THEME\", \"light\")\nPAGE_BG = \"#FAF8F1\" if THEME == \"light\" else \"#1A1A17\"\nELEVATED_BG = \"#FFFDF6\" if THEME == \"light\" else \"#242420\"\nINK = \"#1A1A17\" if THEME == \"light\" else \"#F0EFE8\"\nINK_SOFT = \"#4A4A44\" if THEME == \"light\" else \"#B8B7B0\"\nINK_MUTED = \"#6B6A63\" if THEME == \"light\" else \"#A8A79F\"\nBRAND = \"#009E73\"  # Imprint position 1 — significant lags\n\n# Data — synthetic monthly airline-style passenger counts with trend + seasonality\nnp.random.seed(42)\nn_obs = 200\nt = np.arange(n_obs)\npassengers = 100 + 0.5 * t + 30 * np.sin(2 * np.pi * t / 12) + np.random.normal(0, 8, n_obs)\n\n# Compute ACF and PACF\nn_lags = 36\nacf_values, _ = acf(passengers, nlags=n_lags, alpha=0.05)\npacf_values, _ = pacf(passengers, nlags=n_lags, alpha=0.05)\n\nacf_lags = np.arange(len(acf_values))\npacf_lags = np.arange(1, len(pacf_values))\n\n# 95% confidence bound\nconfidence_bound = 1.96 / np.sqrt(n_obs)\n\n# Classify significance\nacf_sig = np.abs(acf_values) > confidence_bound\npacf_sig = np.abs(pacf_values[1:]) > confidence_bound\n\n# Title — 43 chars < 67 baseline, no scaling needed\ntitle = \"acf-pacf · python · matplotlib · anyplot.ai\"\ntitle_fontsize = 12\n\n# Plot — landscape 3200 × 1800 px (figsize=(8, 4.5) × dpi=400)\nfig, (ax1, ax2) = plt.subplots(2, 1, figsize=(8, 4.5), dpi=400, sharex=True, facecolor=PAGE_BG)\nax1.set_facecolor(PAGE_BG)\nax2.set_facecolor(PAGE_BG)\n\n# --- ACF (top subplot) ---\nacf_colors = [BRAND if s else INK_MUTED for s in acf_sig]\nacf_segments = [[(lag, 0), (lag, val)] for lag, val in zip(acf_lags, acf_values, strict=False)]\nax1.add_collection(LineCollection(acf_segments, colors=acf_colors, linewidths=2.5, zorder=3))\n\nif acf_sig.any():\n    ax1.scatter(acf_lags[acf_sig], acf_values[acf_sig], color=BRAND, s=48, zorder=5, edgecolors=PAGE_BG, linewidths=0.6)\nif (~acf_sig).any():\n    ax1.scatter(\n        acf_lags[~acf_sig], acf_values[~acf_sig], color=INK_MUTED, s=34, zorder=5, edgecolors=PAGE_BG, linewidths=0.5\n    )\n\nax1.axhline(y=0, color=INK_SOFT, linewidth=0.6, zorder=2)\nax1.axhline(y=confidence_bound, color=INK_SOFT, linestyle=\"--\", linewidth=1.2, alpha=0.7)\nax1.axhline(y=-confidence_bound, color=INK_SOFT, linestyle=\"--\", linewidth=1.2, alpha=0.7)\nx_fill = np.array([-1, n_lags + 1], dtype=float)\nax1.fill_between(x_fill, -confidence_bound, confidence_bound, color=INK_SOFT, alpha=0.07, zorder=1)\n\n# Annotation — 12-month seasonal spike (genuine insight, not decorative)\nax1.annotate(\n    \"12-month\\nseasonal cycle\",\n    xy=(12, acf_values[12]),\n    xytext=(20, acf_values[12] + 0.20),\n    fontsize=8,\n    fontweight=\"medium\",\n    color=BRAND,\n    arrowprops={\"arrowstyle\": \"->\", \"color\": BRAND, \"lw\": 1.2, \"connectionstyle\": \"arc3,rad=-0.2\"},\n    ha=\"center\",\n    va=\"bottom\",\n    zorder=6,\n)\n\nax1.set_ylabel(\"ACF\", fontsize=10, fontweight=\"medium\", color=INK, labelpad=8)\nax1.tick_params(axis=\"both\", labelsize=8, colors=INK_SOFT, labelcolor=INK_SOFT)\nax1.spines[\"top\"].set_visible(False)\nax1.spines[\"right\"].set_visible(False)\nfor spine in (\"left\", \"bottom\"):\n    ax1.spines[spine].set_color(INK_SOFT)\n    ax1.spines[spine].set_linewidth(0.6)\nax1.yaxis.grid(True, alpha=0.15, linewidth=0.6, color=INK)\nax1.set_xlim(-0.8, n_lags + 0.8)\nax1.margins(y=0.12)\n\n# Legend for significant / insignificant distinction\nlegend_handles = [\n    Line2D(\n        [0],\n        [0],\n        marker=\"o\",\n        color=\"none\",\n        markerfacecolor=BRAND,\n        markeredgecolor=PAGE_BG,\n        markersize=6,\n        label=\"Significant\",\n    ),\n    Line2D(\n        [0],\n        [0],\n        marker=\"o\",\n        color=\"none\",\n        markerfacecolor=INK_MUTED,\n        markeredgecolor=PAGE_BG,\n        markersize=5,\n        label=\"Insignificant\",\n    ),\n]\nleg = ax1.legend(handles=legend_handles, fontsize=8, loc=\"upper right\", framealpha=0.9, edgecolor=INK_SOFT)\nleg.get_frame().set_facecolor(ELEVATED_BG)\nleg.get_frame().set_edgecolor(INK_SOFT)\nplt.setp(leg.get_texts(), color=INK_SOFT)\n\n# --- PACF (bottom subplot) — starts from lag 1 ---\npacf_vals = pacf_values[1:]\npacf_colors = [BRAND if s else INK_MUTED for s in pacf_sig]\npacf_segments = [[(lag, 0), (lag, val)] for lag, val in zip(pacf_lags, pacf_vals, strict=False)]\nax2.add_collection(LineCollection(pacf_segments, colors=pacf_colors, linewidths=2.5, zorder=3))\n\nif pacf_sig.any():\n    ax2.scatter(\n        pacf_lags[pacf_sig], pacf_vals[pacf_sig], color=BRAND, s=48, zorder=5, edgecolors=PAGE_BG, linewidths=0.6\n    )\nif (~pacf_sig).any():\n    ax2.scatter(\n        pacf_lags[~pacf_sig], pacf_vals[~pacf_sig], color=INK_MUTED, s=34, zorder=5, edgecolors=PAGE_BG, linewidths=0.5\n    )\n\nax2.axhline(y=0, color=INK_SOFT, linewidth=0.6, zorder=2)\nax2.axhline(y=confidence_bound, color=INK_SOFT, linestyle=\"--\", linewidth=1.2, alpha=0.7)\nax2.axhline(y=-confidence_bound, color=INK_SOFT, linestyle=\"--\", linewidth=1.2, alpha=0.7)\nax2.fill_between(x_fill, -confidence_bound, confidence_bound, color=INK_SOFT, alpha=0.07, zorder=1)\n\nax2.set_ylabel(\"PACF\", fontsize=10, fontweight=\"medium\", color=INK, labelpad=8)\nax2.set_xlabel(\"Lag\", fontsize=10, fontweight=\"medium\", color=INK, labelpad=6)\nax2.tick_params(axis=\"both\", labelsize=8, colors=INK_SOFT, labelcolor=INK_SOFT)\nax2.tick_params(axis=\"x\", which=\"both\", bottom=True)\nax2.spines[\"top\"].set_visible(False)\nax2.spines[\"right\"].set_visible(False)\nfor spine in (\"left\", \"bottom\"):\n    ax2.spines[spine].set_color(INK_SOFT)\n    ax2.spines[spine].set_linewidth(0.6)\nax2.yaxis.grid(True, alpha=0.15, linewidth=0.6, color=INK)\nax2.margins(y=0.12)\n\n# Title and layout\nfig.suptitle(title, fontsize=title_fontsize, fontweight=\"medium\", color=INK, y=0.98)\nfig.subplots_adjust(top=0.91, bottom=0.11, left=0.09, right=0.97, hspace=0.18)\n\n# Save — bbox_inches must stay default (None) to preserve exact 3200×1800 canvas\nplt.savefig(f\"plot-{THEME}.png\", dpi=400, facecolor=PAGE_BG)\n"}