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;