{"spec_id":"acf-pacf","library":"makie","language":"julia","code":"# anyplot.ai\n# acf-pacf: Autocorrelation and Partial Autocorrelation (ACF/PACF) Plot\n# Library: makie 0.22.10 | Julia 1.11.9\n# Quality: 86/100 | Created: 2026-06-10\n\nusing CairoMakie\nusing Colors\nusing Random\nusing Statistics\n\nRandom.seed!(42)\n\n# Theme tokens\nconst THEME     = get(ENV, \"ANYPLOT_THEME\", \"light\")\nconst PAGE_BG   = THEME == \"light\" ? colorant\"#FAF8F1\" : colorant\"#1A1A17\"\nconst INK       = THEME == \"light\" ? colorant\"#1A1A17\" : colorant\"#F0EFE8\"\nconst INK_SOFT  = THEME == \"light\" ? colorant\"#4A4A44\" : colorant\"#B8B7B0\"\nconst IMPRINT_PALETTE = [\n    colorant\"#009E73\", colorant\"#C475FD\", colorant\"#4467A3\", colorant\"#BD8233\",\n    colorant\"#AE3030\", colorant\"#2ABCCD\", colorant\"#954477\", colorant\"#99B314\",\n]\n\n# Data: AR(2) time series — monthly economic indicator\n# x[t] = 0.7*x[t-1] + 0.2*x[t-2] + noise  (φ₁=0.7, φ₂=0.2)\n# PACF cuts off at lag 2; ACF decays as a mixture of exponentials\nn_obs = 300\nseries = zeros(n_obs)\nseries[1] = randn()\nseries[2] = 0.7 * series[1] + randn()\nfor t in 3:n_obs\n    series[t] = 0.7 * series[t-1] + 0.2 * series[t-2] + randn()\nend\n\n# ACF (lags 0 through max_lag)\nmax_lag = 35\ns_mean = mean(series)\ns_var  = sum((v - s_mean)^2 for v in series) / n_obs\nacf_vals = [sum((series[i] - s_mean) * (series[i-k] - s_mean) for i in (k+1):n_obs) / (n_obs * s_var)\n            for k in 0:max_lag]\n\n# PACF via Levinson-Durbin recursion\nphi       = zeros(max_lag, max_lag)\nphi[1, 1] = acf_vals[2]\npacf_vals = zeros(max_lag)\npacf_vals[1] = phi[1, 1]\nfor k in 2:max_lag\n    numer = acf_vals[k + 1]\n    denom = 1.0\n    for j in 1:(k - 1)\n        numer -= phi[k-1, j] * acf_vals[k - j + 1]\n        denom -= phi[k-1, j] * acf_vals[j + 1]\n    end\n    phi[k, k] = numer / denom\n    for j in 1:(k - 1)\n        phi[k, j] = phi[k-1, j] - phi[k, k] * phi[k-1, k-j]\n    end\n    pacf_vals[k] = phi[k, k]\nend\n\nconf_bound = 1.96 / sqrt(n_obs)\nacf_lags   = Float64.(0:max_lag)\n\n# Build linesegments! data for ACF: interleaved [x_base, x_tip, ...] pairs per segment\nacf_seg_x = vcat([[lag, lag] for lag in acf_lags]...)\nacf_seg_y = vcat([[0.0, v]   for v   in acf_vals]...)\n\n# PACF: split lags into significant (|r| > conf_bound) vs. within-bound for visual hierarchy\npacf_sig_idx = findall(v -> abs(v) > conf_bound, pacf_vals)\npacf_ns_idx  = findall(v -> abs(v) <= conf_bound, pacf_vals)\n\n# Muted variant for non-significant PACF lags (same hue, lower opacity)\nGREEN_FULL  = IMPRINT_PALETTE[1]\nGREEN_MUTED = RGBAf(GREEN_FULL.r, GREEN_FULL.g, GREEN_FULL.b, 0.38f0)\n\nfunction make_segs(idx, vals)\n    xs = vcat([[Float64(i), Float64(i)] for i in idx]...)\n    ys = vcat([[0.0, vals[i]] for i in idx]...)\n    xs, ys\nend\n\n# Figure\nfig = Figure(\n    size            = (1600, 900),\n    fontsize        = 14,\n    backgroundcolor = PAGE_BG,\n)\n\n# ACF axis (top)\nax_acf = Axis(\n    fig[1, 1];\n    title             = \"AR(2) Process · acf-pacf · julia · makie · anyplot.ai\",\n    titlesize         = 20,\n    titlecolor        = INK,\n    ylabel            = \"ACF\",\n    ylabelsize        = 14,\n    ylabelcolor       = INK,\n    xticklabelsize    = 12,\n    yticklabelsize    = 12,\n    xticklabelcolor   = INK_SOFT,\n    yticklabelcolor   = INK_SOFT,\n    xtickcolor        = INK_SOFT,\n    ytickcolor        = INK_SOFT,\n    backgroundcolor   = PAGE_BG,\n    topspinevisible   = false,\n    rightspinevisible = false,\n    leftspinecolor    = INK_SOFT,\n    bottomspinecolor  = INK_SOFT,\n    xgridvisible      = false,\n    ygridvisible      = true,\n    ygridcolor        = RGBAf(INK.r, INK.g, INK.b, 0.12f0),\n)\n\n# PACF axis (bottom)\nax_pacf = Axis(\n    fig[2, 1];\n    xlabel            = \"Lag\",\n    ylabel            = \"PACF\",\n    xlabelsize        = 14,\n    ylabelsize        = 14,\n    xlabelcolor       = INK,\n    ylabelcolor       = INK,\n    xticklabelsize    = 12,\n    yticklabelsize    = 12,\n    xticklabelcolor   = INK_SOFT,\n    yticklabelcolor   = INK_SOFT,\n    xtickcolor        = INK_SOFT,\n    ytickcolor        = INK_SOFT,\n    backgroundcolor   = PAGE_BG,\n    topspinevisible   = false,\n    rightspinevisible = false,\n    leftspinecolor    = INK_SOFT,\n    bottomspinecolor  = INK_SOFT,\n    xgridvisible      = false,\n    ygridvisible      = true,\n    ygridcolor        = RGBAf(INK.r, INK.g, INK.b, 0.12f0),\n)\n\nlinkxaxes!(ax_acf, ax_pacf)\nax_acf.xticklabelsvisible = false\nax_acf.xlabelvisible      = false\n\n# ACF stems, tips, and reference lines\nlinesegments!(ax_acf, acf_seg_x, acf_seg_y;\n    color = GREEN_FULL, linewidth = 2.0)\nscatter!(ax_acf, acf_lags, acf_vals;\n    color = GREEN_FULL, markersize = 8, strokewidth = 0)\nhlines!(ax_acf, [0.0]; color = INK_SOFT, linewidth = 1.0)\nhlines!(ax_acf, [conf_bound, -conf_bound];\n    color = INK_SOFT, linestyle = :dash, linewidth = 1.5)\n\n# PACF: within-bound lags (muted) drawn first, then significant lags on top\nif !isempty(pacf_ns_idx)\n    ns_sx, ns_sy = make_segs(pacf_ns_idx, pacf_vals)\n    linesegments!(ax_pacf, ns_sx, ns_sy; color = GREEN_MUTED, linewidth = 1.5)\n    scatter!(ax_pacf, Float64.(pacf_ns_idx), pacf_vals[pacf_ns_idx];\n        color = GREEN_MUTED, markersize = 7, strokewidth = 0)\nend\nif !isempty(pacf_sig_idx)\n    sig_sx, sig_sy = make_segs(pacf_sig_idx, pacf_vals)\n    linesegments!(ax_pacf, sig_sx, sig_sy; color = GREEN_FULL, linewidth = 2.5)\n    scatter!(ax_pacf, Float64.(pacf_sig_idx), pacf_vals[pacf_sig_idx];\n        color = GREEN_FULL, markersize = 9, strokewidth = 0)\nend\nhlines!(ax_pacf, [0.0]; color = INK_SOFT, linewidth = 1.0)\nhlines!(ax_pacf, [conf_bound, -conf_bound];\n    color = INK_SOFT, linestyle = :dash, linewidth = 1.5)\n\nrowgap!(fig.layout, 1, 20)\n\nsave(\"plot-$(THEME).png\", fig; px_per_unit = 2)\n"}