Skip to content

Customizing the Tool

Calvin Yang edited this page Jun 1, 2026 · 1 revision

Customizing the Tool

All customisation points are in clearly marked blocks at the top of grr_tool.py.


1. Changing acceptance thresholds

# grr_tool.py — near the top
GRR_ACCEPTABLE_THRESHOLD = 10.0   # %GR&R <= 10% -> Acceptable
GRR_MARGINAL_THRESHOLD   = 30.0   # %GR&R <= 30% -> Marginal
NDC_MINIMUM              = 5      # ndc >= 5 required
Scenario Change
Aerospace / flight-critical (AS9100D) Both thresholds = 10.0 (no marginal zone)
Tighten for automotive SPC GRR_MARGINAL_THRESHOLD = 20.0
VDA Volume 5 ndc requirement NDC_MINIMUM = 8
Strict Class III medical device GRR_ACCEPTABLE_THRESHOLD = 5.0

2. Extending supported study sizes

K2 for 6 operators = 5.15 / d2*(6) = 5.15 / 2.534 = 2.03

K2_BY_OPERATORS[6] = 2.03
D4_BY_TRIALS[6]    = 2.004
K1_BY_TRIALS[6]    = 5.15 / 2.534

Additional K3 values for more parts:

Parts K3 Parts K3
11 1.58 15 1.49
12 1.55 20 1.43
K3_BY_PARTS[11] = 1.58
K3_BY_PARTS[12] = 1.55

3. Customising %Tolerance verdict thresholds

In build_pdf_report():

def _verdict(p: float) -> str:
    if p <= 10: return "Acceptable"
    if p <= 30: return "Marginal"
    return "Unacceptable"

Tighten to 5%/15% for Class III implants:

def _verdict(p: float) -> str:
    if p <= 5:  return "Acceptable"
    if p <= 15: return "Marginal"
    return "Unacceptable"

4. Confidence interval level

# In main() — switch to 90% CI
print(f"  90% CI on GR&R: [{res.grr_ci90[0]:.5f}, {res.grr_ci90[1]:.5f}]")

To add CI to the PDF, insert after the NDC note in build_pdf_report():

ci_msg = f"95% CI on GR&R: [{res.grr_ci95[0]:.5f}, {res.grr_ci95[1]:.5f}]"
story.append(Paragraph(ci_msg, s_body))

5. Report title and regulatory footer

Title: pass --title "Your Study Title" at the CLI.

Regulatory footer in build_pdf_report():

# Medical device (default)
"Regulatory basis: 21 CFR Part 820.72 (FDA QSR)."

# Automotive
"Regulatory basis: IATF 16949:2016 / AIAG PPAP 4th Ed. / VDA Volume 5."

# Aerospace
"Regulatory basis: AS9100D / NADCAP AC7130 / SAE ARP9013."

# Clinical laboratory
"Regulatory basis: CLIA 42 CFR Part 493 / ISO 15189:2022 / CLSI EP05-A3."

# Defense
"Regulatory basis: ANSI/NCSL Z540.3 / MIL-STD-45662A."

6. Color palette

NAVY   = "#1A3A5C"
TEAL   = "#16A085"
ORANGE = "#E67E22"
GREEN  = "#27AE60"
RED    = "#C0392B"

These flow through to both PDF charts and the HTML dashboard. Replace with your company brand colors.


7. Tweaking sample data generation

def generate_sample_data(output_path):
    random.seed(42)
    nominal   = 10.000
    true_vals = [round(nominal + random.uniform(-0.03, 0.03), 4) for _ in range(10)]
    op_biases = {"Alice": 0.0, "Bob": 0.003, "Carol": -0.002}
    noise_sig = 0.002  # gage repeatability sigma
Parameter Effect
random.uniform(-0.03, 0.03) Part spread — wider = higher PV = lower %GRR
noise_sig Gage noise — lower = better EV
op_biases Operator offsets — larger = higher AV

Generate ACCEPTABLE: noise_sig <= 0.001, part spread +/-0.050, op_biases <= 0.001 Generate UNACCEPTABLE: noise_sig >= 0.007, part spread +/-0.010, op_biases +/-0.008


8. Adding custom notes to the PDF

Insert a custom table in build_pdf_report() before the footer:

custom_notes = [
    ["PPAP Requirement", "GR&R submitted in MSA section of Control Plan"],
    ["Customer threshold", "<=10% GRR per OEM portal requirement"],
    ["Re-study trigger", "Annual or after any out-of-tolerance calibration finding"],
]
custom_tbl = Table(custom_notes, colWidths=[2.0*inch, 5.0*inch])
custom_tbl.setStyle(TableStyle([
    ("FONTNAME",  (0,0),(0,-1), "Helvetica-Bold"),
    ("FONTSIZE",  (0,0),(-1,-1), 8),
    ("GRID",      (0,0),(-1,-1), 0.4, _C_BORD),
    ("TOPPADDING",(0,0),(-1,-1), 4),
    ("BOTTOMPADDING",(0,0),(-1,-1), 4),
]))
story += [Paragraph("Site-Specific Requirements", s_section), custom_tbl, Spacer(1, 0.1*inch)]

9. Batch processing

for csv in studies/*.csv; do
  stem=$(basename "$csv" .csv)
  python grr_tool.py --input "$csv" --output "reports/${stem}_report.pdf" --tolerance 0.050
done
import subprocess
from pathlib import Path

for csv in Path("studies").glob("*.csv"):
    subprocess.run([
        "python", "grr_tool.py",
        "--input", str(csv),
        "--output", f"reports/{csv.stem}_report.pdf",
        "--tolerance", "0.050",
    ], check=True)

10. Git-versioned study records

repo/
  grr_tool.py          # pin to a tagged release (git tag v2.0.0)
  requirements.txt
  studies/
    2026-01-micrometer.csv
    2026-04-micrometer.csv   # re-study after calibration
  reports/             # commit or .gitignore

Tag each tool release so every study record references the exact version that produced it — a free, complete audit trail.