{"spec_id":"histogram-capability","library":"matplotlib","language":"python","code":"\"\"\" anyplot.ai\nhistogram-capability: Process Capability Plot with Specification Limits\nLibrary: matplotlib 3.11.0 | Python 3.13.14\nQuality: 92/100 | Updated: 2026-06-20\n\"\"\"\n\nimport os\n\nimport matplotlib.patheffects as pe\nimport matplotlib.pyplot as plt\nimport matplotlib.ticker as ticker\nimport numpy as np\nfrom scipy import stats\n\n\n# Theme tokens\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\"\n\n# Imprint palette positions used in this chart\nBRAND = \"#009E73\"  # position 1 — histogram bars (first categorical series)\nBLUE = \"#4467A3\"  # position 3 — target line\nOCHRE = \"#BD8233\"  # position 4 — mean line\nRED = \"#AE3030\"  # position 5 — spec limits (semantic: reject / bad zone)\n\n# Data — mean shifted from target to demonstrate Cp vs Cpk distinction\nnp.random.seed(42)\nmeasurements = np.random.normal(loc=10.008, scale=0.014, size=200)\nlsl = 9.95\nusl = 10.05\ntarget = 10.00\n\n# Capability indices\nmean = np.mean(measurements)\nsigma = np.std(measurements, ddof=1)\ncp = (usl - lsl) / (6 * sigma)\ncpk = min((usl - mean) / (3 * sigma), (mean - lsl) / (3 * sigma))\n\n# Plot\ntitle = \"histogram-capability · python · matplotlib · anyplot.ai\"\ntitle_fontsize = max(8, round(12 * 67 / len(title))) if len(title) > 67 else 12\n\nfig, ax = plt.subplots(figsize=(8, 4.5), dpi=400, facecolor=PAGE_BG)\nax.set_facecolor(PAGE_BG)\n\n# Histogram — brand green bars with page-background edges\nax.hist(measurements, bins=25, density=True, alpha=0.85, color=BRAND, edgecolor=PAGE_BG, linewidth=0.8, zorder=3)\n\n# Fitted normal curve — theme-adaptive ink color with path effect depth\nx_range = np.linspace(lsl - 0.012, usl + 0.012, 400)\ny_curve = stats.norm.pdf(x_range, mean, sigma)\nax.plot(\n    x_range,\n    y_curve,\n    color=INK,\n    linewidth=2.5,\n    zorder=4,\n    path_effects=[pe.withStroke(linewidth=4.5, foreground=PAGE_BG, alpha=0.75)],\n)\n\n# Rejection regions shaded under curve tails beyond spec limits\nax.fill_between(x_range, y_curve, where=(x_range < lsl), color=RED, alpha=0.20, zorder=2)\nax.fill_between(x_range, y_curve, where=(x_range > usl), color=RED, alpha=0.20, zorder=2)\n\n# Specification limits and reference lines\nax.axvline(lsl, color=RED, linestyle=\"--\", linewidth=2.0, zorder=5, label=f\"LSL = {lsl}\")\nax.axvline(usl, color=RED, linestyle=\"--\", linewidth=2.0, zorder=5, label=f\"USL = {usl}\")\nax.axvline(target, color=BLUE, linestyle=\"-.\", linewidth=2.0, zorder=5, label=f\"Target = {target:.2f}\")\nax.axvline(mean, color=OCHRE, linestyle=\"-\", linewidth=2.0, alpha=0.9, zorder=5, label=f\"Mean = {mean:.4f}\")\n\n# Capability stats box\nverdict = \"CAPABLE\" if cpk >= 1.0 else \"NOT CAPABLE\"\nverdict_color = BRAND if cpk >= 1.0 else RED\nstats_text = f\"Cp   = {cp:.2f}\\nCpk  = {cpk:.2f}\\nσ    = {sigma:.4f}\\nn    = {len(measurements)}\"\nax.text(\n    0.98,\n    0.96,\n    stats_text,\n    transform=ax.transAxes,\n    fontsize=8,\n    verticalalignment=\"top\",\n    horizontalalignment=\"right\",\n    fontfamily=\"monospace\",\n    color=INK,\n    bbox={\"boxstyle\": \"round,pad=0.5\", \"facecolor\": ELEVATED_BG, \"edgecolor\": INK_SOFT, \"alpha\": 0.93},\n    zorder=6,\n)\nax.text(\n    0.98,\n    0.70,\n    verdict,\n    transform=ax.transAxes,\n    fontsize=9,\n    fontweight=\"bold\",\n    verticalalignment=\"top\",\n    horizontalalignment=\"right\",\n    fontfamily=\"monospace\",\n    color=verdict_color,\n    zorder=6,\n)\n\n# Style\nax.set_xlabel(\"Shaft Diameter (mm)\", fontsize=10, color=INK, labelpad=6)\nax.set_ylabel(\"Density\", fontsize=10, color=INK, labelpad=6)\nax.set_title(title, fontsize=title_fontsize, fontweight=\"medium\", color=INK, pad=10)\nax.tick_params(axis=\"both\", labelsize=8, colors=INK_SOFT, labelcolor=INK_SOFT)\nax.xaxis.set_major_formatter(ticker.FormatStrFormatter(\"%.3f\"))\nax.yaxis.grid(True, alpha=0.12, linewidth=0.6, color=INK)\nax.spines[\"top\"].set_visible(False)\nax.spines[\"right\"].set_visible(False)\nax.spines[\"left\"].set_color(INK_SOFT)\nax.spines[\"bottom\"].set_color(INK_SOFT)\n\n# Legend\nleg = ax.legend(fontsize=8, loc=\"upper left\", framealpha=0.93)\nif leg:\n    leg.get_frame().set_facecolor(ELEVATED_BG)\n    leg.get_frame().set_edgecolor(INK_SOFT)\n    plt.setp(leg.get_texts(), color=INK_SOFT)\n\n# Trim x-axis to bracket spec limits with a small margin — eliminates empty canvas edges\nx_lo = min(lsl - 0.010, mean - 4.5 * sigma)\nx_hi = max(usl + 0.010, mean + 4.5 * sigma)\nax.set_xlim(x_lo, x_hi)\n\n# Save — no bbox_inches='tight' (would shave canvas pixels)\nplt.tight_layout()\nplt.savefig(f\"plot-{THEME}.png\", dpi=400, facecolor=PAGE_BG)\n"}