{"spec_id":"qq-basic","library":"plotly","language":"python","code":"\"\"\" anyplot.ai\nqq-basic: Basic Q-Q Plot\nLibrary: plotly 6.9.0 | Python 3.13.14\nQuality: 90/100 | Updated: 2026-07-24\n\"\"\"\n\nimport os\n\nimport numpy as np\nimport plotly.graph_objects as go\n\n\n# Theme tokens (see prompts/default-style-guide.md \"Background\" + \"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\"\nGRID = \"rgba(26,26,23,0.10)\" if THEME == \"light\" else \"rgba(240,239,232,0.10)\"\n\nBRAND = \"#009E73\"  # Imprint palette position 1 — Q-Q scatter points\nREF_COLOR = INK  # Imprint semantic anchor \"neutral\" — reference line (baseline role)\nBAND_COLOR = INK_MUTED  # Imprint semantic anchor \"muted\" — confidence envelope\n\n# Data - sample with slight positive skew to demonstrate Q-Q plot interpretation\nnp.random.seed(42)\nsample = np.concatenate(\n    [\n        np.random.normal(50, 10, 80),  # Main normal distribution\n        np.random.normal(75, 5, 20),  # Slight right tail for interest\n    ]\n)\nsample = np.sort(sample)\n\n# Standardize sample for comparison with standard normal\nsample_standardized = (sample - np.mean(sample)) / np.std(sample)\n\n# Theoretical quantiles via Blom's plotting positions + Winitzki erfinv approximation\nn = len(sample)\nprobabilities = (np.arange(1, n + 1) - 0.375) / (n + 0.25)\nq = 2 * probabilities - 1  # map to [-1, 1] for erfinv\na = 0.147\nln1q2 = np.log(1 - q**2)\nb = 2 / (np.pi * a) + ln1q2 / 2\ntheoretical_quantiles = np.sign(q) * np.sqrt(2) * np.sqrt(np.sqrt(b**2 - ln1q2 / a) - b)\n\n# 95% confidence envelope from the asymptotic variance of normal order statistics\nnormal_density = np.exp(-(theoretical_quantiles**2) / 2) / np.sqrt(2 * np.pi)\nband_half_width = 1.96 * np.sqrt(probabilities * (1 - probabilities) / n) / normal_density\n\n# Reference line (y=x for standardized data)\nmargin = 0.3\nline_min = min(theoretical_quantiles.min(), sample_standardized.min()) - margin\nline_max = max(theoretical_quantiles.max(), sample_standardized.max()) + margin\n\n# Plot\nfig = go.Figure()\n\nfig.add_trace(\n    go.Scatter(\n        x=np.concatenate([theoretical_quantiles, theoretical_quantiles[::-1]]),\n        y=np.concatenate([theoretical_quantiles + band_half_width, (theoretical_quantiles - band_half_width)[::-1]]),\n        fill=\"toself\",\n        fillcolor=BAND_COLOR,\n        opacity=0.15,\n        line={\"width\": 0},\n        name=\"95% Confidence Band\",\n        hovertemplate=\"Theoretical: %{x:.3f}<br>Band Edge: %{y:.3f}<extra></extra>\",\n        legendrank=3,\n    )\n)\n\nfig.add_trace(\n    go.Scatter(\n        x=[line_min, line_max],\n        y=[line_min, line_max],\n        mode=\"lines\",\n        line={\"color\": REF_COLOR, \"width\": 2.5, \"dash\": \"dash\"},\n        name=\"Reference (y=x)\",\n        hoverinfo=\"skip\",\n        legendrank=2,\n    )\n)\n\nfig.add_trace(\n    go.Scatter(\n        x=theoretical_quantiles,\n        y=sample_standardized,\n        mode=\"markers\",\n        marker={\"size\": 10, \"color\": BRAND, \"opacity\": 0.85},\n        name=\"Sample Quantiles\",\n        hovertemplate=\"Theoretical: %{x:.3f}<br>Sample: %{y:.3f}<extra></extra>\",\n        legendrank=1,\n    )\n)\n\n# Annotate the largest tail deviation from the reference line (|theoretical| > 1.5)\ntail_mask = np.abs(theoretical_quantiles) > 1.5\ndeviation = np.abs(sample_standardized - theoretical_quantiles)\ntail_idx = np.where(tail_mask)[0][np.argmax(deviation[tail_mask])]\nfig.add_annotation(\n    x=theoretical_quantiles[tail_idx],\n    y=sample_standardized[tail_idx],\n    text=\"Right-tail deviation\",\n    showarrow=True,\n    arrowhead=2,\n    arrowcolor=INK_SOFT,\n    ax=-50,\n    ay=-30,\n    font={\"size\": 10, \"color\": INK_SOFT},\n)\n\n# Style\ntitle_text = \"qq-basic · python · plotly · anyplot.ai\"\nfig.update_layout(\n    autosize=False,\n    width=800,\n    height=450,\n    paper_bgcolor=PAGE_BG,\n    plot_bgcolor=PAGE_BG,\n    title={\"text\": title_text, \"font\": {\"size\": 16, \"color\": INK}},\n    xaxis={\n        \"title\": {\"text\": \"Theoretical Quantiles\", \"font\": {\"size\": 12, \"color\": INK}},\n        \"tickfont\": {\"size\": 10, \"color\": INK_SOFT},\n        \"gridcolor\": GRID,\n        \"gridwidth\": 1,\n        \"zeroline\": False,\n        \"showline\": True,\n        \"linewidth\": 1.5,\n        \"linecolor\": INK_SOFT,\n        \"mirror\": False,\n    },\n    yaxis={\n        \"title\": {\"text\": \"Sample Quantiles\", \"font\": {\"size\": 12, \"color\": INK}},\n        \"tickfont\": {\"size\": 10, \"color\": INK_SOFT},\n        \"gridcolor\": GRID,\n        \"gridwidth\": 1,\n        \"zeroline\": False,\n        \"showline\": True,\n        \"linewidth\": 1.5,\n        \"linecolor\": INK_SOFT,\n        \"mirror\": False,\n    },\n    legend={\n        \"bgcolor\": ELEVATED_BG,\n        \"bordercolor\": INK_SOFT,\n        \"borderwidth\": 1,\n        \"font\": {\"size\": 10, \"color\": INK_SOFT},\n        \"x\": 0.02,\n        \"y\": 0.98,\n    },\n    margin={\"l\": 80, \"r\": 40, \"t\": 80, \"b\": 60},\n)\n\n# Save\nfig.write_image(f\"plot-{THEME}.png\", width=800, height=450, scale=4)\nfig.write_html(f\"plot-{THEME}.html\", include_plotlyjs=\"cdn\")\n"}