You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
266 lines
11 KiB
266 lines
11 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Windows.Forms.DataVisualization.Charting;
|
|
using System.Drawing;
|
|
using System.Data;
|
|
|
|
namespace QMAPP.WinForm.Common.SPCMonitor
|
|
{
|
|
/// <summary>
|
|
/// 描述:SPC图表帮助类
|
|
/// 作者:单雨春
|
|
/// 日期:2015年5月28日11:03:02
|
|
/// </summary>
|
|
public class ChartHelper
|
|
{
|
|
/// <summary>
|
|
/// 画趋势图
|
|
/// </summary>
|
|
/// <param name="chart"></param>
|
|
/// <param name="chartValue"></param>
|
|
/// <returns></returns>
|
|
public static Chart DrawTendencyChart(Chart chart, DataTable dt, string quota)
|
|
{
|
|
//获得坐标的最大值及最小值
|
|
ChartValueModel chartValue = GetChartValueForTendency(dt, quota);
|
|
|
|
//设置图表的坐标
|
|
chart.ChartAreas.FirstOrDefault().AxisY.Interval = chartValue.Step;
|
|
chart.ChartAreas.FirstOrDefault().AxisY.Maximum = chartValue.MaxOfCoord;
|
|
chart.ChartAreas.FirstOrDefault().AxisY.Minimum = chartValue.MinOfCoord;
|
|
|
|
//画上限、下限之间的格线
|
|
for (double tempValue = chartValue.Min; tempValue < chartValue.Max; tempValue += chartValue.Step)
|
|
{
|
|
StripLine dash = new StripLine();
|
|
dash.BackColor = System.Drawing.Color.Silver;
|
|
dash.BorderDashStyle = ChartDashStyle.Dash;
|
|
dash.IntervalOffset = Math.Round(tempValue,2);
|
|
dash.StripWidth = 0.0001;
|
|
chart.ChartAreas.FirstOrDefault().AxisY.StripLines.Add(dash);
|
|
}
|
|
|
|
//下限
|
|
StripLine minLine = new StripLine();
|
|
minLine.BackColor = Color.FromArgb(0, 90, 0);
|
|
minLine.BorderDashStyle = ChartDashStyle.Dash;
|
|
minLine.IntervalOffset = Convert.ToDouble(chartValue.Min);
|
|
minLine.StripWidth = 0.0001;
|
|
minLine.Text = chartValue.Min.ToString();
|
|
minLine.TextAlignment = StringAlignment.Far;
|
|
chart.ChartAreas.FirstOrDefault().AxisY.StripLines.Add(minLine);
|
|
|
|
//上限
|
|
StripLine maxLine = new StripLine();
|
|
maxLine.BackColor = Color.FromArgb(0, 90, 0);
|
|
maxLine.BorderDashStyle = ChartDashStyle.Dash;
|
|
maxLine.IntervalOffset = Convert.ToDouble(chartValue.Max);
|
|
maxLine.StripWidth = 0.0001;
|
|
maxLine.Text = chartValue.Max.ToString();
|
|
maxLine.TextAlignment = StringAlignment.Far;
|
|
chart.ChartAreas.FirstOrDefault().AxisY.StripLines.Add(maxLine);
|
|
|
|
//中值
|
|
StripLine midLine = new StripLine();
|
|
midLine.BackColor = Color.FromArgb(0, 90, 0);
|
|
midLine.BorderDashStyle = ChartDashStyle.Dash;
|
|
midLine.IntervalOffset = Convert.ToDouble(chartValue.Middle);
|
|
midLine.StripWidth = 0.0001;
|
|
midLine.Text = chartValue.Middle.ToString();
|
|
midLine.TextAlignment = StringAlignment.Far;
|
|
chart.ChartAreas.FirstOrDefault().AxisY.StripLines.Add(midLine);
|
|
|
|
//去掉X轴的标签
|
|
chart.ChartAreas.FirstOrDefault().AxisX.LabelStyle.Enabled = false;
|
|
return chart;
|
|
}
|
|
|
|
// <summary>
|
|
/// 画分布
|
|
/// </summary>
|
|
/// <param name="chart"></param>
|
|
/// <param name="chartValue"></param>
|
|
/// <returns></returns>
|
|
public static Chart DrawDistributionChart(Chart chart, DataTable dt,Dictionary<double, int> dict, string quota)
|
|
{
|
|
//获得坐标的最大值及最小值
|
|
ChartValueModel chartValue = GetChartValueForDistribution(dt, quota);
|
|
|
|
//设置图表的坐标
|
|
chart.ChartAreas.FirstOrDefault().AxisX.Interval = chartValue.Step;
|
|
chart.ChartAreas.FirstOrDefault().AxisX.Maximum = chartValue.MaxOfCoord;
|
|
chart.ChartAreas.FirstOrDefault().AxisX.Minimum = chartValue.MinOfCoord;
|
|
|
|
//均值
|
|
double avg = dt.AsEnumerable().Average(p => Convert.ToDouble(p[quota]));
|
|
//均方差
|
|
double dev = Math.Sqrt(dt.AsEnumerable().Average(p => Math.Pow(Convert.ToDouble(p[quota]) - avg, 2)));
|
|
|
|
//标题
|
|
Title title = new Title("3σ = " + 3 * Math.Round(dev, 6) + "\n" + " ¯x = " + Math.Round(avg, 6), Docking.Right);
|
|
title.TextOrientation = TextOrientation.Horizontal;
|
|
title.Alignment = ContentAlignment.TopRight;
|
|
title.ForeColor = System.Drawing.Color.RoyalBlue;
|
|
title.IsDockedInsideChartArea = true;
|
|
title.DockedToChartArea = "ChartA";
|
|
chart.Titles.Add(title);
|
|
|
|
//高斯图形
|
|
Series seriesGaussian = GetGaussianSeries(dict.Values.Max(), avg, dev);
|
|
chart.Series.Add(seriesGaussian);
|
|
|
|
//下限
|
|
StripLine minLine = new StripLine();
|
|
minLine.BackColor = System.Drawing.Color.Green;
|
|
minLine.BorderDashStyle = ChartDashStyle.Dash;
|
|
minLine.IntervalOffset = avg - 3 * dev;
|
|
minLine.StripWidth = 0.0001;
|
|
minLine.Text = "3σ";
|
|
minLine.TextAlignment = StringAlignment.Far;
|
|
minLine.TextOrientation = TextOrientation.Horizontal;
|
|
chart.ChartAreas.FirstOrDefault().AxisX.StripLines.Add(minLine);
|
|
|
|
//上限
|
|
StripLine maxLine = new StripLine();
|
|
maxLine.BackColor = System.Drawing.Color.Green;
|
|
maxLine.BorderDashStyle = ChartDashStyle.Dash;
|
|
maxLine.IntervalOffset = avg + 3 * dev;
|
|
maxLine.StripWidth = 0.0001;
|
|
maxLine.Text = "3σ";
|
|
maxLine.TextAlignment = StringAlignment.Far;
|
|
maxLine.TextOrientation = TextOrientation.Horizontal;
|
|
chart.ChartAreas.FirstOrDefault().AxisX.StripLines.Add(maxLine);
|
|
|
|
//中值
|
|
StripLine midLine = new StripLine();
|
|
midLine.BackColor = System.Drawing.Color.Orange;
|
|
midLine.BorderDashStyle = ChartDashStyle.Dash;
|
|
midLine.IntervalOffset = avg;
|
|
midLine.StripWidth = 0.0001;
|
|
midLine.Text = "¯x";
|
|
midLine.TextOrientation = TextOrientation.Stacked;
|
|
midLine.TextAlignment = StringAlignment.Far;
|
|
chart.ChartAreas.FirstOrDefault().AxisX.StripLines.Add(midLine);
|
|
|
|
//去掉Y轴的标签
|
|
chart.ChartAreas.FirstOrDefault().AxisY.LabelStyle.Enabled = false;
|
|
return chart;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 趋势图-设置坐标及间隔
|
|
/// </summary>
|
|
/// <param name="dr"></param>
|
|
/// <returns></returns>
|
|
public static ChartValueModel GetChartValueForTendency(DataTable dt, string quota)
|
|
{
|
|
ChartValueModel chartValue = new ChartValueModel();
|
|
DataRow dr = dt.AsEnumerable().FirstOrDefault();
|
|
|
|
|
|
//取得最大值和最小值
|
|
chartValue.Min = Convert.ToDouble(dr["MIN"]);
|
|
chartValue.Max = Convert.ToDouble(dr["MAX"]);
|
|
chartValue.Middle = Convert.ToDouble(chartValue.Min + chartValue.Max) / 2;
|
|
|
|
//计算间隔
|
|
chartValue.Step = (chartValue.Max - chartValue.Min) / 10.0;
|
|
|
|
//计算最大坐标和最小坐标
|
|
chartValue.MaxOfCoord = chartValue.Max + chartValue.Step * 5;
|
|
chartValue.MinOfCoord = chartValue.Min - chartValue.Step * 5;
|
|
|
|
return chartValue;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 分布图-设置坐标及间隔
|
|
/// </summary>
|
|
/// <param name="dr"></param>
|
|
/// <returns></returns>
|
|
public static ChartValueModel GetChartValueForDistribution(DataTable dt, string quota)
|
|
{
|
|
ChartValueModel chartValue = new ChartValueModel();
|
|
DataRow dr = dt.AsEnumerable().FirstOrDefault();
|
|
//取得最大值和最小值
|
|
chartValue.Min = dt.AsEnumerable().Min(p => Convert.ToDouble(p[quota]));
|
|
chartValue.Max = dt.AsEnumerable().Max(p => Convert.ToDouble(p[quota]));
|
|
|
|
//计算间隔
|
|
chartValue.Step = double.Parse(dr["STEP"].ToString());
|
|
|
|
//计算最大坐标和最小坐标
|
|
chartValue.MaxOfCoord = chartValue.Max + chartValue.Step * 3;
|
|
chartValue.MinOfCoord = chartValue.Min - chartValue.Step * 3;
|
|
|
|
return chartValue;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取高斯函数图形
|
|
/// </summary>
|
|
/// <param name="yMax">Y轴最大</param>
|
|
/// <param name="avg">均值</param>
|
|
/// <param name="dev">均方差</param>
|
|
/// <returns></returns>
|
|
private static Series GetGaussianSeries(int yMax, double avg, double dev)
|
|
{
|
|
#region 高斯算法
|
|
List<GaussianModel> gass = new List<GaussianModel>();
|
|
double min = avg - 6 * dev;
|
|
double max = avg + 6 * dev;
|
|
double step = (max - min) / 100;
|
|
if (step == 0)
|
|
step = Int32.MaxValue;
|
|
for (double m = min; m <= max; m += step)
|
|
{
|
|
GaussianModel model = new GaussianModel();
|
|
double y = (1 / (Math.Sqrt(2 * Math.PI) * dev)) * Math.Pow(Math.E, 0 - (Math.Pow(m - avg, 2) / (2 * Math.Pow(dev, 2))));
|
|
model.X = m;
|
|
model.Y = y;
|
|
gass.Add(model);
|
|
}
|
|
#endregion
|
|
|
|
#region 画高斯图形
|
|
Series seriesGass = new Series();
|
|
seriesGass.ChartType = SeriesChartType.Spline;
|
|
double pram = 0;
|
|
double temp = 0;
|
|
pram = yMax * 1.1;
|
|
//double gassMax = gass[50].Y;
|
|
double gassMax = gass.Max<GaussianModel>(o => o.Y);
|
|
temp = pram / gassMax;
|
|
foreach (GaussianModel item in gass)
|
|
{
|
|
seriesGass.Points.AddXY(item.X, temp * item.Y);
|
|
}
|
|
#endregion
|
|
|
|
return seriesGass;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 取Bar图的所有坐标
|
|
/// </summary>
|
|
/// <param name="dr"></param>
|
|
/// <returns></returns>
|
|
public static Dictionary<double, int> GetBarValue(DataTable dt, string quota)
|
|
{
|
|
Type type = dt.Columns[quota].DataType;
|
|
Dictionary<double, int> dict = new Dictionary<double, int>();
|
|
double min = dt.AsEnumerable().Min(p => Convert.ToDouble(p[quota]));
|
|
double max = dt.AsEnumerable().Max(p => Convert.ToDouble(p[quota]));
|
|
double step = Convert.ToDouble(dt.AsEnumerable().FirstOrDefault()["STEP"]);
|
|
|
|
for (double tempValue = min; tempValue <= max; tempValue += step)
|
|
{
|
|
var rowCount = dt.AsEnumerable().Where(p => Convert.ToDouble(p[quota]) > tempValue - step/2 && Convert.ToDouble(p[quota]) <= tempValue + step/2).Count();
|
|
dict.Add(tempValue, rowCount);
|
|
}
|
|
return dict;
|
|
}
|
|
}
|
|
}
|
|
|