This is the shortest path from a column of measurements to a process behavior chart: wrap the data, formulate, execute, read the limits. Ten minutes, one chart, one real signal.
An X/mR chart (individuals and moving range) is the workhorse of process behavior analysis: it charts each measurement individually (X) alongside the point-to-point variation (mR). It is the right first chart whenever you have one measurement per time period.
If you want the full tour of the library afterwards, the Quickstart covers the same workflow in more depth.
import numpy as np
import pandas as pd
from processbehavior import ProcessBehavior
# 30 days of oven temperature readings, one per day.
# Unknown to us (for now): the thermostat drifted on day 25.
rng = np.random.default_rng(7)
temps = rng.normal(72.0, 1.5, 30)
temps[24:] += 5.0
df = pd.DataFrame({'day': range(1, 31), 'temperature': temps.round(2)})
df.head()Formulate¶
formulate() is where you tell the library what your data is: which column is the response, and which orders it in time. It classifies the data’s structure before anything is computed — the observed design state (ODS) is what the raw data supports, and the analytical design state (ADS) is what the analysis will run at. One measurement per day with no factors is design state 2 on Bishop’s 1–6 reference scale: time-ordered, no replication.
pb = ProcessBehavior(df)
study = pb.formulate(response='temperature', time='day')
print(f"Observed: ODS {study.observed_design_state.sds}")
print(f"Analytical: ADS {study.analytical_design_state.sds}")
print(f"Why: {study.ads_description}")
print(f"Recommended: {study.recommended_chart}")Observed: ODS 2
Analytical: ADS 2
Why: No replication (all cells n=1)
Recommended: X
Execute¶
execute() computes the recommended chart — here X. Pass companion=True to also get its partner chart, mR: the X chart watches location, the mR chart watches variation, and reading them together is what makes an “X/mR chart”.
result = study.execute(chart='X', companion=True)
print(f"Charts: {result.all_charts}")
print(f"X: {result.get_statistics('X')}")
print(f"mR: {result.get_statistics('mR')}")Charts: ['X', 'mR']
X: {'N': 1, 'center': np.float64(72.379), 'lpl': np.float64(68.366), 'upl': np.float64(76.392)}
mR: {'N': 2, 'center': np.float64(1.509), 'lpl': np.float64(0.0), 'upl': np.float64(4.93)}
Read the limits¶
Every chart’s statistics come in the same four-key shape:
center— the center line (the process’s typical level)lpl/upl— the lower and upper process limits, set at ±3 sigma from routine variationN— the subgroup size the limits assume (1 for an X chart)
The limits are the voice of the process: they say how far routine variation reaches. A point beyond them — or a run hugging one side — is a signal that something changed.
Signals are formalized as the WECO rules, built on dividing the space between the limits into three sigma-wide zones on each side of the center line (zone C nearest the center, then B, then A). Rule 1 is a point beyond the limits; the run- and zone-based rules (2–8) catch drifts and shifts that never cross a limit. See the WECO rules reference for all eight.
signals = result.detect_signals(chart='X')
print(f"Signals found: {signals.count}")
print(f"Flagged days: {sorted(signals.flagged_observations)}")Signals found: 9
Flagged days: [np.int64(20), np.int64(22), np.int64(24), np.int64(25), np.int64(28), np.int64(29)]
The thermostat drift on day 25 is caught — not just the shifted points themselves, but the run rules firing on the days leading into it. Now look at it:
result.plot()The X chart shows the level jump on day 25 with the shifted points flagged beyond the upper limit; the mR chart spikes exactly once — at the jump itself — then settles, telling you the variation didn’t change, only the level. That distinction (level shift vs. variation change) is exactly why the two charts are read as a pair.
What’s next¶
Quickstart — the same workflow with factors, stratification, and theming
Coffee Shop — A Complete Story — a full improvement narrative end to end
Signal Detection — the WECO rules in depth: which rule fired, where, and what to do