C# 画直方图

  1直方图分为坐标系和竖条组成  
  2      
  3    首先画坐标系  
  4      
  5    using System;  
  6    using System.Collections.Generic;  
  7    using System.Text;  
  8    using System.Drawing;  
  9    using System.Collections;  
 10      
 11    namespace Sirc.cem.ZFT  
 12    {  
 13        /// <summary>  
 14        /// 直角坐标系类  
 15        /// 用于表示气象自动站时段内降雨量在各个时间的分布  
 16        /// </summary>  
 17        public class ZFTCoordinate  
 18        {  
 19            private int jtLength = 20; //箭头的长度  
 20            private int valueLent = 4; //刻度线的长度  
 21            private Hashtable table = new Hashtable(); //记录直方图X轴各个刻度的坐标,用键值对的形式保存在table中  
 22      
 23            List<ZFTCell> cellList = null;  
 24            /// <summary>  
 25            /// 各个小直方图单元集合  
 26            /// </summary>  
 27            public List<ZFTCell> CellList  
 28            {  
 29                get  
 30                {  
 31                    return cellList;  
 32                }  
 33                set { cellList = value; }  
 34            }  
 35      
 36            private double xCellValue = 0; //X轴一个单元格表示的值  
 37            /// <summary>  
 38            /// X轴一个单元格表示的值  
 39            /// </summary>  
 40            public double XCellValue  
 41            {  
 42                get { return xCellValue; }  
 43                set { xCellValue = value; }  
 44            }  
 45      
 46            private int xCellCount = 0;     //X轴单元格的数目  
 47            /// <summary>  
 48            /// X轴单元格的数目  
 49            /// </summary>  
 50            public int XCellCount  
 51            {  
 52                get { return xCellCount; }  
 53                set { xCellCount = value; }  
 54            }  
 55      
 56            private int xCellLength = 0;    //X轴单元格长度  
 57            /// <summary>  
 58            /// X轴单元格长度  
 59            /// </summary>  
 60            public int XCellLength  
 61            {  
 62                get { return xCellLength; }  
 63                set { xCellLength = value; }  
 64            }  
 65      
 66      
 67            private double yCellValue = 0; //Y轴一个单元格表示的值  
 68            /// <summary>  
 69            /// Y轴一个单元格表示的值  
 70            /// </summary>  
 71            public double YCellValue  
 72            {  
 73                get { return yCellValue; }  
 74                set { yCellValue = value; }  
 75            }  
 76      
 77            private int yCellCount = 0;     //Y轴单元格的数目  
 78            /// <summary>  
 79            /// Y轴单元格的数目  
 80            /// </summary>  
 81            public int YCellCount  
 82            {  
 83                get { return yCellCount; }  
 84                set { yCellCount = value; }  
 85            }  
 86      
 87            private int yCellLength = 0;    //Y轴单元格长度  
 88            /// <summary>  
 89            /// Y轴单元格长度  
 90            /// </summary>  
 91            public int YCellLength  
 92            {  
 93                get { return yCellLength; }  
 94                set { yCellLength = value; }  
 95            }  
 96      
 97            private int xStyle = 0;        //X轴的样式,0表示从08点-08点 1表示20点-20点 2表示近多少小时  
 98            /// <summary>  
 99            /// X轴的样式,  
100            /// 0表示从08点-08点 也就是fromHour需要加上8   
101            /// 1表示20点-20点 也就是fromHour需要加上20  
102            /// 2表示近多少小时 fromHour不需要加任何数值  
103            /// 默认是0  
104            /// </summary>  
105            public int XStyle  
106            {  
107                get { return xStyle; }  
108                set { xStyle = value; }  
109            }  
110      
111            private Point coordinatesOrigin;    //坐标原点origin of coordinates  
112            /// <summary>  
113            /// 坐标原点  
114            /// </summary>  
115            public Point CoordinatesOrigin  
116            {  
117                get { return coordinatesOrigin; }  
118                set { coordinatesOrigin = value; }  
119            }  
120      
121            private int fromHour = 0;   //起点时间  
122            /// <summary>  
123            /// 起点时间  
124            /// X轴的起点时间  
125            /// </summary>  
126            public int FromHour  
127            {  
128                get { return fromHour; }  
129                set  
130                {  
131                    fromHour = value;  
132                    if (fromHour == 8)  
133                        xStyle = 0;  
134                    else if (fromHour == 20)  
135                        xStyle = 1;  
136                    else  
137                        xStyle = 2;  
138      
139                }  
140            }  
141      
142            public ZFTCoordinate()  
143            {  
144            }  
145      
146            public ZFTCoordinate(double xCellValue, int xCellCount, double yCellValue, int yCellCount)  
147            {  
148                this.xCellCount = xCellCount;  
149                this.xCellValue = xCellValue;  
150                this.yCellCount = yCellCount;  
151                this.yCellValue = yCellValue;  
152            }  
153      
154            /// <summary>  
155            /// 依据雨量的最大值  
156            /// 计算Y轴刻度值的分布  
157            /// 保证直方图尽量的大  
158            /// </summary>  
159            /// <param name="maxRainfall"></param>  
160            public void SetYValue(double maxRainfall)  
161            {  
162                if (maxRainfall > 5)  
163                {  
164                    //计算Y轴刻度最大值   
165                    //计算方法:用最大雨量除以5,取整数加上1,再乘以5  
166                    int count1 = Convert.ToInt32(maxRainfall / 5);  
167                    int count2 = count1 + 1;  
168                    double maxCellValue = count2 * 5;  
169                    yCellValue = maxCellValue / 5;  
170                }  
171                else  
172                {  
173                    yCellValue = 1;  
174                }  
175            }  
176              
177            /// <summary>  
178            /// 画直方图  
179            /// 包括坐标系 雨量等  
180            /// </summary>  
181            /// <param name="width"></param>  
182            /// <param name="height"></param>  
183            /// <returns></returns>  
184            public Image Draw(int width,int height)  
185            {  
186                Image img = new Bitmap(width, height);  
187                Graphics g = Graphics.FromImage(img);  
188                  
189                //画坐标系  
190                DrawXLine(g);  
191                DrawYLine(g);  
192                DrawCell(g, cellList);  
193      
194                g.Dispose();  
195      
196                return img;  
197            }  
198      
199            /// <summary>  
200            /// 利用坐标系参数 画坐标系  
201            /// </summary>  
202            /// <param name="g"></param>  
203            private void DrawXLine(Graphics g)  
204            {  
205                //坐标原点CoordinatesOrigin  
206                //画X轴  
207                //一个单元格一个单元格的画  
208                Point fromPt = coordinatesOrigin;  
209                Point toPt = new Point();  
210                Pen pen = new Pen(Color.Black);  
211                Font font = new Font("宋体", 9);  
212      
213                for (int i = 0; i < xCellCount; i++)  
214                {  
215                    //画单元格  
216                    toPt = new Point(fromPt.X + xCellLength, fromPt.Y);  
217                    g.DrawLine(pen, fromPt, toPt);  
218                    //画刻度线  
219                    Point xCellValuePoint = new Point(toPt.X, toPt.Y + valueLent);  
220                    g.DrawLine(pen, toPt, xCellValuePoint);  
221                                     
222      
223                    //画数值 只画偶数  
224                    int hour = i;  
225                    if (i % 2 == 0)  
226                    {  
227                        string s = "";  
228                        if (xStyle == 0)  
229                        {  
230                            hour = hour + 8;  
231                        }  
232                        else if (xStyle == 1)  
233                        {  
234                            hour = hour + 20;  
235                        }  
236                        else  
237                        {  
238                            if (fromHour % 2 != 0)  
239                                hour = hour + fromHour - 1;  
240                            else  
241                                hour = hour + fromHour;  
242                        }  
243      
244                        if (hour == 24)  
245                        {  
246                            hour = 0;  
247                        }  
248                        else if (hour > 24)  
249                        {  
250                            hour = hour - 24;  
251                        }  
252      
253                        s = (hour < 10) ? ("0" + hour) : hour + "";  
254      
255                        //保存刻度点 用来画直方图时使用  
256                        if (i > 0)  
257                        {  
258                            table.Add(hour, toPt);  
259                        }  
260                        else  
261                            table.Add(-1, toPt);//X轴第一个点  
262      
263                        Point sPoint = new Point(xCellValuePoint.X - 7, xCellValuePoint.Y + 5);  
264                        g.DrawString(s, font, Brushes.Black, sPoint);  
265                    }  
266                    fromPt = toPt;  
267                }  
268                //画箭头  
269                Point jtPoint = new Point(toPt.X + jtLength, toPt.Y);  
270                g.DrawLine(pen, toPt, jtPoint);  
271      
272                g.DrawLine(pen, jtPoint.X, jtPoint.Y, jtPoint.X - jtLength / 4, jtPoint.Y + jtLength / 4);  
273                g.DrawLine(pen, jtPoint.X, jtPoint.Y, jtPoint.X - jtLength / 4, jtPoint.Y - jtLength / 4);  
274      
275                //画单位  
276                Point sjtPoint = new Point(jtPoint.X + 5, jtPoint.Y+5);  
277                string jts = "时";  
278      
279                g.DrawString(jts, font, Brushes.Black, sjtPoint);  
280      
281                pen.Dispose();  
282                font.Dispose();  
283            }  
284            /// <summary>  
285            /// 利用坐标系参数 画坐标系  
286            /// </summary>  
287            /// <param name="g"></param>  
288            private void DrawYLine(Graphics g)  
289            {  
290                //坐标原点CoordinatesOrigin  
291                //画X轴  
292                //一个单元格一个单元格的画  
293                Point fromPt = coordinatesOrigin;  
294                Point toPt = new Point();  
295                Pen pen = new Pen(Color.Black);  
296                Font font = new Font("宋体", 9);  
297      
298                for (int i = 0; i < yCellCount; i++)  
299                {  
300                    //画单元格  
301                    toPt = new Point(fromPt.X, fromPt.Y - yCellLength);  
302                    g.DrawLine(pen, fromPt, toPt);  
303      
304                    //画刻度线  
305                    Point yCellValuePoint = new Point(toPt.X - valueLent, toPt.Y);  
306                    g.DrawLine(pen, toPt, yCellValuePoint);  
307      
308      
309                    //画数值  
310                    Point sPoint = new Point(yCellValuePoint.X - 20, yCellValuePoint.Y - 5);  
311                    string s = (i + 1) * yCellValue + "";  
312      
313                    g.DrawString(s, font, Brushes.Black, sPoint);  
314      
315      
316                    fromPt = toPt;  
317                }  
318                //画箭头  
319                  
320                Point jtPoint = new Point(toPt.X, toPt.Y - jtLength);  
321                g.DrawLine(pen, toPt, jtPoint);  
322      
323                g.DrawLine(pen, jtPoint.X, jtPoint.Y, jtPoint.X + jtLength / 4, jtPoint.Y + jtLength / 4);  
324                g.DrawLine(pen, jtPoint.X, jtPoint.Y, jtPoint.X - jtLength / 4, jtPoint.Y + jtLength / 4);  
325      
326                //画单位  
327                Point sjtPoint = new Point(jtPoint.X + 10, jtPoint.Y);  
328                string jts = "毫米";  
329                g.DrawString(jts, font, Brushes.Black, sjtPoint);  
330      
331                pen.Dispose();  
332                font.Dispose();  
333            }  
334      
335            /// <summary>  
336            /// 画直方图  
337            /// </summary>  
338            /// <param name="g"></param>  
339            private void DrawCell(Graphics g,List<ZFTCell> cellList)  
340            {  
341                if (cellList == null)  
342                    return;  
343      
344                Pen pen = new Pen(Color.Black);  
345                 
346      
347                foreach (ZFTCell cell in cellList)  
348                {  
349                    System.Drawing.Point fromPt = new Point();  
350      
351                    int hours = cell.Hour;  
352                    if (hours % 2 != 0)  
353                    {  
354                        hours = hours - 1;  
355      
356                        if(hours == fromHour)  
357                            fromPt = (Point)table[-1];  
358                        else  
359                            fromPt = (Point)table[hours];  
360      
361                        fromPt.X += xCellLength;  
362                    }  
363                    else  
364                    {  
365                        fromPt = (Point)table[hours];  
366                    }  
367      
368      
369                    int lenth = Convert.ToInt32((cell.Rainfall / yCellValue) * yCellLength);  
370                    Point leftUp = new Point(fromPt.X - xCellLength / 2, fromPt.Y - lenth);  
371                    Point rightLow = new Point(fromPt.X + xCellLength / 2, fromPt.Y);  
372                    Rectangle rect = new Rectangle(leftUp.X, leftUp.Y, rightLow.X - leftUp.X, rightLow.Y - leftUp.Y);  
373                    g.FillRectangle(Brushes.LightBlue, rect);  
374      
375                    g.DrawRectangle(pen, rect);  
376                      
377                }  
378            }  
379      
380        }  
381    }  
382      
383      
384      
385    接下来是构造各个直方图单元格  
386      
387    using System;  
388    using System.Collections.Generic;  
389    using System.Text;  
390      
391    namespace Sirc.cem.ZFT  
392    {  
393        /// <summary>  
394        /// 直方图类  
395        /// 存有雨量值和对应的时间  
396        /// </summary>  
397        public class ZFTCell  
398        {  
399            private int hour = 0;   //几点  
400            /// <summary>  
401            /// 标志该单元格表示的是几点的雨量  
402            /// </summary>  
403            public int Hour  
404            {  
405                get { return hour; }  
406                set { hour = value; }  
407            }  
408            private double rainfall = 0;    //雨量  
409            /// <summary>  
410            /// 雨量值  
411            /// </summary>  
412            public double Rainfall  
413            {  
414                get { return rainfall; }  
415                set { rainfall = value; }  
416            }  
417      
418            public ZFTCell(int hour, double rainfall)  
419            {  
420                this.hour = hour;  
421                this.rainfall = rainfall;  
422            }  
423        }  
424    }  
425      
426      
427    最后是使用方法  
428      
429    //分析直方图的值  
430                double maxRainfall = 0;//表示雨量的最大值,用来计算Y轴刻度值的分布  
431                List<ZFTCell> cellList = new List<ZFTCell>();  
432                string[] splitDoller = { "$" };  
433                string[] cellStrArr = s.Split(splitDoller, StringSplitOptions.RemoveEmptyEntries);  
434                foreach (string cellStr in cellStrArr)  
435                {  
436                    if (cellStr.IndexOf("-") == -1)  
437                        continue;  
438      
439                    string[] splitCellStr = { "-" };  
440                    string[] cellInfoArr = cellStr.Split(splitCellStr, StringSplitOptions.RemoveEmptyEntries);  
441                    int hour = Convert.ToInt32(cellInfoArr[0]);  
442                    double rainfall = Convert.ToDouble(cellInfoArr[1]);  
443      
444                    ZFTCell cell = new ZFTCell(hour, rainfall);  
445                    maxRainfall = Math.Max(maxRainfall, rainfall);  
446                    cellList.Add(cell);  
447                }  
448      
449                //画直方图  
450                ZFTCoordinate c = new ZFTCoordinate(1, 25, 0, 5);  
451      
452                //fromTime是世界时,而直方图上显示的为北京时,所以要进行一个转换  
453                c.FromHour = fromTime.Hour + 8;  
454      
455                c.SetYValue(maxRainfall);  
456                c.CoordinatesOrigin = new System.Drawing.Point(30, 120);  
457                c.XCellLength = 10;  
458                c.YCellLength = 20;  
459                c.CellList = cellList;  
460                Image img = c.Draw(this.pictureBoxZFT.Width, this.pictureBoxZFT.Height);  
461      
462    this.pictureBoxZFT.Image = img;