{"spec_id":"pp-basic","library":"pygal","language":"python","code":"\"\"\" anyplot.ai\npp-basic: Probability-Probability (P-P) Plot\nLibrary: pygal 3.1.0 | Python 3.13.13\nQuality: 92/100 | Updated: 2026-06-16\n\"\"\"\n\nimport math\nimport os\nimport sys\n\n\n# This file is named pygal.py, which shadows the installed `pygal` package when\n# run as `python pygal.py`; dropping the script directory from sys.path lets the\n# real package resolve.\nsys.path.pop(0)\n\nimport numpy as np\nimport pygal\nfrom pygal.style import Style\n\n\n# Theme tokens (see prompts/default-style-guide.md \"Theme-adaptive Chrome\")\nTHEME = os.getenv(\"ANYPLOT_THEME\", \"light\")\nPAGE_BG = \"#FAF8F1\" if THEME == \"light\" else \"#1A1A17\"\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 anchors used here — severity tiers map to semantic colors:\n# good/pass -> brand green (also the mandatory first categorical series),\n# warning -> amber, bad/error -> matte red. CVD-safe and clearly separable.\nBRAND_GREEN = \"#009E73\"  # Imprint position 1 — first categorical series\nIMPRINT_AMBER = \"#DDCC77\"  # warning / caution anchor\nIMPRINT_RED = \"#AE3030\"  # bad / error anchor (Imprint position 5)\nNEUTRAL = INK  # reference line — structural \"neutral\" anchor (theme-adaptive)\n\n# Data — quality-control scenario: 200 tensile-strength measurements (MPa) from\n# steel rods. A compliant production run (normal) mixed with a heat-treatment\n# drift batch (skewed) so the data departs from pure normality.\nnp.random.seed(42)\ncompliant = np.random.normal(520, 35, 160)\nanomalous = np.random.exponential(30, 40) + 480\nobserved = np.sort(np.concatenate([compliant, anomalous]))\nn = len(observed)\n\n# Fit normal parameters from the full sample\nmu = np.mean(observed)\nsigma = np.std(observed, ddof=1)\n\n# Empirical CDF using plotting position i/(n+1)\nempirical_cdf = np.arange(1, n + 1) / (n + 1)\n\n# Theoretical CDF: Phi((x - mu) / sigma)\nsqrt2 = math.sqrt(2)\ntheoretical_cdf = np.array([0.5 * (1.0 + math.erf((x - mu) / (sigma * sqrt2))) for x in observed])\n\n# Deviation from perfect fit — drives the three-tier visual hierarchy\ndeviation = empirical_cdf - theoretical_cdf\n\ngood_fit = []  # |Δ| ≤ 0.01 — tightly along the diagonal\nmild_dev = []  # 0.01 < |Δ| ≤ 0.025 — moderate departure\nstrong_dev = []  # |Δ| > 0.025 — clear distributional mismatch\n\nfor i in range(n):\n    t = float(theoretical_cdf[i])\n    e = float(empirical_cdf[i])\n    d = float(deviation[i])\n    label = \"#{} · {:.0f} MPa · Δ = {:+.3f}\".format(i + 1, observed[i], d)\n    point = {\"value\": (t, e), \"label\": label}\n    if abs(d) <= 0.01:\n        good_fit.append(point)\n    elif abs(d) <= 0.025:\n        mild_dev.append(point)\n    else:\n        strong_dev.append(point)\n\n# Style — pygal Style carries every theme token. Font sizes are unitless source\n# pixels (see default-style-guide.md \"Why the Native-pixel numbers look bigger\").\ncustom_style = Style(\n    background=PAGE_BG,\n    plot_background=PAGE_BG,\n    foreground=INK,  # primary text\n    foreground_strong=INK,  # title\n    foreground_subtle=INK_MUTED,  # tick labels / grid tone\n    opacity=\".78\",\n    opacity_hover=\"1\",\n    transition=\"120ms ease-in\",\n    # Color cycle follows add() order: reference line, good, mild, strong.\n    colors=(NEUTRAL, BRAND_GREEN, IMPRINT_AMBER, IMPRINT_RED),\n    value_colors=(),\n    title_font_size=66,\n    label_font_size=56,\n    major_label_font_size=44,\n    legend_font_size=44,\n    value_font_size=36,\n    tooltip_font_size=34,\n    stroke_width=2.5,\n    guide_stroke_color=INK_MUTED,\n    major_guide_stroke_color=INK_MUTED,\n    font_family=\"Helvetica Neue, Helvetica, Arial, sans-serif\",\n    tooltip_border_radius=8,\n)\n\n# Square canvas (2400×2400) preserves the meaning of the 45° diagonal\nchart = pygal.XY(\n    width=2400,\n    height=2400,\n    style=custom_style,\n    title=\"pp-basic · python · pygal · anyplot.ai\",\n    x_title=\"Theoretical CDF  (fitted Normal)\",\n    y_title=\"Empirical CDF  (steel-rod tensile strength)\",\n    show_legend=True,\n    legend_at_bottom=True,\n    legend_box_size=28,\n    stroke=False,\n    show_x_guides=True,\n    show_y_guides=True,\n    xrange=(0, 1),\n    range=(0, 1),\n    x_labels=[0, 0.2, 0.4, 0.6, 0.8, 1.0],\n    y_labels=[0, 0.2, 0.4, 0.6, 0.8, 1.0],\n    print_values=False,\n    tooltip_fancy_mode=True,\n    explicit_size=True,\n    margin_bottom=40,\n    margin_top=30,\n    margin_left=30,\n    margin_right=40,\n    truncate_legend=-1,\n)\n\n# 45° reference line — perfect distributional fit (neutral anchor), drawn first\n# and dashed so the data points sit on top of it.\nchart.add(\n    \"Perfect Normal fit  (y = x)\",\n    [(0, 0), (0.5, 0.5), (1, 1)],\n    stroke=True,\n    show_dots=False,\n    dots_size=0,\n    stroke_dasharray=\"16, 10\",\n    stroke_style={\"width\": 5, \"linecap\": \"round\"},\n    formatter=lambda x, y: \"Reference: y = x\",\n)\n\n# Three severity tiers — graduated dot sizes amplify the color hierarchy. The\n# dense good-fit band uses the smallest dots to de-clutter the diagonal while\n# the sparse strong-deviation points stay large and focal.\nchart.add(\"Good fit  |Δ| ≤ 0.01  ({})\".format(len(good_fit)), good_fit, dots_size=7)\nchart.add(\"Mild dev  |Δ| ≤ 0.025  ({})\".format(len(mild_dev)), mild_dev, dots_size=13)\nchart.add(\"Strong dev  |Δ| > 0.025  ({})\".format(len(strong_dev)), strong_dev, dots_size=18)\n\n# Save — theme-suffixed PNG (gallery) + interactive HTML (pygal is interactive)\nchart.render_to_png(f\"plot-{THEME}.png\")\nwith open(f\"plot-{THEME}.html\", \"wb\") as f:\n    f.write(chart.render())\n"}