Create a control chart

28 Feb 202224 minutes to read

You can create a control chart (with UCL, CL, and LCL limits) using the stripline and annotation features.

To create a control charts, follow the given steps.

Step 1: Load line charts for the data.

@(Html.EJS().Chart("container").Title("Sales History of Product X").Load("load").Loaded("loaded").PointRender("pointRender").Series(series =>
{
    series.Type(Syncfusion.EJ2.Charts.ChartSeriesType.Line).
        XName("xValue").
        YName("yValue").
        Marker(mr => mr.Visible(true).Height(10).Width(10)).
        DataSource(ViewBag.dataSource).Add();
}).
   PrimaryXAxis(px => px.ValueType(Syncfusion.EJ2.Charts.ValueType.DateTime).MajorGridLines(mg => mg.Width(0)).MajorTickLines(mt => mt.Width(0)))
   .PrimaryYAxis(py => py.MajorGridLines(mg => mg.Width(0)).MajorTickLines(mt => mt.Width(0)))
   .Render()
)
public IActionResult Index()
        {
            List<LineChartData> chartData = new List<LineChartData>
            {
                new LineChartData { xValue = new DateTime(1975, 01, 01), yValue = 36},
                new LineChartData { xValue = new DateTime(1980, 01, 01), yValue = 32.5 },
                new LineChartData { xValue = new DateTime(1985, 01, 01), yValue = 39 },
                new LineChartData { xValue = new DateTime(1990, 01, 01), yValue = 34.4 },
                new LineChartData { xValue = new DateTime(1995, 01, 01), yValue = 31.5 },
                new LineChartData { xValue = new DateTime(2000, 01, 01), yValue = 40 },
                new LineChartData { xValue = new DateTime(2005, 01, 01), yValue = 60 },
                new LineChartData { xValue = new DateTime(2010, 01, 01), yValue = 66 },
            };
            ViewBag.dataSource = chartData;
            ViewBag.line = new { width = 0.0001 };
            return View();
        }
        public class LineChartData
        {
            public DateTime xValue;
            public double yValue;
        }

Alt text

Step 2: Now, add three striplines for three control limits: LCL, UCL, and CL.

@(Html.EJS().Chart("container").Title("Sales History of Product X").Load("load").Loaded("loaded").PointRender("pointRender").Series(series =>
{
    series.Type(Syncfusion.EJ2.Charts.ChartSeriesType.Line).
        XName("xValue").
        YName("yValue").
        Marker(mr => mr.Visible(true).Height(10).Width(10)).
        DataSource(ViewBag.dataSource).Add();
}).
   PrimaryXAxis(px => px.ValueType(Syncfusion.EJ2.Charts.ValueType.DateTime).MajorGridLines(mg => mg.Width(0)).MajorTickLines(mt => mt.Width(0)))
   .PrimaryYAxis(py => py.MajorGridLines(mg => mg.Width(0)).MajorTickLines(mt => mt.Width(0)).StripLines(ViewBag.yAxisStripLine))
   .Render()
)
public IActionResult Index()
        {
            List<LineChartData> chartData = new List<LineChartData>
            {
                new LineChartData { xValue = new DateTime(1975, 01, 01), yValue = 36},
                new LineChartData { xValue = new DateTime(1980, 01, 01), yValue = 32.5 },
                new LineChartData { xValue = new DateTime(1985, 01, 01), yValue = 39 },
                new LineChartData { xValue = new DateTime(1990, 01, 01), yValue = 34.4 },
                new LineChartData { xValue = new DateTime(1995, 01, 01), yValue = 31.5 },
                new LineChartData { xValue = new DateTime(2000, 01, 01), yValue = 40 },
                new LineChartData { xValue = new DateTime(2005, 01, 01), yValue = 60 },
                new LineChartData { xValue = new DateTime(2010, 01, 01), yValue = 66 },
            };
            ViewBag.dataSource = chartData;

            ViewBag.line = new { width = 0.0001 };

            List<ChartStripLine> yAxisStripline = new List<ChartStripLine>();
            ChartStripLine ystripline1 = new ChartStripLine();
            ystripline1.Start = "30";
            ystripline1.End = "40";
            ystripline1.Text = "";
            ystripline1.Color = "black";
            ystripline1.Visible = true;

            ChartStripLine ystripline2 = new ChartStripLine();
            ystripline2.Start = "20";
            ystripline2.End = "30";
            ystripline2.Text = "";
            ystripline2.Color = "black";
            ystripline2.Visible = true;

            ChartStripLine ystripline3 = new ChartStripLine();
            ystripline3.Start = "10";
            ystripline3.End = "20";
            ystripline3.Text = "";
            ystripline3.Color = "black";
            ystripline3.Visible = true;

            yAxisStripline.Add(ystripline1);
            yAxisStripline.Add(ystripline2);
            yAxisStripline.Add(ystripline3);
            ViewBag.yAxisStripLine = yAxisStripline;
            return View();
        }
        public class LineChartData
        {
            public DateTime xValue;
            public double yValue;
        }

Step 3: Then, add annotations to show the text for LCL, UCL, and CL in respective positions.

        <ejs-chart id="container" title="Sales History of Product X">
            <e-chart-primaryxaxis valueType="DateTime" majorGridLines="ViewBag.line" majorTickLines="ViewBag.line"></e-chart-primaryxaxis>
            <e-chart-primaryyaxis stripLines="ViewBag.yAxisStripLine" majorGridLines="ViewBag.line" majorTickLines="ViewBag.line"></e-chart-primaryyaxis>
            <e-series-collection>
                <e-series dataSource="ViewBag.dataSource" xName="xValue" yName="yValue" type="@Syncfusion.EJ2.Charts.ChartSeriesType.Line">
                    <e-series-marker visible="true" height="10" width="10"></e-series-marker>
                </e-series>
            </e-series-collection>
            <e-chart-annotations>
                <e-chart-annotation Content="<div>LCL</div>" X="30" Y="2" CoordinateUnits='@Syncfusion.EJ2.Charts.Units.Point'></e-chart-annotation>
                <e-chart-annotation Content="<div>CL</div>" X="30" Y="2" CoordinateUnits='@Syncfusion.EJ2.Charts.Units.Point'></e-chart-annotation>
                <e-chart-annotation Content="<div>UCL</div>" X="30" Y="2" CoordinateUnits='@Syncfusion.EJ2.Charts.Units.Point'></e-chart-annotation>
                <e-chart-annotation Content="<div>Number of groups: xx</div><div>CL: xx</div><div>LCL: xx</div><div>UCL: xx</div><div>Standard Divation: xx</div>" X="400" Y="500" CoordinateUnits='@Syncfusion.EJ2.Charts.Units.Pixel'></e-chart-annotation>
            </e-chart-annotations>
        </ejs-chart>

Step 4: Calculate the control limits based on the CL, LCL, and UCL. The start and end ranges have been set for strip lines in the load event.

<script>
    var mean = 0, LCL = 0, UCL = 0, s = 0;
    function load(args) {
        // calculate the mean value
        for (var i = 0; i < args.chart.series[0].dataSource.length; i++) {
            mean = (mean) + (+args.chart.series[0].dataSource[i].yValue);
        }
        mean = mean / args.chart.series[0].dataSource.length;
        for (var i = 0; i < args.chart.series[0].dataSource.length; i++) {
            s += ((+args.chart.series[0].dataSource[i].yValue) - mean) * ((+args.chart.series[0].dataSource[i].yValue) - mean);
        }
        // calculate the standard divation here
        s = s / args.chart.series[0].dataSource.length;
        s = Math.sqrt(s);
        // Calculate LCL and UCL
        LCL = mean - (1.5 * s);
        UCL = mean + (1.5 * s);
        // set the strip line ranges based on the LCL and UCL
        args.chart.primaryYAxis.stripLines[0].start = LCL;
        args.chart.primaryYAxis.stripLines[0].end = LCL + 0.0125;
        args.chart.primaryYAxis.stripLines[1].start = mean;
        args.chart.primaryYAxis.stripLines[1].end = mean + 0.25;
        args.chart.primaryYAxis.stripLines[2].start = UCL;
        args.chart.primaryYAxis.stripLines[2].end = UCL + 0.0135;
    }
</script>

Alt text

Step 5: Highlight the points that are above the UCL using the pointRender event.

<script>
    function pointRender(args) {
        if (args.point.y > UCL) {
            args.fill = 'red';

        }
    }
</script>

Alt text

Step 6: Change the values of annotation text (UCL, LCL, mean, and CL).

<script>
    var mean = 0, LCL = 0, UCL = 0, s = 0;
    function load(args) {
        // calculate the mean value
        for (var i = 0; i < args.chart.series[0].dataSource.length; i++) {
            mean = (mean) + (+args.chart.series[0].dataSource[i].yValue);
        }
        mean = mean / args.chart.series[0].dataSource.length;
        for (var i = 0; i < args.chart.series[0].dataSource.length; i++) {
            s += ((+args.chart.series[0].dataSource[i].yValue) - mean) * ((+args.chart.series[0].dataSource[i].yValue) - mean);
        }
        // calculate the standard divation here
        s = s / args.chart.series[0].dataSource.length;
        s = Math.sqrt(s);
        // Calculate LCL and UCL
        LCL = mean - (1.5 * s);
        UCL = mean + (1.5 * s);

        // set the annotations x and y positions based on the LCL and UCL
        args.chart.annotations[0].x = args.chart.series[0].dataSource[args.chart.series[0].dataSource.length - 1].xValue;
        args.chart.annotations[0].y = LCL;
        args.chart.annotations[1].x = args.chart.series[0].dataSource[args.chart.series[0].dataSource.length - 1].xValue;
        args.chart.annotations[1].y = mean;
        args.chart.annotations[2].x = args.chart.series[0].dataSource[args.chart.series[0].dataSource.length - 1].xValue;
        args.chart.annotations[2].y = UCL;
    }
</script>

Alt text

Step 7: Add the dasharray for stripline elements and add some pixel for the annotation elements to move from its default position and then add the text for the last annotation to show the mean, UCL, CL, LCL and standard divation in the loaded event.

<script>
    function loaded(args) {
        // Add dasharray for strip line elements
        var strip1 = document.getElementById('container_stripline_Behind_rect_0');
        strip1.setAttribute('stroke', 'black');
        strip1.setAttribute('stroke-dasharray', '5');
        var strip2 = document.getElementById('container_stripline_Behind_rect_2');
        strip2.setAttribute('stroke', 'black');
        strip2.setAttribute('stroke-dasharray', '5');
        var annotation = document.getElementById('container_Annotation_Collections');
        var child, left;

        // move the annotation elements to nearest chart area by adding some pixel to annotation elements
        for (var i = 0; i < annotation.children.length - 1; i++) {
            child = annotation.children[i];
            left = child.style.left;
            left = +(left.replace('px', '')) + 20;
            child.style.left = left + 'px';
        }

        // Add the annotation text to show the mean, UCL, CL, LCL and standard divation
        annotation.children[3].children[0].innerText = annotation.children[3].children[0].innerText.replace('xx', args.chart.series[0].dataSource.length);
        annotation.children[3].children[1].innerText = annotation.children[3].children[1].innerText.replace('xx', mean);
        annotation.children[3].children[2].innerText = annotation.children[3].children[2].innerText.replace('xx', LCL);
        annotation.children[3].children[3].innerText = annotation.children[3].children[3].innerText.replace('xx', UCL);
        annotation.children[3].children[4].innerText = annotation.children[3].children[4].innerText.replace('xx', s);
    }
</script>
@(Html.EJS().Chart("container").Title("Sales History of Product X").Load("load").Loaded("loaded").PointRender("pointRender").Series(series =>
{
    series.Type(Syncfusion.EJ2.Charts.ChartSeriesType.Line).
        XName("xValue").
        YName("yValue").
        Marker(mr => mr.Visible(true).Height(10).Width(10)).
        DataSource(ViewBag.dataSource).Add();
}).Annotations(an =>
{
    an.X("30").Y("2").CoordinateUnits(Syncfusion.EJ2.Charts.Units.Point).Content("<div>LCL</div>").Add();
    an.X("30").Y("2").CoordinateUnits(Syncfusion.EJ2.Charts.Units.Point).Content("<div>CL</div>").Add();
    an.X("30").Y("2").CoordinateUnits(Syncfusion.EJ2.Charts.Units.Point).Content("<div>UCL</div>").Add();
    an.X("400").Y("500").CoordinateUnits(Syncfusion.EJ2.Charts.Units.Point).Content("<div>Number of groups: xx</div><div>CL: xx</div><div>LCL: xx</div><div>UCL: xx</div><div>Standard Divation: xx</div>").Add();
}).
   PrimaryXAxis(px => px.ValueType(Syncfusion.EJ2.Charts.ValueType.DateTime).MajorGridLines(mg => mg.Width(0)).MajorTickLines(mt => mt.Width(0)))
   .PrimaryYAxis(py => py.MajorGridLines(mg => mg.Width(0)).MajorTickLines(mt => mt.Width(0)).StripLines(ViewBag.yAxisStripLine))
   .Render()
)

<script>
    var mean = 0, LCL = 0, UCL = 0, s = 0;
    function load(args) {
        // calculate the mean value
        for (var i = 0; i < args.chart.series[0].dataSource.length; i++) {
            mean = (mean) + (+args.chart.series[0].dataSource[i].yValue);
        }
        mean = mean / args.chart.series[0].dataSource.length;
        for (var i = 0; i < args.chart.series[0].dataSource.length; i++) {
            s += ((+args.chart.series[0].dataSource[i].yValue) - mean) * ((+args.chart.series[0].dataSource[i].yValue) - mean);
        }
        // calculate the standard divation here
        s = s / args.chart.series[0].dataSource.length;
        s = Math.sqrt(s);
        // Calculate LCL and UCL
        LCL = mean - (1.5 * s);
        UCL = mean + (1.5 * s);
        // set the strip line ranges based on the LCL and UCL
        args.chart.primaryYAxis.stripLines[0].start = LCL;
        args.chart.primaryYAxis.stripLines[0].end = LCL + 0.0125;
        args.chart.primaryYAxis.stripLines[1].start = mean;
        args.chart.primaryYAxis.stripLines[1].end = mean + 0.25;
        args.chart.primaryYAxis.stripLines[2].start = UCL;
        args.chart.primaryYAxis.stripLines[2].end = UCL + 0.0135;

        args.chart.annotations[0].x = args.chart.series[0].dataSource[args.chart.series[0].dataSource.length - 1].xValue;
        args.chart.annotations[0].y = LCL;
        args.chart.annotations[1].x = args.chart.series[0].dataSource[args.chart.series[0].dataSource.length - 1].xValue;
        args.chart.annotations[1].y = mean;
        args.chart.annotations[2].x = args.chart.series[0].dataSource[args.chart.series[0].dataSource.length - 1].xValue;
        args.chart.annotations[2].y = UCL;
    }
    function loaded(args) {
        var strip1 = document.getElementById('container_stripline_Behind_rect_primaryYAxis_0');
        strip1.setAttribute('stroke', 'black');
        strip1.setAttribute('stroke-dasharray', '5');
        var strip2 = document.getElementById('container_stripline_Behind_rect_primaryYAxis_0');
        strip2.setAttribute('stroke', 'black');
        strip2.setAttribute('stroke-dasharray', '5');
        var annotation = document.getElementById('container_Annotation_Collections');
        var child, left;
        for (var i = 0; i < annotation.children.length - 1; i++) {
            child = annotation.children[i];
            left = child.style.left;
            left = +(left.replace('px', '')) + 20;
            child.style.left = left + 'px';
        }
        annotation.children[3].children[0].innerText = annotation.children[3].children[0].innerText.replace('xx', args.chart.series[0].dataSource.length);
        annotation.children[3].children[1].innerText = annotation.children[3].children[1].innerText.replace('xx', mean);
        annotation.children[3].children[2].innerText = annotation.children[3].children[2].innerText.replace('xx', LCL);
        annotation.children[3].children[3].innerText = annotation.children[3].children[3].innerText.replace('xx', UCL);
        annotation.children[3].children[4].innerText = annotation.children[3].children[4].innerText.replace('xx', s);
    }

    function pointRender(args) {
        if (args.point.y > UCL) {
            args.fill = 'red';

        }
    }
</script>
public IActionResult Index()
        {
            List<LineChartData> chartData = new List<LineChartData>
            {
                new LineChartData { xValue = new DateTime(1975, 01, 01), yValue = 36},
                new LineChartData { xValue = new DateTime(1980, 01, 01), yValue = 32.5 },
                new LineChartData { xValue = new DateTime(1985, 01, 01), yValue = 39 },
                new LineChartData { xValue = new DateTime(1990, 01, 01), yValue = 34.4 },
                new LineChartData { xValue = new DateTime(1995, 01, 01), yValue = 31.5 },
                new LineChartData { xValue = new DateTime(2000, 01, 01), yValue = 40 },
                new LineChartData { xValue = new DateTime(2005, 01, 01), yValue = 60 },
                new LineChartData { xValue = new DateTime(2010, 01, 01), yValue = 66 },
            };
            ViewBag.dataSource = chartData;
            
            List<ChartStripLine> yAxisStripline = new List<ChartStripLine>();
            ChartStripLine ystripline1 = new ChartStripLine();
            ystripline1.Start = "30";
            ystripline1.End = "40";
            ystripline1.Text = "";
            ystripline1.Color = "black";
            ystripline1.Visible = true;

            ChartStripLine ystripline2 = new ChartStripLine();
            ystripline2.Start = "20";
            ystripline2.End = "30";
            ystripline2.Text = "";
            ystripline2.Color = "black";
            ystripline2.Visible = true;

            ChartStripLine ystripline3 = new ChartStripLine();
            ystripline3.Start = "10";
            ystripline3.End = "20";
            ystripline3.Text = "";
            ystripline3.Color = "black";
            ystripline3.Visible = true;

            yAxisStripline.Add(ystripline1);
            yAxisStripline.Add(ystripline2);
            yAxisStripline.Add(ystripline3);
            ViewBag.yAxisStripLine = yAxisStripline;
            return View();
        }
        public class LineChartData
        {
            public DateTime xValue;
            public double yValue;
        }

Screenshots:

Alt text

Sample link: A sample for creating control chart is available in the following link, chartSample.