Shewhart individuals (I) chart
NIST MAVRO filter-transmittance data
Example from the compendium of canonical charts
Python Code
"""Shewhart individuals (I) chart — NIST MAVRO filter-transmittance data."""
import numpy as np
import pandas as pd
import plotly.graph_objects as go
import requests, warnings
URL = "https://www.itl.nist.gov/div898/handbook/datasets/MAVRO.DAT"
D2 = 1.128 # unbiasing constant for n=2 moving range
def generate():
print("fetching NIST MAVRO.DAT …")
warnings.filterwarnings("ignore")
requests.packages.urllib3.disable_warnings()
r = requests.get(URL, verify=False, timeout=30)
r.raise_for_status()
lines = r.text.strip().split("\n")
# Skip first 25 header lines; remaining lines are the data values
data_lines = lines[25:]
values = []
for line in data_lines:
for token in line.split():
try:
values.append(float(token))
except ValueError:
pass
values = values[:50] # spec says 50 values
print(f" parsed {len(values)} values")
x = list(range(1, len(values) + 1))
y = np.array(values)
# Center line and control limits via moving-range method
mr = np.abs(np.diff(y))
mr_bar = np.mean(mr)
y_bar = np.mean(y)
sigma = mr_bar / D2
ucl = y_bar + 3 * sigma
lcl = y_bar - 3 * sigma
# Flag out-of-control: beyond ±3σ
ooc_mask = (y > ucl) | (y < lcl)
# Western Electric run rule: 8 consecutive points on same side of center
run8_idx = []
for i in range(7, len(y)):
window = y[i-7:i+1]
if np.all(window > y_bar) or np.all(window < y_bar):
run8_idx.append(i)
fig = go.Figure()
# UCL / LCL / Center
for val, label, color, dash in [
(ucl, f"UCL = {ucl:.4f}", PINK, "dash"),
(y_bar, f"CL = {y_bar:.4f}", VIOLET, "solid"),
(lcl, f"LCL = {lcl:.4f}", PINK, "dash"),
]:
fig.add_hline(y=val, line=dict(color=color, width=1.5, dash=dash),
annotation_text=label, annotation_position="right",
annotation_font=dict(size=10))
# All points
fig.add_trace(go.Scatter(
x=x, y=values,
mode="lines+markers",
name="Transmittance",
line=dict(color=VIOLET, width=1.5),
marker=dict(color=VIOLET, size=6),
hovertemplate="Sample %{x}<br>Value=%{y:.4f}<extra></extra>",
))
# Run-rule violations
if run8_idx:
fig.add_trace(go.Scatter(
x=[x[i] for i in run8_idx],
y=[values[i] for i in run8_idx],
mode="markers", name="8-pt run rule",
marker=dict(color=TEAL, size=16, symbol="diamond"),
hovertemplate="Run rule: Sample %{x}<extra></extra>",
))
# Out-of-control points
if ooc_mask.any():
ooc_x = [x[i] for i in range(len(x)) if ooc_mask[i]]
ooc_y = [values[i] for i in range(len(values)) if ooc_mask[i]]
fig.add_trace(go.Scatter(
x=ooc_x, y=ooc_y,
mode="markers", name="Out of control",
marker=dict(color=PINK, size=12, symbol="circle-open", line=dict(width=2)),
hovertemplate="OOC: Sample %{x}, Value=%{y:.4f}<extra></extra>",
))
fig.update_layout(
title=dict(text="Shewhart I-Chart — NIST MAVRO Filter Transmittance", x=0.5),
xaxis=dict(title="Sample"),
yaxis=dict(title="Transmittance"),
legend=dict(orientation="h", y=1.08),
margin=dict(t=60, b=50, l=80, r=130),
height=460,
)
return fig
if __name__ == "__main__":
generate()
Made with Plotly