Cookbook
This page contains five self-contained recipes that cover the most common SPC analysis scenarios. Each recipe describes its input data shape, provides working code samples in C#, Visual Basic, and F#, explains what the results mean, and highlights the single most common mistake practitioners make in that scenario.
These recipes assume the reader has already read Getting Started with Numerics.NET SPC. For guidance on selecting the right chart type, see Choosing the Right Analysis.
Recipe 1: Individuals Process Analysis (I‑MR)
Scenario. A chemical batch process produces one measurement per batch: the yield (%) of a distillation step. Batches arrive in time order and cannot be grouped into rational subgroups. The goal is to determine whether the yield process is in statistical control and, if so, to estimate process capability against a specification of 90 %–105 %.
Input shape. A single IReadOnlyList<double> of n observations in time order. Missing values should be omitted before passing to the API; the library treats NaN as a contract violation in individuals data.
// Recipe: Individuals process analysis (I-MR)
double[] measurements = {
23.1, 24.0, 22.8, 24.5, 23.3, 24.8, 22.5, 24.2,
23.7, 24.1, 23.4, 24.3, 23.6, 24.0, 23.2
};
Vector<double> obs = Vector.Create(measurements);
// 1. Construct and analyze the chart
IndividualsMovingRangeChartSet chart =
new IndividualsMovingRangeChartSet(obs);
chart.Analyze();
FixedLimitSeries iSeries = chart.IndividualsSeries;
Console.WriteLine(
$"I chart: CL={iSeries.CenterLine:F2} " +
$"UCL={iSeries.UpperControlLimit:F2} " +
$"LCL={iSeries.LowerControlLimit:F2}");
// 2. Evaluate rules
RuleSetEvaluation rules =
chart.IndividualsSeries.EvaluateRules(ControlRuleSets.Nelson);
bool isStable = !rules.HasViolations;
Console.WriteLine($"Stable: {isStable}");
// 3. Capability analysis (independent step)
if (isStable)
{
var specs = new SpecificationLimits(Lower: 21.0, Upper: 27.0);
CapabilityAnalysisResult cap = Capability.Analyze(obs, specs);
Console.WriteLine($"Cpk = {cap.Cpk:F3}");
}Reading the result.
After calling
Analyze(),
the
IndividualsMovingRangeChartSet
exposes each observation with its plotted value, control limits,
and rule violations through its
IndividualsSeries
series.
The capability section exposes
Recipe 2: Subgrouped Manufacturing Analysis (XBar‑R)
Scenario. A machining centre produces shafts in a continuous run. Every hour an operator measures five consecutive shafts (a rational subgroup) and records the diameters in millimetres. Twenty-five subgroups have been collected. The engineering tolerance is 50.00 mm ± 0.05 mm.
Input shape. A jagged or rectangular 2-D collection where each inner sequence is one subgroup of equal or near-equal size. XBar‑R is reliable for subgroup sizes 2–10; for larger subgroups use XBar‑S instead. See Variables Charts for the supported size range.
// Recipe: Subgrouped manufacturing analysis (XBar-R, n=4)
double[,] rawData = {
{ 23.1, 24.0, 22.8, 24.5 },
{ 23.3, 24.8, 22.5, 24.2 },
{ 23.7, 24.1, 23.4, 24.3 },
{ 23.6, 24.0, 23.2, 24.4 },
{ 23.0, 24.6, 22.9, 24.1 }
};
Matrix<double> subgroups = Matrix.CopyFrom(rawData);
// 1. Construct and analyze
XBarRChartSet chart = new XBarRChartSet(subgroups);
chart.Analyze();
Console.WriteLine(
$"XBar UCL={chart.MeansSeries.UpperControlLimit:F3}");
// 2. Rules on XBar component
RuleSetEvaluation rules =
chart.MeansSeries.EvaluateRules(ControlRuleSets.Nelson);
Console.WriteLine($"XBar rule violations: {rules.Violations.Count}");
// 3. Capability (independent step)
var specs = new SpecificationLimits(Lower: 21.0, Upper: 27.0);
CapabilityAnalysisResult cap = Capability.Analyze(subgroups, specs);
Console.WriteLine($"Cpk = {cap.Cpk:F3}");Reading the result. The fitted
XBarRChartSet
exposes
separate series for the XBar chart (monitoring the subgroup
mean) and the R chart (monitoring the subgroup range). Stability
must be evaluated on both charts. An R chart out of control
indicates that within-subgroup variation itself is unstable, which
invalidates the XBar control limits. If both charts show control,
the capability section will report
Recipe 3: Variable Sample-Size P Chart
Scenario. A circuit-board assembly line inspects every board in each production lot, but lot sizes vary from 50 to 300 boards. The quality metric is the proportion defective per lot. Because the denominator changes from lot to lot, the control limits must be recalculated individually for each point.
Input shape. Two parallel sequences of equal length: a sequence of defective counts (integers or doubles) and a sequence of sample sizes (integers). The sample sizes may all differ. Do not pre-compute proportions and pass them as the first sequence; the API requires raw counts so it can compute Poisson or binomial limits correctly.
// Recipe: Variable sample-size P chart
Vector<double> defects = Vector.Create(
new double[] { 3, 5, 2, 7, 4, 6, 3, 8, 2, 5 });
Vector<double> sizes = Vector.Create(
new double[] { 50, 60, 45, 70, 55, 65, 50, 80, 45, 60 });
PChart chart = new PChart(defects, sizes);
chart.Analyze();
Console.WriteLine($"P bar = {chart.Series.CenterLine:F4}");
// Render with pointwise limits
Vector<double> pts = chart.Series.Values;
Vector<double> ucls = chart.Series.UpperControlLimits;
for (int i = 0; i < pts.Count; i++)
Console.WriteLine(
$" [{i}] p={pts[i]:F4} " +
$"UCL={ucls[i]:F4}");Reading the result. Because sample sizes differ, each plotted point has its own pair of upper and lower control limits. The result model exposes per-point limit vectors; do not read a single scalar limit from the result and apply it to all points. Points where the computed lower control limit would be negative are floored at zero. See Result Model and Rendering Semantics for details on accessing per-point vectors.
Recipe 4: Capability Analysis with Assumption Diagnostics
Scenario. After confirming an XBar‑R
process is in control (Recipe 2), the team needs to produce a
formal capability report that includes a normality test so the
customer can evaluate whether the standard
Input shape. The same subgrouped data as Recipe 2, plus a SpecificationLimits class with at minimum one non-null limit, and the flag assumptionDiagnostics: true passed to the analysis call.
// Recipe: Capability analysis with assumption diagnostics
double[] data = {
23.1, 24.0, 22.8, 24.5, 23.3, 24.8, 22.5, 24.2,
23.7, 24.1, 23.4, 24.3, 23.6, 24.0, 23.2, 24.4,
23.0, 24.6, 22.9, 24.1
};
Vector<double> obs = Vector.Create(data);
var specs = new SpecificationLimits(Lower: 21.0, Upper: 27.0);
// 1. Chart analysis
IndividualsMovingRangeChartSet chart =
new IndividualsMovingRangeChartSet(obs);
chart.Analyze();
bool stable =
!chart.IndividualsSeries.EvaluateRules(ControlRuleSets.Nelson).HasViolations;
Console.WriteLine($"Stable: {stable}");
// 2. Capability (request normality testing)
CapabilityAnalysisResult cap = Capability.Analyze(
obs, specs,
normalityTest: TestOfNormality.ShapiroWilk);
Console.WriteLine($"Cp={cap.Cp:F3} Cpk={cap.Cpk:F3}");
Console.WriteLine($"Pp={cap.Pp:F3} Ppk={cap.Ppk:F3}");
// 3. Assumption diagnostics from the capability result
AssumptionDiagnostics? diag = cap.Diagnostics;
if (diag?.NormalityTest != null)
Console.WriteLine(
$"Normality p = {diag.NormalityTest.PValue:F4}");Reading the result. The
AssumptionDiagnostics
object is returned alongside the
CapabilityAnalysisResult.
Check the
PValue
from the normality test (accessible via
NormalityTest).
A p-value above 0.05 does not
contradict normality; a value below 0.05 warrants investigation
before submitting the
Recipe 5: Serialize and Restore a Result
Scenario. A web service computes SPC results on a background worker and needs to cache or transmit the result to a front-end that renders the chart. The front-end should not re-run the analysis; it should deserialize the result and read the per-point vectors directly for rendering without any further computation.
Input shape. A previously computed fitted chart. After calling Analyze(), the chart object is self-contained and can be serialized via its ToJson() method. All plotted values, control limits, and rule violation flags are stored as immutable vectors and survive a round-trip. See Integration and Persistence for serializer configuration details.
// Recipe: Serialize and restore a deployed chart
double[] data = {
23.1, 24.0, 22.8, 24.5, 23.3, 24.8, 22.5, 24.2, 23.7, 24.1
};
// 1. Fit the chart
IndividualsMovingRangeChartSet original =
new IndividualsMovingRangeChartSet(Vector.Create(data));
original.Analyze();
// 2. Deploy (freeze parameters) and serialize
IndividualsMovingRangeChartSet deployed = original.Deploy();
string json = deployed.ToJson();
// 3. Restore from JSON (e.g., from database or API response)
IndividualsMovingRangeChartSet restored =
IndividualsMovingRangeChartSet.FromJson(json);
Console.WriteLine(
$"Original CL = {original.IndividualsSeries.CenterLine:F4}");
Console.WriteLine(
$"Restored CL = {restored.IndividualsSeries.CenterLine:F4}");Reading the result. After deserialization the restored object is functionally identical to the original: all indexed vectors are present at the same positions, control limits match, and rule violation flags are preserved. The receiver does not need access to the original raw data at all. This pattern is the recommended approach for any architecture that separates the computation tier from the presentation tier.
Recipe 6: Phase II Monitoring (Deploy and Apply)
Scenario. A manufacturing line has completed Phase I baseline estimation. New batches arrive daily and must be plotted against the frozen control limits. The baseline chart is persisted to JSON and restored on each monitoring run.
Workflow.
Fit the chart with Analyze() during Phase I.
Call Deploy() to create a deployed chart that holds frozen control limits and discards the original observations.
Serialize the deployed chart with ToJson() and store it.
When new data arrives, restore the deployed chart with FromJson() and call Apply(Vector<Double>) to produce a new fitted chart evaluated against the frozen baseline.
This pattern supports charts-only monitoring without rules or capability analysis—simply inspect the plotted values and control limits after Apply(Vector<Double>).