{"spec_id":"acf-pacf","library":"plotnine","language":"python","code":"\"\"\" anyplot.ai\nacf-pacf: Autocorrelation and Partial Autocorrelation (ACF/PACF) Plot\nLibrary: plotnine 0.15.5 | Python 3.13.13\nQuality: 91/100 | Updated: 2026-06-10\n\"\"\"\n\nimport os\nimport sys\n\nimport numpy as np\nimport pandas as pd\n\n\n# Work around naming conflict with plotnine.py script and plotnine package\nscript_dir = os.path.dirname(os.path.abspath(__file__))\nif script_dir in sys.path:\n    sys.path.remove(script_dir)\nif \"\" in sys.path:\n    sys.path.remove(\"\")\nif \".\" in sys.path:\n    sys.path.remove(\".\")\n\nfrom plotnine import (\n    aes,\n    element_blank,\n    element_line,\n    element_rect,\n    element_text,\n    facet_wrap,\n    geom_hline,\n    geom_point,\n    geom_segment,\n    geom_vline,\n    ggplot,\n    guides,\n    labs,\n    scale_color_manual,\n    scale_x_continuous,\n    scale_y_continuous,\n    theme,\n    theme_minimal,\n)\nfrom statsmodels.tsa.stattools import acf, pacf\n\n\n# Theme tokens — Imprint palette, theme-adaptive chrome\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\"\n\n# Imprint palette positions used\nBRAND = \"#009E73\"  # position 1 — significant lags (brand green, first series)\nALARM = \"#AE3030\"  # position 5 — confidence bounds (semantic: alert/threshold)\n\n# Data — simulated monthly temperature with seasonality and AR(1) component\nnp.random.seed(42)\nn_obs = 240\ntime = np.arange(n_obs)\nseasonal = 12 * np.sin(2 * np.pi * time / 12) + 4 * np.cos(2 * np.pi * time / 6)\nar_component = np.zeros(n_obs)\nfor t in range(1, n_obs):\n    ar_component[t] = 0.4 * ar_component[t - 1] + np.random.normal(0, 2)\ntemperature = seasonal + ar_component\n\n# Compute ACF and PACF\nn_lags = 36\nacf_values = acf(temperature, nlags=n_lags, fft=True)\npacf_values = pacf(temperature, nlags=n_lags, method=\"ywm\")\nconfidence_bound = 1.96 / np.sqrt(n_obs)\n\n# Build long-format DataFrame for faceting\nacf_df = pd.DataFrame({\"lag\": np.arange(len(acf_values)), \"correlation\": acf_values, \"panel\": \"ACF\"})\npacf_df = pd.DataFrame({\"lag\": np.arange(1, len(pacf_values)), \"correlation\": pacf_values[1:], \"panel\": \"PACF\"})\ndf = pd.concat([acf_df, pacf_df], ignore_index=True)\ndf[\"panel\"] = pd.Categorical(df[\"panel\"], categories=[\"ACF\", \"PACF\"], ordered=True)\n\n# Mark significance: lags outside confidence bounds\ndf[\"significant\"] = np.where(np.abs(df[\"correlation\"]) > confidence_bound, \"Significant\", \"Non-significant\")\n# Lag 0 in ACF is always 1.0 by definition — not a meaningful significant lag\ndf.loc[(df[\"panel\"] == \"ACF\") & (df[\"lag\"] == 0), \"significant\"] = \"Non-significant\"\n\n# Seasonal lag markers restricted to ACF panel — period-12 structure at lags 12, 24, 36\nseasonal_ann_df = pd.DataFrame(\n    {\n        \"xintercept\": [12, 24, 36],\n        \"panel\": pd.Categorical([\"ACF\", \"ACF\", \"ACF\"], categories=[\"ACF\", \"PACF\"], ordered=True),\n    }\n)\n\n# Title — 41 chars, within 67-char baseline, no font scaling needed\ntitle = \"acf-pacf · python · plotnine · anyplot.ai\"\n\n# Plot — strip labels \"ACF\" / \"PACF\" serve as per-panel y-axis identifiers per spec\nplot = (\n    ggplot(df, aes(x=\"lag\", y=\"correlation\", color=\"significant\"))\n    + geom_hline(yintercept=0, color=INK_SOFT, size=0.6, alpha=0.8)\n    + geom_vline(\n        data=seasonal_ann_df, mapping=aes(xintercept=\"xintercept\"), color=BRAND, alpha=0.14, size=0.8, linetype=\"dotted\"\n    )\n    + geom_hline(yintercept=confidence_bound, linetype=\"dashed\", color=ALARM, size=0.7, alpha=0.65)\n    + geom_hline(yintercept=-confidence_bound, linetype=\"dashed\", color=ALARM, size=0.7, alpha=0.65)\n    + geom_segment(aes(x=\"lag\", xend=\"lag\", y=0, yend=\"correlation\"), size=1.2)\n    + geom_point(size=3.0)\n    + scale_color_manual(values={\"Significant\": BRAND, \"Non-significant\": INK_MUTED})\n    + guides(color=\"none\")\n    + facet_wrap(\"~panel\", ncol=1, scales=\"free_y\")\n    + scale_x_continuous(breaks=list(range(0, n_lags + 1, 6)))\n    + scale_y_continuous(expand=(0.04, 0))\n    + labs(x=\"Lag\", y=\"\", title=title)\n    + theme_minimal()\n    + theme(\n        figure_size=(8, 4.5),\n        plot_background=element_rect(fill=PAGE_BG, color=PAGE_BG),\n        panel_background=element_rect(fill=PAGE_BG),\n        panel_grid_major_x=element_blank(),\n        panel_grid_minor_x=element_blank(),\n        panel_grid_major_y=element_line(color=INK, size=0.2, alpha=0.12),\n        panel_grid_minor_y=element_blank(),\n        axis_title_x=element_text(color=INK, size=10),\n        axis_title_y=element_blank(),\n        axis_text=element_text(color=INK_SOFT, size=8),\n        plot_title=element_text(color=INK, size=12, face=\"bold\"),\n        strip_background=element_rect(fill=PAGE_BG, color=\"none\"),\n        strip_text=element_text(color=INK, size=10, face=\"bold\"),\n        panel_spacing_y=0.08,\n    )\n)\n\n# Save — canvas: 8×4.5 in × 400 dpi = 3200×1800 px\nplot.save(f\"plot-{THEME}.png\", dpi=400, width=8, height=4.5, units=\"in\", verbose=False)\n"}