Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Quickstart

This tutorial will get you up and running with ProcessBehavior in about 5 minutes.

What You’ll Learn

  1. Load data into a ProcessBehavior wrapper

  2. Formulate a study with response, factors, and time

  3. Execute the analysis and create control charts

  4. Detect signals (out-of-control points)

  5. Export results

Setup

First, let’s import the necessary libraries:

import numpy as np
import pandas as pd
from processbehavior import ProcessBehavior

Step 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)
Loading...

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:

CodeCell distributionNotes
1Complete grid, all N_kt >= 2Full residual decomposition
2Complete grid, all N_kt = 1No replication; X/mR only
3Complete grid, mixed N_ktPartial replication
4, 5, 6Incomplete 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:
Loading...
# 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()
Loading...

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()
Loading...

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:
Loading...

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()
Loading...

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:

  1. ProcessBehavior(df) - Wrap your data

  2. pb.formulate(...) - Define response, factors, time

  3. study.execute() - Compute statistics

  4. result.plot() - Visualize

  5. result.detect_signals() - Find out-of-control points

Next Steps