Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

SPC XBAR and Range Chart

0.00/5 (No votes)
25 Jan 2015 1  
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 how to create a simple Control Bar Chart for USL and LSL data check.

In this article today, I am going to explain how to create a simple SPC (Statistical Process Control) X-bar and Range Line Chart. If you are interested in learning about SPC and X-Bar, Range Chart refers to the below links:

Now, let's see how I have created a SPC X-Bar and Range chart. My main aim is to make a very 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 a zip file named as SHANUSPCXbarRangeChartSRC.zip which contains:

  1. "SHANUXbarRangeChart" folder (This folder contains the <span style="font-size: 12px; background-color: rgb(255,255,255)">SHANUXbarRangeChart</span> User control source code.)
  2. "SHANUSPCXBarDemo" folder (This folder contains the demo program which includes the <span style="font-size: 12px; background-color: rgb(255,255,255)">SHANUXbarRangeChart</span> 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 <span style="font-size: 12px; background-color: rgb(255,255,255)">SHANUXbarRangeChart</span>).
    3. Add all the controls which are 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 the variable is declared, 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 drawn 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 to 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 the 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;
             }
    5. 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 gridview.

Conclusion

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

History

  • 2014/07/16: Initial release

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here