Result Model
After calling Analyze() on a chart object, the chart exposes its analysis results through typed series properties. This page describes the shared properties available on all ControlSeries subtypes, explains the difference between scalar and pointwise control limits, documents the RuleViolation window model, and gives guidance on translating the result object into a visual chart.
Shared Chart Data Properties
All concrete chart-data types inherit from ControlSeries, which exposes Values and Index. Control-limit properties are defined on FixedLimitSeries (for charts with constant limits) and on PointwiseLimitSeries (for P, U, and EWMA charts with per-point limits).
Property | Source | Type | Description |
|---|---|---|---|
Vector<double> | The plotted statistic for each point on the chart (e.g., individual value, subgroup mean, proportion defective). Indexed from 0 (earliest) to Values.Length - 1 (latest). Available on all chart types. | ||
double | The estimated process center. Drawn as a horizontal reference line. Available on all chart types through FixedLimitSeries or PointwiseLimitSeries. | ||
double | Scalar upper 3-sigma control limit. Available on Individuals, MR, XBar, R, S, NP, and C charts. For P, U, and EWMA charts use the pointwise UpperControlLimits vector instead. | ||
double | Scalar lower 3-sigma control limit. Same availability note as above. May be double.NaN when the lower limit is theoretically zero (count charts). | ||
double | The within-process sigma estimate used to compute the 3-sigma limits. The estimation method is controlled by SigmaEstimator. |
Point Alignment
The length of the <codeEntityReference>P:Numerics.NET.Statistics.ProcessControl.ControlSeries.Values</codeEntityReference> vector depends on the chart family:
Individuals charts: one point per observation, so Values.Length equals the number of values passed in.
XBar, XBar‑R, XBar‑S, P, NP, C, U charts : one point per subgroup. For a matrix input with k rows, Values.Length == k.
EWMA and CUSUM charts: one point per observation, mirroring the individuals layout.
When displaying a control chart alongside a time axis or subgroup-number axis, map index i in Values to the (i+1)-th tick on the axis.
Scalar vs. Pointwise Control Limits
For chart families where every point shares the same control limit (equal subgroup sizes), the scalar UpperControlLimit and LowerControlLimit properties are sufficient for rendering.
For P and U charts with variable subgroup sizes, the 3-sigma limits vary from point to point because they depend on n_i. In this case:
PChart and UChart expose UpperControlLimits and LowerControlLimits vectors (plural) alongside the scalar summary properties.
When rendering, prefer the vectors over the scalars. Draw each limit as a step function or connected line through the per-point values.
P and U charts do not expose scalar UpperControlLimit / LowerControlLimit properties. Always use the UpperControlLimits and LowerControlLimits vectors for both rendering and violation detection.
Vector<double> defects =
Vector.Create(new double[] { 3, 5, 2, 7, 4, 6 });
Vector<double> sampleSizes =
Vector.Create(new double[] { 50, 60, 45, 70, 55, 65 });
PChart chart = new PChart(defects, sampleSizes);
chart.Analyze();
// CORRECT: use pointwise vectors for variable-sample P/U charts
Vector<double> upperLimits = chart.Series.UpperControlLimits;
Vector<double> lowerLimits = chart.Series.LowerControlLimits;
Vector<double> points = chart.Series.Values;
for (int i = 0; i < points.Count; i++)
{
Console.WriteLine(
$"Point {i}: p={points[i]:F4} " +
$"LCL={lowerLimits[i]:F4} UCL={upperLimits[i]:F4}");
}
// NOTE: in Deployed state per-point limits are not available;
// use chart.Apply(newCounts, newSizes) to obtain fresh pointwise limits.Chart Family Summary
The table below summarizes the point unit and limit layout for each chart family.
Chart family | Point unit | Scalar limits valid? | Pointwise limits available? |
|---|---|---|---|
Individuals (I) | Individual observation | Yes | No |
Moving Range (MR) | Successive absolute difference | Yes | No |
XBar | Subgroup mean | Yes | No |
R (Range) | Subgroup range | Yes | No |
S (Standard Deviation) | Subgroup standard deviation | Yes | No |
P | Proportion defective | No. Always use vectors | Yes, always |
NP | Count defective | Yes | No |
C | Defect count per unit | Yes | No |
U (variable inspection unit) | Defects per unit | Summary only. Do not use for per-point rendering | Yes, use vectors |
EWMA | Exponentially weighted mean | Yes (asymptotic) | Optional transient-phase vectors |
CUSUM | Cumulative sum statistic | Yes (decision interval h) | No |
Rule-Violation Windows
When a run rule fires, the library records a RuleViolation object with the following properties:
Property | Meaning |
|---|---|
Zero-based index into Values of the trigger point, the observation at which the rule condition was finally satisfied. | |
A short string identifier for the rule (e.g., "N1" for Nelson rule 1, "W1" for Western Electric rule 1). | |
Human-readable description of the rule that fired, suitable for display in a tooltip or report. | |
Zero-based index of the first point in the detection window (the oldest point contributing to the violation). | |
Number of consecutive points in the detection window, ending at TriggerIndex. Always satisfies WindowStart + WindowLength - 1 == Index . |
Rendering Rule Violations
The typical pattern for highlighting a violation window is:
Iterate the Violations collection on RuleSetEvaluation.
For each violation, shade the horizontal region from x = WindowStart - 0.5 to x = WindowStart + WindowLength - 0.5 with a warning color.
Render the trigger point at TriggerIndex with a distinct marker (e.g., filled circle vs. open circle) so that the exact trigger is identifiable at a glance.
double[] data = {
10.5, 11.2, 10.8, 11.5, 10.3, 11.8, 10.1, 11.4,
10.9, 11.1, 10.6, 11.3, 10.7, 11.0, 10.4
};
IndividualsMovingRangeChartSet chart =
new IndividualsMovingRangeChartSet(Vector.Create(data));
chart.Analyze();
RuleSetEvaluation ruleResult =
chart.IndividualsSeries.EvaluateRules(ControlRuleSets.Nelson);
foreach (RuleViolation v in ruleResult.Violations)
{
int windowEnd = v.WindowStart + v.WindowLength - 1;
// Shade the violation window in your charting layer:
// chart.AddHighlight(v.WindowStart, windowEnd, color: Red);
Console.WriteLine(
$"[{v.RuleId}] Highlight points {v.WindowStart}..{windowEnd}");
}Rendering a Basic Control Chart
The minimal steps to render any control chart are the same regardless of charting library:
Plot Values as the primary data series (line + markers).
Draw CenterLine as a solid horizontal reference line.
Draw UpperControlLimit and LowerControlLimit as dashed horizontal lines (or per-point series for variable-limit charts).
Overlay violation highlights using the window model described above.
double[] data = {
10.5, 11.2, 10.8, 11.5, 10.3, 11.8, 10.1, 11.4, 10.9, 11.1
};
IndividualsMovingRangeChartSet chart =
new IndividualsMovingRangeChartSet(Vector.Create(data));
chart.Analyze();
FixedLimitSeries iSeries = chart.IndividualsSeries;
// Map to a hypothetical plotting API:
// chartSeries.Add("I", iSeries.Values);
// chartSeries.AddHorizontalLine("CL", iSeries.CenterLine);
// chartSeries.AddHorizontalLine("UCL", iSeries.UpperControlLimit);
// chartSeries.AddHorizontalLine("LCL", iSeries.LowerControlLimit);
Console.WriteLine($"Points: {iSeries.Values.Count}");
Console.WriteLine(
$"CL={iSeries.CenterLine:F4} UCL={iSeries.UpperControlLimit:F4}");