Click here to Skip to main content
Click here to Skip to main content

SPC XBAR and Range Chart

, 16 Jul 2014 CPOL
Rate this:
Please Sign up or sign in to vote.
XBAR and Range Chart using C#

Introduction

Before we start refer my previous article about Control Chart for USL and LSL Control Chart Link.In my previous article i have explained about how to create a simple Control Bar Chart for USL and LSL data check.

In this article today iam going to explain how to create a simple SPC (Statistical Process Control) X-bar and Range Line Chart.If your interested to learn about SPC and X-Bar ,Range Chart refer to the below links.

https://www.moresteam.com/toolbox/statistical-process-control-spc.cfm
http://www.qualitytrainingportal.com/resources/spc/form_3839a_app1.htm
http://www.pqsystems.com/qualityadvisor/formulas/x_bar_range_f.php

now lets see how I have created a SPC X-Bar and Range chart.My main aim is to make a ver simple SPC Chart which can be used by the end users.

I have created a SPC Xbar/Range Chart  as a User Control so that it can be used easily in all projects.

In this article i have attached zip file named as SHANUSPCXbarRangeChartSRC.zip. Which contains .

1) "SHANUXbarRangeChart" Folder (This folder contains the SHANUXbarRangeChart User control Source code.

2) "SHANUSPCXBarDemo" Folder (This folder conains the Demo program which includes the SHANUXbarRangeChart user control with Random Data sample).

Note : I have used DataTable as the datainput for the UserControl .from the windows form we need to pass the DataTable to User control to plot the XBAR and Range Line Graph.

Using the code

1) First we will start with the User Control .To Create a user control .

  1. Create a new Windows Control Library project.
  2. Set the Name of Project and Click Ok(here my user control name is SHANUXbarRangeChart).
  3. Add all the controls which is needed.
  4. In code behind declare all the public variables and Public Method.In User control i have added one panel and one PictureBox Control named as "PIC_SHANUSPC"
 //Public Variable
        
        public DataTable dt=new DataTable();
        Font f12 = new Font("arial", 12, FontStyle.Bold, GraphicsUnit.Pixel);
        Pen B1pen = new Pen(Color.Black, 1);
        Pen B2pen = new Pen(Color.Black, 2);
        Double XDoublkeBAR = 0;
        Double RBAR = 0;
        Double XBARUCL = 0;
        Double XBARLCL = 0;

        Double RANGEUCL = 0;
        Double RANGELCL = 0;
        Double[] intMeanArrayVals;
        Double[] intRangeArrayVals;
        int First_chartDatarectHeight = 80;
        Font f10 = new Font("arial", 10, FontStyle.Bold, GraphicsUnit.Pixel);
        LinearGradientBrush a2 = new LinearGradientBrush(new RectangleF(0, 0, 100, 19), Color.DarkGreen, Color.Green, LinearGradientMode.Horizontal);
        LinearGradientBrush a1 = new LinearGradientBrush(new RectangleF(0, 0, 100, 19), Color.Blue, Color.DarkBlue, LinearGradientMode.Horizontal);

Once declared the variable I have created a public function as Bindgrid.This function will be used from windows form to pass the DataTable.In this function i check for the DataTable and if the DataTable is not null I refresh the PictureBox which will call the PictureBox paint method.

 public void Bindgrid(DataTable dtnew)
    {
        if (dtnew != null)
        {
            dt = dtnew;
            PIC_SHANUSPC.Refresh();
        }
   }

In PictureBox paint event I will check for the DataTable data .using the data i have created the  Sum, Mean and Range of all Data.Using this information I have created UCL and LCL by Standard formula .for details about UCL and LCL calculation kindly check the above links. Using all this information i have draw the SPC XBAR and Range Chart using GrawLine,DrawRectangle

  //Paint Method 
        public void PIC_SHANUSPC_Paint(object sender, PaintEventArgs e)
       {
           if (dt.Rows.Count <= 0)
           {
               return;
           }
           int opacity = 48; 

           e.Graphics.DrawString("SHANU SPC CHART",
               new Font("Arial", 72),
               new SolidBrush(Color.FromArgb(opacity, Color.OrangeRed)),
               80,
                PIC_SHANUSPC.Height / 2 - 50);


           int NoofTrials = dt.Rows.Count;
           int NoofParts = dt.Columns.Count - 1;


           intMeanArrayVals = new Double[NoofParts];
           intRangeArrayVals = new Double[NoofParts];

          
           PIC_SHANUSPC.Width = dt.Columns.Count * 50 + 40;


           // 1) For the Chart Data Display ---------
           e.Graphics.DrawRectangle(Pens.Black, 10, 10, PIC_SHANUSPC.Width - 20, First_chartDatarectHeight);

           // for the chart data Horizontal Line Display
           e.Graphics.DrawLine(B1pen, 10, 30, PIC_SHANUSPC.Width - 10, 30);
           e.Graphics.DrawLine(B1pen, 10, 60, PIC_SHANUSPC.Width - 10, 60);


           // for the chart data Vertical Line Display
           e.Graphics.DrawLine(B1pen, 60, 10, 60, First_chartDatarectHeight + 8);
           e.Graphics.DrawLine(B1pen, 110, 10, 110, First_chartDatarectHeight + 8);

           //-------------

           // DrawItemEventArgs String

           e.Graphics.DrawString("SUM", f12, a1, 14, 12);

           e.Graphics.DrawString("MEAN", f12, a1, 14, 40);

           e.Graphics.DrawString("Range", f12, a1, 14, 68);


           // load data 
           //Outer Loop for Columns count
           int xLineposition = 110;
           int xStringDrawposition = 14;

           for (int iCol = 1; iCol <= dt.Columns.Count - 1; iCol++)
           {
               //inner Loop for Rows count
               Double Sumresult = 0;
               Double Meanresult = 0;
               Double Rangeresult = 0;


               Double minRangeValue = int.MaxValue;
               Double maxRangeValue = int.MinValue;


               for (int iRow = 0; iRow < dt.Rows.Count; iRow++)
               {
                   Sumresult = Sumresult + System.Convert.ToDouble(dt.Rows[iRow][iCol].ToString());

                   Double accountLevel = System.Convert.ToDouble(dt.Rows[iRow][iCol].ToString());
                   minRangeValue = Math.Min(minRangeValue, accountLevel);
                   maxRangeValue = Math.Max(maxRangeValue, accountLevel);

               }
               xLineposition = xLineposition + 50;
               xStringDrawposition = xStringDrawposition + 50;

               e.Graphics.DrawLine(B1pen, xLineposition, 10, xLineposition, First_chartDatarectHeight + 8);
               //Sum Data Display
               e.Graphics.DrawString(Math.Round(Sumresult, 3).ToString(), f10, a2, xStringDrawposition, 12);

               //MEAN Data Display
               Meanresult = Sumresult / NoofTrials;
               e.Graphics.DrawString(Math.Round(Meanresult, 3).ToString(), f10, a2, xStringDrawposition, 40);
               //RANGE Data Display
               Rangeresult = maxRangeValue - minRangeValue;
               e.Graphics.DrawString(Math.Round(Rangeresult, 3).ToString(), f10, a2, xStringDrawposition, 68);


               //XDoubleBar used to display in chart
               XDoublkeBAR = XDoublkeBAR + Meanresult;

               //RBAR used to display in chart
               RBAR = RBAR + Rangeresult;

               intMeanArrayVals[iCol - 1] = Meanresult;
               intRangeArrayVals[iCol - 1] = Rangeresult;

           }
           //End 1 ) -------------------

           // 2) -------------------------- 
           // XdoubleBAr/RBAR/UCL and LCL Calculation.

           //XDoubleBar used to display in chart
           XDoublkeBAR = XDoublkeBAR / NoofParts;

           //RBAR used to display in chart
           RBAR = RBAR / NoofParts;

           //XBARUCL to display in chart
           XBARUCL = XDoublkeBAR + UCLLCLTYPE("A2", RBAR, NoofTrials);
           //XBARLCL to display in chart
           XBARLCL = XDoublkeBAR - UCLLCLTYPE("A2", RBAR, NoofTrials);

           //XBARUCL to display in chart
           RANGEUCL = UCLLCLTYPE("D4", RBAR, NoofTrials);

           //XBARLCL to display in chart
           RANGELCL = UCLLCLTYPE("D3", RBAR, NoofTrials);

           //---------------------------------

           //3) Average chart Display ---------------
           //  e.Graphics.DrawRectangle(Pens.Black, 10, 10, picSpcChart.Width - 20, First_chartDatarectHeight);
           int chartAvarageDatarectHeight = 18;

           e.Graphics.DrawRectangle(Pens.Black, 10, First_chartDatarectHeight + 20, PIC_SHANUSPC.Width - 20, chartAvarageDatarectHeight);

           e.Graphics.DrawLine(B2pen, 476, 116, 480, 100);
           e.Graphics.DrawString("MEAN CHART", f12, a1, 14, First_chartDatarectHeight + 22);

           e.Graphics.DrawString("XBarS:", f12, a1, 160, First_chartDatarectHeight + 22);
           e.Graphics.DrawString(Math.Round(XDoublkeBAR, 3).ToString(), f12, a2, 202, First_chartDatarectHeight + 22);

           e.Graphics.DrawString("UCL:", f12, a1, 300, First_chartDatarectHeight + 22);
           e.Graphics.DrawString(Math.Round(XBARUCL, 3).ToString(), f12, a2, 330, First_chartDatarectHeight + 22);

           e.Graphics.DrawString("LCL:", f12, a1, 400, First_chartDatarectHeight + 22);
           e.Graphics.DrawString(Math.Round(XBARLCL, 3).ToString(), f12, a2, 430, First_chartDatarectHeight + 22);

           e.Graphics.DrawString("RANGE CHART", f12, a1, 490, First_chartDatarectHeight + 22);


           e.Graphics.DrawString("RBar : ", f12, a1, 600, First_chartDatarectHeight + 22);
           e.Graphics.DrawString(Math.Round(RBAR, 3).ToString(), f12, a2, 638, First_chartDatarectHeight + 22);

           e.Graphics.DrawString("UCL : ", f12, a1, 700, First_chartDatarectHeight + 22);
           e.Graphics.DrawString(Math.Round(RANGEUCL, 3).ToString(), f12, a2, 734, First_chartDatarectHeight + 22);

           e.Graphics.DrawString("LCL : ", f12, a1, 800, First_chartDatarectHeight + 22);
           e.Graphics.DrawString(Math.Round(RANGELCL, 3).ToString(), f12, a2, 834, First_chartDatarectHeight + 22);

           //Mean Line Chart

           DrawLineChart(e.Graphics, intMeanArrayVals, XBARUCL, XBARLCL, PIC_SHANUSPC.Width - 70, 164, 60, 130, "MEAN");

           DrawLineChart(e.Graphics, intRangeArrayVals, RANGEUCL, RANGELCL, PIC_SHANUSPC.Width - 70, 164, 60, 300, "RANGE");

           //End 3)---------------------

       }

For UCL and LCL we need use the A2,D4,D3 Constants in calculation.For this i have created a Function named as "UCLLCLTYPE" which will return the constants. For Example to calculate UCL and LCL see th code below.

//In paint method we have used this to call the UCL and LCL constant data.

//XBARUCL to display in chart - >This is to calculate  XBAR UCL
           XBARUCL = XDoublkeBAR + UCLLCLTYPE("A2", RBAR, NoofTrials);
           //XBARLCL to display in chart - >This is to calculate  XBAR LCL
           XBARLCL = XDoublkeBAR - UCLLCLTYPE("A2", RBAR, NoofTrials);

           //RANGEUCL to display in chart 
           RANGEUCL = UCLLCLTYPE("D4", RBAR, NoofTrials);

           //RANGELCL to display in chart
           RANGELCL = UCLLCLTYPE("D3", RBAR, NoofTrials);

 public double UCLLCLTYPE(String ControlUCLLCLType, Double RBAR, int NoofTrials)
       {
           Double Result = 0;
           Double A2Val = 0;
           Double D3val = 0;
           Double D4val = 0;
           //Constant value for the UCL and LCL calculation.
           if (ControlUCLLCLType == "A2")
           {
               switch (NoofTrials)
               {
                   case 2:
                       A2Val = 1.880;
                       break;
                   case 3:
                       A2Val = 1.023;
                       break;
                   case 4:
                       A2Val = 0.729;
                       break;
                   case 5:
                       A2Val = 0.577;
                       break;
                   case 6:
                       A2Val = 0.483;
                       break;
                   case 7:
                       A2Val = 0.419;
                       break;
                   case 8:
                       A2Val = 0.373;
                       break;
                   case 9:
                       A2Val = 0.337;
                       break;
                   case 10:
                       A2Val = 0.308;
                       break;
                   case 11:
                       A2Val = 0.285;
                       break;
                   case 12:
                       A2Val = 0.266;
                       break;
                   case 13:
                       A2Val = 0.249;
                       break;
                   case 14:
                       A2Val = 0.235;
                       break;
                   case 15:
                       A2Val = 0.223;
                       break;
                   case 16:
                       A2Val = 0.212;
                       break;
                   case 17:
                       A2Val = 0.203;
                       break;
                   case 18:
                       A2Val = 0.194;
                       break;
                   case 19:
                       A2Val = 0.187;
                       break;
                   case 20:
                       A2Val = 0.180;
                       break;

                   case 21:
                       A2Val = 0.173;
                       break;
                   case 22:
                       A2Val = 0.167;
                       break;
                   case 23:
                       A2Val = 0.162;
                       break;
                   case 24:
                       A2Val = 0.157;
                       break;
                   case 25:
                       A2Val = 0.153;
                       break;


               }
               Result = A2Val * RBAR;
           }
           else if (ControlUCLLCLType == "D3")
           {
               switch (NoofTrials)
               {
                   case 2:
                       D3val = 0;
                       break;
                   case 3:
                       D3val = 0;
                       break;
                   case 4:
                       D3val = 0;
                       break;
                   case 5:
                       D3val = 0;
                       break;
                   case 6:
                       D3val = 0;
                       break;
                   case 7:
                       D3val = 0.076;
                       break;
                   case 8:
                       D3val = 0.136;
                       break;
                   case 9:
                       D3val = 0.184;
                       break;
                   case 10:
                       D3val = 0.223;
                       break;
                   case 11:
                       D3val = 0.256;
                       break;
                   case 12:
                       D3val = 0.283;
                       break;
                   case 13:
                       D3val = 0.307;
                       break;
                   case 14:
                       D3val = 0.328;
                       break;
                   case 15:
                       D3val = 0.347;
                       break;
                   case 16:
                       D3val = 0.363;
                       break;
                   case 17:
                       D3val = 0.378;
                       break;
                   case 18:
                       D3val = 0.391;
                       break;
                   case 19:
                       D3val = 0.403;
                       break;
                   case 20:
                       D3val = 0.415;
                       break;

                   case 21:
                       D3val = 0.425;
                       break;
                   case 22:
                       D3val = 0.434;
                       break;
                   case 23:
                       D3val = 0.443;
                       break;
                   case 24:
                       D3val = 0.451;
                       break;
                   case 25:
                       D3val = 0.459;
                       break;


               }
               Result = D3val * RBAR;

           }
           else if (ControlUCLLCLType == "D4")
           {
               switch (NoofTrials)
               {
                   case 2:
                       D4val = 3.268;
                       break;
                   case 3:
                       D4val = 2.574;
                       break;
                   case 4:
                       D4val = 2.282;
                       break;
                   case 5:
                       D4val = 2.114;
                       break;
                   case 6:
                       D4val = 2.004;
                       break;
                   case 7:
                       D4val = 1.924;
                       break;
                   case 8:
                       D4val = 1.864;
                       break;
                   case 9:
                       D4val = 1.816;
                       break;
                   case 10:
                       D4val = 1.777;
                       break;
                   case 11:
                       D4val = 1.744;
                       break;
                   case 12:
                       D4val = 1.717;
                       break;
                   case 13:
                       D4val = 1.693;
                       break;
                   case 14:
                       D4val = 1.672;
                       break;
                   case 15:
                       D4val = 1.653;
                       break;
                   case 16:
                       D4val = 1.637;
                       break;
                   case 17:
                       D4val = 1.622;
                       break;
                   case 18:
                       D4val = 1.608;
                       break;
                   case 19:
                       D4val = 1.597;
                       break;
                   case 20:
                       D4val = 1.585;
                       break;

                   case 21:
                       D4val = 1.575;
                       break;
                   case 22:
                       D4val = 1.566;
                       break;
                   case 23:
                       D4val = 1.557;
                       break;
                   case 24:
                       D4val = 1.548;
                       break;
                   case 25:
                       D4val = 1.541;
                       break;


               }
               Result = D4val * RBAR;

           }

           return Result;
       }

  6.After completion save,Build and run the project.

2) Now we create a Windows application and add and test our "SHANUXbarRangeChart" User Control.

  1. Create a new Windows project.
  2. Open your form and then from Toolbox > right click > choose items > browse select your user control dll and add.
  3.  Drag the User Control to your windows form.
  4. Call the "Bindgrid" Method of user control and pass the Datatable to Usercontrol and check the result.
 private void button1_Click(object sender, EventArgs e)
        {
            loadgrid();
//shanuXBARChart is the User-control Name here we call the function and pass the DataTable.
            shanuXBARChart.Bindgrid(dt);          
        }

In the "loadgrid" method i load the random data to DataTable and display in grid view.

Conclusion

The main aim of this article is to create a simple and standard SPC X-Bar and Range  Chart user control .I have planed to add more featuers to the chart.

History

Initial release on 2014/07/16.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

syed shanu
Team Leader
India India
Visit My SHANU C# Blog
Mr.Shanu is a Senior Software Engineer. He’s basically from India and working at South Korea for more than 7 years.


He has 9+ years of Experience in Microsoft Technologies. More than 7 Years of experience in Automation Fields, He has worked in several projects of MES, Automation, ERP and HMI programs like PLC, Sensor, RFID and Nutrunner Tools. He has worked in both Windows based and Web Based projects.


Shanu Love to learn and work with new technology.


His main hobbies are to spend time with Family and to create Different and Innvotive programs and write Article about his program and Share with others.

His Latest Article which he likes most was Windows Form Design at Run Time

His facebook page
Follow on   Twitter   Google+   LinkedIn

Comments and Discussions

 
Suggestiongood job PinmemberMember 1077984122-Oct-14 17:40 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.141220.1 | Last Updated 16 Jul 2014
Article Copyright 2014 by syed shanu
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid