This tutorial will get you up and running with ProcessBehavior in about 5 minutes.
What You’ll Learn¶
Load data into a ProcessBehavior wrapper
Formulate a study with response, factors, and time
Execute the analysis and create control charts
Detect signals (out-of-control points)
Export results
Setup¶
First, let’s import the necessary libraries:
import numpy as np
import pandas as pd
from processbehavior import ProcessBehaviorStep 1: Create Sample Data¶
Let’s create a realistic manufacturing dataset. We’ll simulate a filling machine with:
4 filling lanes (A, B, C, D)
Measurements over 10 time periods
3 replicate measurements per lane per time period
np.random.seed(42)
# Create replicated design: 4 lanes x 10 times x 3 replicates
n_lanes = 4
n_times = 10
n_reps = 3
# Build the data
lanes = ['A', 'B', 'C', 'D']
data = []
for t in range(n_times):
for lane in lanes:
# Each lane has slightly different mean
lane_offset = {'A': 0, 'B': 1, 'C': -0.5, 'D': 0.5}[lane]
for rep in range(n_reps):
# Add some special cause variation to Lane C at time 7
special_cause = 8 if (lane == 'C' and t == 7) else 0
value = 100 + lane_offset + special_cause + np.random.normal(0, 2)
data.append({
'time': t + 1,
'lane': lane,
'weight': round(value, 2)
})
df = pd.DataFrame(data)
print(f"Dataset shape: {df.shape}")
df.head(12)Dataset shape: (120, 3)
Step 2: Create a ProcessBehavior Wrapper¶
Wrap your pandas DataFrame in a ProcessBehavior to enable IDE auto-completion and the fluent API:
pb = ProcessBehavior(df)
# Explore available columns with auto-completion
print("Available columns:")
print(f" - {pb.cols.time}")
print(f" - {pb.cols.lane}")
print(f" - {pb.cols.weight}")Available columns:
- time
- lane
- weight
Step 3: Formulate Your Study¶
Use formulate() to specify:
response: The measurement variable
factors: Categorical variables that define subgroups
time: Time ordering variable
ProcessBehavior automatically detects the Sampling Design State (SDS):
study = pb.formulate(
response=pb.cols.weight,
factors=[pb.cols.lane],
time=pb.cols.time
)
print(f"Observed: ODS {study.observed_design_state.sds}")
print(f"Analytical: ADS {study.analytical_design_state.sds}")
print(f"Recommended chart: {study.recommended_chart}")
print(f"Valid charts: {study.valid_charts}")Observed: ODS 1
Analytical: ADS 1
Recommended chart: Xbar
Valid charts: ['Histogram', 'Xbar', 'S', 'X', 'mR']
Understanding the design-state lineage¶
The output above reports two design states:
ODS (Observed Design State) - what the raw data structure looks like before any cleaning. Computed on the (factor x time) grid as Bishop’s classification of the N_kt distribution.
ADS (Analytical Design State) - what survives tidying and drives chart selection, residual availability, and variance decomposition.
For this dataset, both classify as Bishop’s Code 1 (“full replication”): every cell has at least 2 observations. That’s the gold-standard design - it supports the full residual decomposition (R1-R5) and Xbar-S charts.
Other Bishop codes you may see:
| Code | Cell distribution | Notes |
|---|---|---|
| 1 | Complete grid, all N_kt >= 2 | Full residual decomposition |
| 2 | Complete grid, all N_kt = 1 | No replication; X/mR only |
| 3 | Complete grid, mixed N_kt | Partial replication |
| 4, 5, 6 | Incomplete grid (some cells empty) | ODS only; collapses to ADS 1/2/3 |
Step 4: Execute the Analysis¶
The execute() method computes control chart statistics:
# Execute with the recommended chart (Xbar-S)
result = study.execute()
print(f"Charts calculated: {result.all_charts}")
print(f"Has residuals: {result.has_residuals}")Charts calculated: ['Xbar']
Has residuals: True
View Chart Statistics¶
Results are returned as plain pandas DataFrames:
# Get the Xbar chart data
xbar_data = result.get_chart('Xbar')
print("Xbar Chart Data:")
xbar_data.head(10)Xbar Chart Data:
# View statistics
print("\nXbar Statistics:")
result.get_statistics('Xbar')
Xbar Statistics:
{'center': np.float64(100.292),
'N': np.int64(3),
'upl': np.float64(103.696),
'lpl': np.float64(96.887)}Step 5: Visualize with Control Charts¶
Create interactive Plotly charts with one line:
# Basic control chart
fig = result.plot()
fig.show()Enhanced Visualization¶
Add zone shading, signal markers, and statistics:
fig = result.plot(
chart='Xbar',
show_zones=True, # Show 1σ, 2σ, 3σ zones
highlight_signals=True, # Highlight out-of-control points
show_stats=True, # Display statistics box
theme='processbehavior' # Use default theme
)
fig.show()Step 6: Detect Signals¶
Use Western Electric rules to detect out-of-control conditions:
# Detect signals on Xbar chart
signals = result.detect_signals(chart='Xbar')
print(f"Signals detected: {signals.count}")
print(f"Has signals: {signals.has_signals}")
if signals.has_signals:
print("\nViolations:")
display(signals.violations)Signals detected: 1
Has signals: True
Violations:
Signal Detection Rules¶
For Xbar and S charts (categorical comparisons), only Rule 1 applies:
Points beyond the control limits
For IMR charts (time series), all 8 Western Electric rules apply:
Rule 1: Point beyond 3σ
Rule 2: 2 of 3 consecutive in Zone A
Rule 3: 4 of 5 consecutive in Zone B or beyond
Rule 4: 8+ consecutive same side of center
Rule 5: 6+ consecutive trending
Rule 6: 14+ consecutive alternating
Rule 7: 15+ consecutive in Zone C
Rule 8: 8+ consecutive avoiding Zone C
Step 7: Stratified Analysis¶
For time series analysis by lane, use stratified IMR charts. The by parameter controls how data is grouped:
# Execute stratified X/mR (one chart pair per lane)
# `by=['lane']` separates the chart into one lane each;
# `companion=True` gives both X (Individuals) and mR (Moving Range).
result_imr = study.execute(chart='X', by=['lane'], companion=True)
# Each lane gets its own X and mR chart
print(f"X chart strata: {result_imr.charts['X']['strata']}")
print(f"mR chart strata: {result_imr.charts['mR']['strata']}")X chart strata: ['A', 'B', 'C', 'D']
mR chart strata: ['A', 'B', 'C', 'D']
# Plot stratified IMR with all rules
fig = result_imr.plot(
show_zones=True,
highlight_signals=True,
show_rules=True, # Show all WECO rule violations
theme='dark'
)
fig.show()Step 8: Export Results¶
Export everything to Excel for sharing:
# Export to Excel (requires openpyxl)
# result.to_excel('analysis_results.xlsx')
# Or get results as DataFrames for custom export
print("Available as plain DataFrames:")
print(f" - result.get_chart('Xbar')")
print(f" - result.get_statistics('Xbar')")
print(f" - result.residuals # VAS residuals")Available as plain DataFrames:
- result.get_chart('Xbar')
- result.get_statistics('Xbar')
- result.residuals # VAS residuals
Summary¶
You’ve learned the core ProcessBehavior workflow:
ProcessBehavior(df) - Wrap your data
pb.formulate(...) - Define response, factors, time
study.execute() - Compute statistics
result.plot() - Visualize
result.detect_signals() - Find out-of-control points
Next Steps¶
Key Concepts - Understand DS, VAS, and Wheeler terminology
Xbar-S Analysis - Deep dive into Xbar-S charts
Stratified Analysis - Multi-factor analysis
Plotting & Themes - Advanced visualization options