{"spec_id":"qq-basic","library":"makie","language":"julia","code":"# anyplot.ai\n# qq-basic: Basic Q-Q Plot\n# Library: makie 0.21.9 | Julia 1.11.9\n# Quality: 89/100 | Created: 2026-07-24\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 ELEVATED_BG = THEME == \"light\" ? colorant\"#FFFDF6\" : colorant\"#242420\"\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# --- Standard normal quantile (inverse CDF), Acklam's rational approximation --\nfunction norm_quantile(p)\n    a = (-3.969683028665376e+01, 2.209460984245205e+02, -2.759285104469687e+02,\n        1.383577518672690e+02, -3.066479806614716e+01, 2.506628277459239e+00)\n    b = (-5.447609879822406e+01, 1.615858368580409e+02, -1.556989798598866e+02,\n        6.680131188771972e+01, -1.328068155288572e+01)\n    c = (-7.784894002430293e-03, -3.223964580411365e-01, -2.400758277161838e+00,\n        -2.549732539343734e+00, 4.374664141464968e+00, 2.938163982698783e+00)\n    d = (7.784695709041462e-03, 3.224671290700398e-01, 2.445134137142996e+00,\n        3.754408661907416e+00)\n    p_low = 0.02425\n    p_high = 1 - p_low\n    if p < p_low\n        q = sqrt(-2 * log(p))\n        return (((((c[1] * q + c[2]) * q + c[3]) * q + c[4]) * q + c[5]) * q + c[6]) /\n               ((((d[1] * q + d[2]) * q + d[3]) * q + d[4]) * q + 1)\n    elseif p <= p_high\n        q = p - 0.5\n        r = q * q\n        return (((((a[1] * r + a[2]) * r + a[3]) * r + a[4]) * r + a[5]) * r + a[6]) * q /\n               (((((b[1] * r + b[2]) * r + b[3]) * r + b[4]) * r + b[5]) * r + 1)\n    else\n        q = sqrt(-2 * log(1 - p))\n        return -(((((c[1] * q + c[2]) * q + c[3]) * q + c[4]) * q + c[5]) * q + c[6]) /\n               ((((d[1] * q + d[2]) * q + d[3]) * q + d[4]) * q + 1)\n    end\nend\n\n# --- Data ----------------------------------------------------------------\n# Reaction times (ms) from a simple cognitive task. Response-time data is\n# classically right-skewed, giving the Q-Q plot a clear upward curve away\n# from the reference line at the high end — a textbook normality check.\nn = 180\nz = randn(n)\nreaction_times_ms = 320.0 .+ 70.0 .* z .+ 18.0 .* z .^ 2\n\nsample_q = sort(reaction_times_ms)\nmu, sigma = mean(sample_q), std(sample_q)\nplot_pos = ((1:n) .- 0.5) ./ n\ntheoretical_q = mu .+ sigma .* norm_quantile.(plot_pos)\n\nlo = min(minimum(theoretical_q), minimum(sample_q))\nhi = max(maximum(theoretical_q), maximum(sample_q))\nresidual_ms = sample_q .- theoretical_q\n\n# --- Plot ------------------------------------------------------------------\ntitle_str = \"qq-basic · julia · makie · anyplot.ai\"\n\nfig = Figure(size = (1600, 900), fontsize = 14, backgroundcolor = PAGE_BG)\n\nax = Axis(\n    fig[1, 1];\n    title             = title_str,\n    titlesize         = 24,\n    titlecolor        = INK,\n    xlabel            = \"Theoretical Quantiles (ms)\",\n    ylabel            = \"Sample Quantiles (ms)\",\n    xlabelsize        = 14,\n    ylabelsize        = 14,\n    xticklabelsize    = 12,\n    yticklabelsize    = 12,\n    xlabelcolor       = INK,\n    ylabelcolor       = INK,\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    xgridcolor        = RGBAf(INK.r, INK.g, INK.b, 0.15),\n    ygridcolor        = RGBAf(INK.r, INK.g, INK.b, 0.15),\n    xminorgridvisible = false,\n    yminorgridvisible = false,\n)\n\nlines!(ax, [lo, hi], [lo, hi]; color = INK_SOFT, linewidth = 2.0, linestyle = :dash)\nscatter!(ax, theoretical_q, sample_q;\n    color = (IMPRINT_PALETTE[1], 0.85), markersize = 10, strokewidth = 1.0, strokecolor = PAGE_BG)\n\n# --- Residual inset: a Makie-native nested Axis sharing the same grid cell,\n# positioned in the corner farthest from the diagonal band, to show the\n# skew signature (sample - theoretical) as a companion diagnostic panel.\nax_inset = Axis(\n    fig[1, 1];\n    width             = Relative(0.30),\n    height            = Relative(0.30),\n    halign            = 1.0,\n    valign            = 0.14,\n    title             = \"Residuals\",\n    titlesize         = 12,\n    titlecolor        = INK,\n    xlabel            = \"Theoretical Q. (ms)\",\n    ylabel            = \"Residual (ms)\",\n    xlabelsize        = 9,\n    ylabelsize        = 9,\n    xticklabelsize    = 8,\n    yticklabelsize    = 8,\n    xlabelcolor       = INK,\n    ylabelcolor       = INK,\n    xticklabelcolor   = INK_SOFT,\n    yticklabelcolor   = INK_SOFT,\n    xtickcolor        = INK_SOFT,\n    ytickcolor        = INK_SOFT,\n    backgroundcolor   = ELEVATED_BG,\n    topspinevisible   = false,\n    rightspinevisible = false,\n    leftspinecolor    = INK_SOFT,\n    bottomspinecolor  = INK_SOFT,\n    xgridcolor        = RGBAf(INK.r, INK.g, INK.b, 0.15),\n    ygridcolor        = RGBAf(INK.r, INK.g, INK.b, 0.15),\n    xminorgridvisible = false,\n    yminorgridvisible = false,\n)\n\nhlines!(ax_inset, [0.0]; color = INK_SOFT, linewidth = 1.5, linestyle = :dash)\nscatter!(ax_inset, theoretical_q, residual_ms;\n    color = (IMPRINT_PALETTE[1], 0.85), markersize = 6, strokewidth = 0.5, strokecolor = ELEVATED_BG)\n\n# --- Save --------------------------------------------------------------------\nsave(\"plot-$(THEME).png\", fig; px_per_unit = 2)\n"}