天津投入产出系统后端
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.

267 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;
}
}
}