{"spec_id":"spc-xbar-r","library":"matplotlib","language":"python","code":"\"\"\" anyplot.ai\nspc-xbar-r: Statistical Process Control Chart (X-bar/R)\nLibrary: matplotlib 3.11.0 | Python 3.13.14\nQuality: 93/100 | Updated: 2026-06-20\n\"\"\"\n\nimport os\n\nimport matplotlib.pyplot as plt\nimport matplotlib.ticker as ticker\nimport numpy as np\n\n\n# Theme tokens (Imprint palette — 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\"\n\n# Imprint palette — semantic roles for SPC chart elements\nBRAND = \"#009E73\"  # position 1: main data line (first series)\nOOC_COLOR = \"#AE3030\"  # matte red: out-of-control points (semantic bad/error)\nAMBER = \"#DDCC77\"  # semantic amber: warning limits\n\n# Data — CNC shaft diameter measurements (subgroups of n=5)\nnp.random.seed(42)\nn_samples = 30\nsubgroup_size = 5\ntarget_diameter = 25.0\nprocess_std = 0.05\n\n# Control chart constants for n=5\nA2 = 0.577\nD3 = 0.0\nD4 = 2.114\n\n# Generate subgroup measurements (mostly in-control with injected shifts)\nmeasurements = np.random.normal(target_diameter, process_std, (n_samples, subgroup_size))\nmeasurements[7] += 0.15\nmeasurements[18] -= 0.18\nmeasurements[24] += 0.20\n\nsample_ids = np.arange(1, n_samples + 1)\nsample_means = measurements.mean(axis=1)\nsample_ranges = measurements.max(axis=1) - measurements.min(axis=1)\n\n# X-bar chart limits\nxbar_bar = sample_means.mean()\nr_bar = sample_ranges.mean()\nxbar_ucl = xbar_bar + A2 * r_bar\nxbar_lcl = xbar_bar - A2 * r_bar\nxbar_upper_warn = xbar_bar + (2 / 3) * A2 * r_bar\nxbar_lower_warn = xbar_bar - (2 / 3) * A2 * r_bar\nxbar_1sigma_upper = xbar_bar + (1 / 3) * A2 * r_bar\nxbar_1sigma_lower = xbar_bar - (1 / 3) * A2 * r_bar\n\n# R chart limits\nr_ucl = D4 * r_bar\nr_lcl = D3 * r_bar\nr_upper_warn = r_bar + (2 / 3) * (r_ucl - r_bar)\nr_lower_warn = r_bar - (2 / 3) * (r_bar - r_lcl)\nr_1sigma_upper = r_bar + (1 / 3) * (r_ucl - r_bar)\nr_1sigma_lower = r_bar - (1 / 3) * (r_bar - r_lcl)\n\n# Identify out-of-control points\nxbar_ooc = (sample_means > xbar_ucl) | (sample_means < xbar_lcl)\nr_ooc = (sample_ranges > r_ucl) | (sample_ranges < r_lcl)\n\n# Plot — landscape 3200×1800 px (figsize × dpi, no bbox_inches='tight')\nfig, (ax1, ax2) = plt.subplots(\n    2, 1, figsize=(8, 4.5), dpi=400, sharex=True, facecolor=PAGE_BG, gridspec_kw={\"height_ratios\": [3, 2]}\n)\n\n# X-bar chart — zone shading (inlined, no helper function)\nax1.axhspan(xbar_1sigma_lower, xbar_1sigma_upper, color=BRAND, alpha=0.07, zorder=0)\nax1.axhspan(xbar_1sigma_upper, xbar_upper_warn, color=AMBER, alpha=0.06, zorder=0)\nax1.axhspan(xbar_lower_warn, xbar_1sigma_lower, color=AMBER, alpha=0.06, zorder=0)\nax1.axhspan(xbar_upper_warn, xbar_ucl, color=OOC_COLOR, alpha=0.05, zorder=0)\nax1.axhspan(xbar_lcl, xbar_lower_warn, color=OOC_COLOR, alpha=0.05, zorder=0)\n\nax1.plot(\n    sample_ids,\n    sample_means,\n    color=BRAND,\n    linewidth=2.0,\n    marker=\"o\",\n    markersize=5,\n    markerfacecolor=BRAND,\n    markeredgecolor=PAGE_BG,\n    markeredgewidth=0.8,\n    zorder=3,\n    label=\"Sample Mean\",\n)\nax1.scatter(\n    sample_ids[xbar_ooc],\n    sample_means[xbar_ooc],\n    color=OOC_COLOR,\n    marker=\"X\",\n    s=110,\n    zorder=4,\n    edgecolors=PAGE_BG,\n    linewidth=1.0,\n    label=\"Out-of-Control\",\n)\n\nax1.axhline(xbar_bar, color=INK_SOFT, linewidth=1.5, linestyle=\"-\", zorder=2)\nax1.axhline(xbar_ucl, color=OOC_COLOR, linewidth=1.5, linestyle=\"--\", zorder=2)\nax1.axhline(xbar_lcl, color=OOC_COLOR, linewidth=1.5, linestyle=\"--\", zorder=2)\nax1.axhline(xbar_upper_warn, color=AMBER, linewidth=1.0, linestyle=\":\", alpha=0.9, zorder=2)\nax1.axhline(xbar_lower_warn, color=AMBER, linewidth=1.0, linestyle=\":\", alpha=0.9, zorder=2)\n\nax1.text(n_samples + 0.6, xbar_ucl, \"UCL\", fontsize=8, color=OOC_COLOR, va=\"center\", fontweight=\"bold\")\nax1.text(n_samples + 0.6, xbar_lcl, \"LCL\", fontsize=8, color=OOC_COLOR, va=\"center\", fontweight=\"bold\")\nax1.text(n_samples + 0.6, xbar_bar, f\"CL={xbar_bar:.3f}\", fontsize=8, color=INK_SOFT, va=\"center\")\n\nax1.set_xlim(0.5, n_samples + 3.5)\nax1.set_ylabel(\"Sample Mean, X̄ (mm)\", fontsize=10, color=INK)\nax1.set_title(\"spc-xbar-r · python · matplotlib · anyplot.ai\", fontsize=12, fontweight=\"medium\", color=INK, pad=8)\nax1.set_facecolor(PAGE_BG)\nax1.tick_params(axis=\"both\", labelsize=8, colors=INK_SOFT, labelcolor=INK_SOFT)\nax1.spines[\"top\"].set_visible(False)\nax1.spines[\"right\"].set_visible(False)\nfor s in (\"left\", \"bottom\"):\n    ax1.spines[s].set_color(INK_SOFT)\nax1.yaxis.grid(True, alpha=0.12, linewidth=0.7, color=INK)\nax1.yaxis.set_major_formatter(ticker.FormatStrFormatter(\"%.2f\"))\n\nleg1 = ax1.legend(fontsize=8, loc=\"upper left\", facecolor=ELEVATED_BG, edgecolor=INK_SOFT)\nif leg1:\n    plt.setp(leg1.get_texts(), color=INK_SOFT)\n\n# R chart — zone shading (inlined)\nax2.axhspan(max(r_1sigma_lower, 0), r_1sigma_upper, color=BRAND, alpha=0.07, zorder=0)\nax2.axhspan(r_1sigma_upper, r_upper_warn, color=AMBER, alpha=0.06, zorder=0)\nax2.axhspan(max(r_lower_warn, 0), max(r_1sigma_lower, 0), color=AMBER, alpha=0.06, zorder=0)\nax2.axhspan(r_upper_warn, r_ucl, color=OOC_COLOR, alpha=0.05, zorder=0)\nif r_lcl > 0:\n    ax2.axhspan(r_lcl, max(r_lower_warn, 0), color=OOC_COLOR, alpha=0.05, zorder=0)\n\nax2.plot(\n    sample_ids,\n    sample_ranges,\n    color=BRAND,\n    linewidth=2.0,\n    marker=\"s\",\n    markersize=4.5,\n    markerfacecolor=BRAND,\n    markeredgecolor=PAGE_BG,\n    markeredgewidth=0.8,\n    zorder=3,\n    label=\"Sample Range\",\n)\nax2.scatter(\n    sample_ids[r_ooc],\n    sample_ranges[r_ooc],\n    color=OOC_COLOR,\n    marker=\"X\",\n    s=100,\n    zorder=4,\n    edgecolors=PAGE_BG,\n    linewidth=1.0,\n    label=\"Out-of-Control\",\n)\n\nax2.axhline(r_bar, color=INK_SOFT, linewidth=1.5, linestyle=\"-\", zorder=2)\nax2.axhline(r_ucl, color=OOC_COLOR, linewidth=1.5, linestyle=\"--\", zorder=2)\nif r_lcl > 0:\n    ax2.axhline(r_lcl, color=OOC_COLOR, linewidth=1.5, linestyle=\"--\", zorder=2)\nax2.axhline(r_upper_warn, color=AMBER, linewidth=1.0, linestyle=\":\", alpha=0.9, zorder=2)\nif r_lower_warn > 0:\n    ax2.axhline(r_lower_warn, color=AMBER, linewidth=1.0, linestyle=\":\", alpha=0.9, zorder=2)\n\nax2.text(n_samples + 0.6, r_ucl, \"UCL\", fontsize=8, color=OOC_COLOR, va=\"center\", fontweight=\"bold\")\nax2.text(n_samples + 0.6, r_bar, f\"CL={r_bar:.3f}\", fontsize=8, color=INK_SOFT, va=\"center\")\n\nax2.set_xlabel(\"Sample Number\", fontsize=10, color=INK)\nax2.set_ylabel(\"Sample Range, R (mm)\", fontsize=10, color=INK)\nax2.set_facecolor(PAGE_BG)\nax2.tick_params(axis=\"both\", labelsize=8, colors=INK_SOFT, labelcolor=INK_SOFT)\nax2.spines[\"top\"].set_visible(False)\nax2.spines[\"right\"].set_visible(False)\nfor s in (\"left\", \"bottom\"):\n    ax2.spines[s].set_color(INK_SOFT)\nax2.yaxis.grid(True, alpha=0.12, linewidth=0.7, color=INK)\nax2.yaxis.set_major_formatter(ticker.FormatStrFormatter(\"%.2f\"))\n\nleg2 = ax2.legend(fontsize=8, loc=\"upper left\", facecolor=ELEVATED_BG, edgecolor=INK_SOFT)\nif leg2:\n    plt.setp(leg2.get_texts(), color=INK_SOFT)\n\nfig.subplots_adjust(left=0.08, right=0.88, top=0.93, bottom=0.10, hspace=0.08)\nplt.savefig(f\"plot-{THEME}.png\", dpi=400, facecolor=PAGE_BG)\n"}