代码有注释,在通用性方面进行了处理

可以指定极值,可以自定义分段,对样本数据分段比较灵活,

不填临界值时平均分段,不指定极值时样本数据中的最大值为极大值。极小值默认为0,但可以设置。

    /// <summary>/// 提供获取统计图的相关方法/// 适合有极值和无极值,无极值时采用样本内的极值/// 除极小值包含在近右片外,其他临界值包含在近左片/// </summary>public class StatisticsGraph{/// <summary>/// 样本数据/// </summary>private List<float> Samples = null;private int NumberOfSegments = 10;//段数 即得到的图线有10个柱private double MaxSample = 0;//最大样本数据private double MinSample = 0;//最小样本数据private int MaxExtremum = 100;//样本极值 ,如统计学生成绩时 极值一般为100,即卷满分private float[] Demarcation = new float[] { 10, 20, 30, 40, 50, 60, 70, 80, 90 };//限有极值时设置/// <summary>/// 根据样本数据初始化/// </summary>/// <param name="samples"></param>public StatisticsGraph(List<float> samples){this.Init(samples);}/// <summary>/// 通过指定分片段数和样本数据进行初始化/// </summary>/// <param name="samples"></param>/// <param name="numberOfSegments"></param>public StatisticsGraph(List<float> samples, int numberOfSegments){this.HasSpecifiedExtremum = false;this.Init(samples);this.NumberOfSegments = numberOfSegments;this.Demarcation = GetDemarcation();}/// <summary>/// 通过指定分片段数、极大值和样本数据进行初始化/// </summary>/// <param name="samples"></param>/// <param name="numberOfSegments"></param>/// <param name="maxExtremum"></param>public StatisticsGraph(List<float> samples, int numberOfSegments, int maxExtremum){this.HasSpecifiedExtremum = true;this.MaxExtremum = maxExtremum;this.Init(samples);this.NumberOfSegments = numberOfSegments;this.Demarcation = GetDemarcation();}/// <summary>/// 通过指定极大值、样本数据和自定义分段临界值进行初始化/// </summary>/// <param name="samples"></param>/// <param name="demarcation"></param>/// <param name="maxExtremum"></param>public StatisticsGraph(List<float> samples, float[] demarcation, int maxExtremum){this.HasSpecifiedExtremum = true;this.Init(samples);this.MaxExtremum = maxExtremum;this.Demarcation = demarcation;this.NumberOfSegments = demarcation.Count();}public int MinExtremum = 0;//最小极值默认为0private void Init(List<float> samples){this.Samples = samples;this.MaxSample = Samples.Max();this.MinSample = Samples.Min();}/// <summary>/// 是否指定了极大值/// </summary>private bool _hasSpecifiedExtremum = true;/// <summary>/// 是否已经指定了极大值/// </summary>public bool HasSpecifiedExtremum { get { return _hasSpecifiedExtremum; } private set { _hasSpecifiedExtremum = value; } }/// <summary>/// 获取每个分片的临界点/// </summary>/// <returns></returns>private float[] GetDemarcation(){if (NumberOfSegments <= 1){return null;}float[] result = new float[NumberOfSegments - 1];if (HasSpecifiedExtremum == false)//未指定极大值时 样本中最大值为统计范围内极大值
            {MaxExtremum = Convert.ToInt32(Math.Floor(MaxSample)) + 1;MinExtremum = Convert.ToInt32(Math.Floor(MinSample)) - 1;}int span = MaxExtremum - MinExtremum;//极值跨度float segSpan = span * 1f / NumberOfSegments;//每个片段的跨度for (int i = 0; i < NumberOfSegments - 1; i++){result[i] = MinExtremum + segSpan * (i + 1);}return result;}/// <summary>/// 获取各个分片的样本数量/// 结果《分片的极右值,该片的样本数》/// 分片总数为临界点数+1个/// </summary>/// <returns></returns>private Dictionary<float, int> GetSampleNumbersOfPerSegment(){Dictionary<float, int> result = new Dictionary<float, int>();List<float> segRightValue = new List<float>();//分片极右值foreach (var item in Demarcation){segRightValue.Add(item);}segRightValue.Add(MaxExtremum);for (int i = 0; i < segRightValue.Count; i++){int value = 0;foreach (float m in Samples)//计算每个片段的样本数
                {if (i == 0){if (m <= segRightValue[i]){value += 1;}}else{if (m <= segRightValue[i] && m > segRightValue[i - 1]){value += 1;}}}result.Add(segRightValue[i], value);}return result;}/// <summary>/// 获取每个分片的左上顶点坐标/// </summary>/// <param name="UsableWidth">最大利用宽度</param>/// <param name="UsableHeight">最小利用宽度</param>/// <returns></returns>private List<PointF> GetTopLeftPointFOfSegment(PointF bottomLeft, float UsableWidth, float UsableHeight, out  float widthPerSeg, out  float unitHeight, out  Dictionary<float, int> SampleNumbersOfPerSegment){List<PointF> result = new List<PointF>();SampleNumbersOfPerSegment = GetSampleNumbersOfPerSegment();//获取每个片段占有的样本数int maxSampleNumbersOfSegment = SampleNumbersOfPerSegment.Max(x => x.Value);//所有分片中 最大分片样本数
widthPerSeg = UsableWidth * 1f / (SampleNumbersOfPerSegment.Count * 2 + 1);//每个分片的宽度  分片之间还有空白分片
unitHeight = UsableHeight * 1f / maxSampleNumbersOfSegment;//充分利用高度的情况下 单位样本数所占高度for (int i = 0; i < SampleNumbersOfPerSegment.Count; i++){PointF pf = new PointF();pf.X = bottomLeft.X + (i * 2 + 1) * widthPerSeg;//每个片段的左边X坐标
pf.Y = bottomLeft.Y - SampleNumbersOfPerSegment.ElementAt(i).Value * unitHeight;//每个片段上边Y坐标
result.Add(pf);}return result;}/// <summary>/// 获取每个分片的 条形数据(包括:左上角坐标,高度和宽度)/// </summary>/// <param name="UsableWidth"></param>/// <param name="UsableHeight"></param>/// <returns></returns>private RectangleF[] GetRectangleFs(PointF bottomLeft, float UsableWidth, float UsableHeight, out Dictionary<float, int> SampleNumbersOfPerSegment){float widthPerSeg = 0;//每个片段的宽度float unitHeight = 0;//单位样本数据在Y轴上表示需要的高度//每个片段的左上角坐标List<PointF> pfs = GetTopLeftPointFOfSegment(bottomLeft, UsableWidth, UsableHeight, out widthPerSeg, out unitHeight, out SampleNumbersOfPerSegment);RectangleF[] RFs = new RectangleF[pfs.Count];for (int i = 0; i < pfs.Count; i++){//通过计算宽度和高度 结合左上角坐标 以准确描述每个矩形的大小和位置RFs[i] = new RectangleF(pfs[i], new SizeF(widthPerSeg, SampleNumbersOfPerSegment.ElementAt(i).Value * unitHeight));}return RFs;}/// <summary>/// 获得10段柱状图/// 横轴 分数段;纵轴 该分数段的 人数/// </summary>/// <param name="width"></param>/// <param name="heigh"></param>/// <param name="unitName"></param>/// <param name="familyName"></param>/// <returns></returns>public Bitmap GetBargraph(int width, int heigh, string XunitName, string YunitName, string familyName = "宋体"){Font font = new Font(familyName, 10);Bitmap bitmap = new Bitmap(width, heigh);Graphics gdi = Graphics.FromImage(bitmap);//用白色填充整个图片,因为默认是黑色
            gdi.Clear(Color.White);//抗锯齿gdi.SmoothingMode = SmoothingMode.HighQuality;//高质量的文字gdi.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;//像素均偏移0.5个单位,以消除锯齿gdi.PixelOffsetMode = PixelOffsetMode.Half;int margin = 30;//坐标轴与边框的距离int padding = 20;//实际表示内容区域 与坐标轴右和上边的距离
PointF bottomLeft = new PointF(margin, heigh - margin);//坐标原点
PointF topLeft = new PointF(bottomLeft.X, margin);//Y轴最上顶端坐标
PointF topLeft_bl = new PointF(topLeft.X - 6, topLeft.Y + 10);//Y轴箭头左下端坐标
PointF topLeft_br = new PointF(topLeft.X + 6, topLeft_bl.Y);//Y轴箭头右下端坐标
gdi.DrawLines(Pens.Black, new PointF[] { topLeft_bl, topLeft, topLeft_br });//画坐标轴Y轴箭头
gdi.DrawString(string.Format("({0})", YunitName), font, Brushes.Black, topLeft_bl.X - 20, topLeft.Y - 14);//在Y轴箭头左下角写上 Y轴表示的单位
PointF bottomRight = new PointF(width - margin, bottomLeft.Y);//X轴最右端坐标
PointF bottomRight_lt = new PointF(bottomRight.X - 10, bottomRight.Y - 6);//X轴箭头左上端坐标
PointF bottomRight_lb = new PointF(bottomRight_lt.X, bottomRight.Y + 6);//X轴箭头右下端坐标
gdi.DrawLines(Pens.Black, new PointF[] { bottomRight_lt, bottomRight, bottomRight_lb });//画坐标轴X轴箭头
gdi.DrawString(string.Format("({0})", XunitName), font, Brushes.Black, bottomRight_lt.X - 3, bottomRight_lt.Y + 13);//在X轴箭头的下方 写上X轴表示的单位
gdi.DrawLines(Pens.Black, new PointF[] { topLeft, bottomLeft, bottomRight });//画坐标轴float usableHeight = bottomLeft.Y - margin - padding;//内容区高度float usableWidth = width - margin * 2 - padding;//内容区宽度
Dictionary<float, int> SampleNumbersOfPerSegment = null;//各个片段的描述数据
RectangleF[] RFs = GetRectangleFs(bottomLeft, usableWidth, usableHeight, out SampleNumbersOfPerSegment);//获取条形图位置数据
gdi.FillRectangles(new SolidBrush(Color.FromArgb(70, 161, 185)), RFs);//填充柱形//标上坐标轴上的数据//X轴上写的内容string Xcontent = string.Empty;//条形顶上方写的内容string Ycontent = string.Empty;for (int i = 0; i < SampleNumbersOfPerSegment.Count; i++){if (i == 0)Xcontent = "X<=" + SampleNumbersOfPerSegment.ElementAt(i).Key.ToString("F0");else{Xcontent = string.Format("{0}<X<={1}", SampleNumbersOfPerSegment.ElementAt(i - 1).Key.ToString("F0"), SampleNumbersOfPerSegment.ElementAt(i).Key.ToString("F0"));}gdi.DrawString(Xcontent, font, Brushes.Black, RFs[i].X - 8, bottomLeft.Y + 5); //写上X轴上的数据
Ycontent = SampleNumbersOfPerSegment.ElementAt(i).Value.ToString();gdi.DrawString(Ycontent, font, Brushes.Black, RFs[i].X + 3, RFs[i].Y - 13); //写上Y轴上的数据
}return bitmap;}}

调用:

 StatisticsGraph sg = new StatisticsGraph(scores.ConvertAll(x => (float)x),10,100);System.Diagnostics.Stopwatch w = new System.Diagnostics.Stopwatch();w.Start();Bitmap bitmap = sg.GetBargraph(800, 480,"分","人数");bitmap.Save("tt.jpg", System.Drawing.Imaging.ImageFormat.Jpeg);Debug.WriteLine(w.Elapsed);

一张图片大约耗时20毫秒。

测试数据得到的柱形图:

转载于:https://www.cnblogs.com/langu/archive/2013/05/13/3075658.html

使用c#类库绘制柱状图相关推荐

  1. Python使用matplotlib绘制柱状图(bar plot)实战:水平条形图、垂直条形图、分组条形图、堆叠条形图

    Python使用matplotlib绘制柱状图(bar plot)实战:水平条形图.垂直条形图.分组条形图.堆叠条形图 目录

  2. plotly基于dataframe数据绘制柱状图(bar plot)

    plotly基于dataframe数据绘制柱状图(bar plot) # 构建仿真pandas数据: # 绘制条形图: import plotly as py # 导入plotly库并命名为py im ...

  3. cufflinks基于dataframe数据绘制柱状图(bar plot)、堆叠柱状图(stacked bar plot)

    cufflinks基于dataframe数据绘制柱状图(bar plot).堆叠柱状图(stacked bar plot) # bar plot # from chart_studio import ...

  4. 超详细的Python matplotlib 绘制柱状图

    复习回顾 Python 为数据展示提供了大量优秀的功能包,其中 matplotlib 模块可以方便绘制制作折线图.柱状图.散点图等高质量的数据包. 关于 matplotlib 模块,我们前期已经对ma ...

  5. 用python绘制柱状图标题-Python数据可视化:5种绘制柱状图表的方法(附源码)...

    本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理 以下文章来源于数据Magic,作者我不是小样 前言 python里面有很多优秀的可 ...

  6. python 画柱状图-python使用Plotly绘图工具绘制柱状图

    本文实例为大家分享了python使用Plotly绘图工具绘制柱状图的具体代码,供大家参考,具体内容如下 使用Plotly绘制基本的柱状图,需要用到的函数是graph_objs 中 Bar函数 通过参数 ...

  7. python画柱形图-Python绘制柱状图

    import os #输入想要存储图像的路径 os.chdir('路径') import matplotlib.pyplot as plt import numpy as np #改变绘图风格 imp ...

  8. 2021-04-29 Python绘制柱状图之可视化神器Pyecharts

    Python绘制柱状图之可视化神器Pyecharts 昨晚写了关于Matplotlib的可视化,今天推荐一个可视化的利器-pyecharts. 前文链接:Python可视化图表生成-Matplotli ...

  9. 成功解决采用ax.bar进行三维绘图绘制柱状图的时候,横坐标只显示三列而不是数据中的四列

    成功解决采用ax.bar进行三维绘图绘制柱状图的时候,横坐标只显示三列而不是数据中的四列 目录 解决问题 解决思路 解决方法 解决问题 输入数据为四列五行,如下所示: labelX_lists02= ...

最新文章

  1. 【网页前端设计Front end】HTML语言基础.下(看不懂你来打我)
  2. 用java实现八皇后问题_使用java语言实现八皇后问题
  3. 【Python】字符串类型及操作求三位水仙花数
  4. 因触屏故障 美国监管部门对15.9万辆特斯拉进行调查
  5. 教育学考研跨考计算机,某985计算机专业,想要三跨北师大教育学,会不会很难?...
  6. [工具] Mac下一键APK逆向环境
  7. 当网页无法正常显示时更换浏览器
  8. ca42a_demo_c++_new_delete表达式
  9. 上传大文件超时upstream timed out ,nginx配置修改
  10. 【Java Set接口】
  11. 活动 支付、退款相关的订单测试
  12. linux新建分区步骤
  13. 游戏全区全服和分区分服 QQ斗地主的设计
  14. iOS开发系列--通讯录、蓝牙、内购、GameCenter、iCloud、Passbook详解
  15. Android 获取手机IP
  16. Windows XP自动登录 auto login
  17. OpenCV-Python图像叠加
  18. 锦州市2021年高考成绩查询时间,2021年辽宁锦州中考考试时间及科目安排(已公布)...
  19. 120.(leaflet篇)区域下钻,区域钻取
  20. 上饶“智慧城市”生活:家居出行购物医疗全覆盖

热门文章

  1. JZOJ 5677. 【GDOI2018Day2模拟4.21】纽约
  2. linux mysql软件_「Linux」 - 常用软件安装-MySql
  3. vue 页面闪烁的问题_vue页面加载闪烁问题的解决方法
  4. python scatter参数详解_matplotlib.pyplot.scatter散点图结构及用法||参数详解
  5. 模型学习 - HNN、RBM、DBN
  6. ECCV 2016《SSD: Single Shot MultiBox Detector》论文笔记
  7. uvalive4838(凸包+重心)
  8. 2017年10月05日普及组 负进制
  9. oracle动态 returning,oracle returning
  10. mysql不支持python3吗_MySQL的4种事务隔离级别你还不清楚吗?