SPC XBAR and Range Chart





5.00/5 (5 votes)
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:
- 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, 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:
- "SHANUXbarRangeChart" folder (This folder contains the
<span style="font-size: 12px; background-color: rgb(255,255,255)">SHANUXbarRangeChart</span>
User control source code.) - "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
- First, we will start with the User Control. To create a user control:
- Create a new Windows Control Library project.
- 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>
). - Add all the controls which are needed.
- In code behind, declare all the
public
variables andPublic
method. In User control, I have added one panel and onePictureBox
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 asBindgrid
. This function will be used from Windows Form to pass theDataTable
. In this function, I check for theDataTable
and if theDataTable
is notnull
, I refresh thePictureBox
which will call thePictureBox paint
method.public void Bindgrid(DataTable dtnew) { if (dtnew != null) { dt = dtnew; PIC_SHANUSPC.Refresh(); } }
In
PictureBox paint
event, I will check for theDataTable
data. Using the data, I have created theSum
,Mean
andRange
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 usingGrawLine
,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; }
- After completion save, build and run the project.
- Now, we create a Windows application and add and test our "
SHANUXbarRangeChart
" User Control.- Create a new Windows project.
- Open your form and then from Toolbox > right click > choose items >, browse select your user control DLL and add.
- Drag the User Control to your Windows Form.
- Call the "
Bindgrid
" method of user control and pass theDatatable
toUsercontrol
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 toDataTable
and display ingridview
.
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