Java绘制正态分布统计图
Java绘制正态分布统计图
1.正态分布
正态分布(Normal distribution),又名高斯分布(Gaussian distribution),它在数学等工程领域中使用较为频繁的一种概率分布,尤其在统计学上有着重大的影响力。统计后的正态曲线呈钟型(两边低,中间高),如下图所示(图片来源百度百家号http://baijiahao.baidu.com/):
2.生成正态分布数据并统计
在做开发的过程中,我们往往要模拟出一些正态分布的数据,统计后进行图表绘制。使用Java模拟正态分布是一件非常容易的事情,随机数类Random的nextGaussian方法提供。
nextGaussian方法返回一个随机double类型数据,我们可以用一个数据容器存储该方法生成的若干个随机数。这些随机数会以0为基准随机生成正态分布的double数值,这些数值的均值接近0。在下面的程序示例中,我们利用nextGaussian生成若干个随机数,然后进行分组统计,最后在控制台上输出统计图表。
控制台输出正态分布统计图
01. import java.util.ArrayList;
02. import java.util.Comparator;
03. import java.util.HashMap;
04. import java.util.Map;
05. import java.util.Random;
06. import java.util.function.Supplier;
07. import java.util.stream.Stream;
08.
09. public class Gauss {10.
11.
12. private int ySize;//统计的标记数目y轴(分组数)
13. private int dataNumber;//生成的虚拟数据的个数
14. private int xSize;//刻度数目x轴
15.
16. //保存生成的高斯数据
17. private ArrayList<Double> list=new ArrayList<>();
18. //根据分组统计数据个数
19. private Map<Integer,Integer> map=new HashMap<>();
20.
21. public Gauss(int xSize,int ySize,int dataNumber) {22. this.ySize=ySize>3?ySize:3;
23. this.xSize=xSize>3?xSize:3;
24. this.dataNumber=dataNumber>1000?dataNumber:1000;
25. init();
26. }
27.
28. private void init() {29. //初始化高斯随机数
30. Random ran=new Random();
31. for(int i=0;i<dataNumber;i++) {32. list.add(ran.nextGaussian());
33. }
34. //初始化统计容器
35. for(int i=1;i<=this.ySize;i++) {36. map.put(i, 0);
37. }
38. }
39. //分析并统计高斯随机数
40. public void analysis() {41. /*
42. * 利用Stream进行统计,由于Stream终极方法会关闭,当重复使用Stream时
43. * 我们需要用供应商不断的提供相同的stream。
44. */
45. Supplier<Stream<Double>> supp=()->list.stream();//Lambda表达式给供应商
46. //为Stream提供一个比较器
47. Comparator<Double> comp=(e1,e2)->e1>e2?1:-1;
48. //获取最大最小值
49. double max=supp.get().max(comp).get();
50. double min=supp.get().min(comp).get();
51. double range=(max-min)/this.ySize;//计算统计区间的单位范围
52. //将每一个标记区的数据统计后放入map中。
53. for(int i=1;i<=this.ySize;i++) {54. double start=min+(i-1)*range;
55. double end=min+i*range;
56. Stream<Double> stream=supp.get()
57. .filter((e)->e>=start).filter((e)->e<end);
58. map.put(i,(int)stream.count());
59. }
60. }
61. //绘制统计图
62. public void grawValue() {63. int ScaleSize=14;//x轴刻度长度
64. int avgScale=this.dataNumber/xSize;
65. int printSize=ScaleSize-String.valueOf(avgScale).length();
66. //打印X轴、刻度以及刻度值
67. for(int i=0;i<=xSize;i++) {68. printChar(' ',printSize);
69. System.out.print(i*avgScale);
70. }
71. System.out.println("");
72. for(int i=0;i<=xSize;i++) {73. if(i==0) {74. printChar(' ',printSize);
75. }else {76. printChar('-',ScaleSize);
77. }
78. }
79. System.out.println();
80. //绘制统计内容
81. for(int i=1;i<=ySize;i++) {82. printChar(' ', printSize-1-String.valueOf(i).length());
83. System.out.print(i+":");
84. int scaleValue=map.get(i);
85. double grawSize=scaleValue/(avgScale*1.0/ScaleSize);
86. grawSize=(grawSize>0 && grawSize<1)?1:grawSize;
87. printChar('█', (int)grawSize);
88. System.out.println(" "+scaleValue+"\n");
89. }
90. }
91.
92. public Map<Integer,Integer> getAnalysisMap(){93. return this.map;
94. }
95.
96. private void printChar(char c,int number) {97. for(int i=0;i<number;i++) {98. System.out.print(c);
99. }
100. }
101.
102. public static void main(String[] args) {103. Gauss g=new Gauss(8,12,10000);
104. g.analysis();
105. g.grawValue();
106. }
107. }
运行结果如下图:
从运行的结果上来看,它形成的分布是符合正态分布的。如果熟悉Swing组件的话,我们也可以在Swing组件中进行动态的绘制。如下面示例所示:
SwingGUI模拟正态分布数据
01. import java.awt.BorderLayout;
02. import java.awt.Color;
03. import java.awt.Dimension;
04. import java.awt.Font;
05. import java.awt.Graphics;
06. import java.awt.Rectangle;
07. import java.awt.font.FontRenderContext;
08. import java.awt.geom.AffineTransform;
09. import java.util.Map;
10.
11. import javax.swing.JButton;
12. import javax.swing.JFrame;
13. import javax.swing.JLabel;
14. import javax.swing.JPanel;
15. import javax.swing.JScrollPane;
16. import javax.swing.JSlider;
17. import javax.swing.SwingUtilities;
18. import javax.swing.SwingWorker;
19. import javax.swing.event.ChangeListener;
20.
21. public class GaussGUI extends JFrame{22.
23. private static final long serialVersionUID = 1L;
24. //绘图面板
25. private JPanel grawPanel=new JPanel();
26. //滑杆x-刻度个数,y-分组个数,dataNum-随机数个数
27. private JSlider x,y,dataNum;
28. //各组件说明标签
29. private JLabel xlab,ylab,datalab;
30. private JLabel grawLab;
31. private JButton bt=new JButton("绘图");
32. //绘制图像的基础宽度,高度
33. private final int X_WIDTH=600;
34. private final int Y_HEIGHT=350;
35. //绘制图像的起始x,y坐标位置
36. private final int X_START=50;
37. private final int Y_START=50;
38.
39. public GaussGUI() {40. super("正态分布数据模拟");
41. this.setBounds(300,300,800,600);
42. this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
43. this.setVisible(true);
44. }
45. //加载界面内容和事件
46. public void load() {47. init();
48. eventInit();
49. }
50.
51. //初始化界面
52. public void init() {53. JScrollPane scrPan=new JScrollPane(grawPanel);
54. grawLab=new JLabel("统计图");
55. grawPanel.add(grawLab);
56. JPanel topPanel=new JPanel(null);
57. xlab=new JLabel("x轴刻度个数:5");
58. ylab=new JLabel("y轴刻度个数:5");
59. datalab=new JLabel("随机数个数:10000");
60. //数轴最小3,最大20,默认为5,刻度单位为3
61. x=new JSlider(3,15,5);
62. y=new JSlider(3,15,5);
63. //设置随机数数量
64. dataNum=new JSlider(1000,100000,10000);
65. x.setMinorTickSpacing(3);
66. y.setMinorTickSpacing(3);
67. dataNum.setMinorTickSpacing(1000);
68.
69. xlab.setBounds(10, 10, 100, 30);
70. x.setBounds(120, 10, 150, 30);
71. ylab.setBounds(300, 10, 100, 30);
72. y.setBounds(420, 10, 150, 30);
73. bt.setBounds(600, 10, 100, 30);
74. datalab.setBounds(10,50,130,30);
75. dataNum.setBounds(150,50,600,30);
76. topPanel.add(xlab);
77. topPanel.add(x);
78. topPanel.add(ylab);
79. topPanel.add(y);
80. topPanel.add(bt);
81. topPanel.add(datalab);
82. topPanel.add(dataNum);
83. //显示刻度
84. x.setPaintTicks(true);
85. y.setPaintTicks(true);
86. dataNum.setPaintTicks(true);
87. dataNum.setSnapToTicks(true);//移动一个刻度
88. topPanel.setPreferredSize(new Dimension(0,80));
89. this.add(topPanel,BorderLayout.NORTH);
90. this.add(scrPan,BorderLayout.CENTER);
91. }
92. //事件处理
93. public void eventInit() {94. //处理滑杆
95. ChangeListener listener=(e)->{96. if(e.getSource() instanceof JSlider){97. JSlider o=(JSlider)e.getSource();
98. JLabel lab=null;
99. if(o==x) lab=xlab;
100. if(o==y) lab=ylab;
101. if(o==dataNum) lab=datalab;
102.
103. if(lab!=null) {104. String newTxt=lab.getText()
105. .replaceAll("\\d+",o.getValue()+"");
106. lab.setText(newTxt);
107. }
108. }
109. };
110. x.addChangeListener(listener);
111. y.addChangeListener(listener);
112. dataNum.addChangeListener(listener);
113. //处理按钮,关键绘图
114. bt.addActionListener((e)->{115. //注意生成大量数据可能会造成阻塞,使用swing工作线程进行生成。
116. getTask().execute();
117. });
118. }
119. //工作线程实现
120. private SwingWorker<String, Integer> getTask(){121. SwingWorker<String, Integer> task=new SwingWorker<String, Integer>(){122.
123. @Override
124. protected String doInBackground() throws Exception {125. //利用Console版的Gauss生成数据,并获取统计集合
126. Gauss gus=new Gauss(x.getValue(),
127. y.getValue(),dataNum.getValue());
128. gus.analysis();
129. Graphics g=grawPanel.getGraphics();
130. //图形绘制需要使用EDT线程完成,否则容易出现部分图形无法绘制的情况
131. SwingUtilities.invokeLater(()->{132. g.clearRect(0, 0, grawPanel.getWidth(),
133. grawPanel.getHeight());
134. drawX(g);
135. drawY(g,gus.getAnalysisMap());
136. });
137. return null;
138. }
139. };
140.
141. return task;
142. }
143. //绘制X坐标轴
144. private void drawX(Graphics g) {145. //刻度值
146. int avgScaleValue=dataNum.getValue()/x.getValue();
147. g.setColor(Color.RED);
148. //刻度间距
149. int avgScale=X_WIDTH/x.getValue();
150. //绘制坐标X横轴
151. g.drawLine(X_START,Y_START,X_START+X_WIDTH+20,Y_START);
152. g.drawLine(X_START+X_WIDTH+16,Y_START-3,X_START+X_WIDTH+20,Y_START);
153. g.drawLine(X_START+X_WIDTH+16,Y_START+3,X_START+X_WIDTH+20,Y_START);
154. Font font=this.getFont();
155. //测量文本大小所需的信息容器
156. FontRenderContext frc = new FontRenderContext(new AffineTransform(),
157. true,true);
158. //绘制坐标轴上的刻度标题
159. for(int i=0;i<=x.getValue();i++) {160. String xTitle=String.valueOf(avgScaleValue*i);
161. //获取标题文本像素宽度
162. int titleWidthPix=font.getStringBounds(xTitle, frc)
163. .getBounds().width;
164. //基础x加i倍刻度减一半文本宽度
165. int titleX=X_START+avgScale*i-titleWidthPix/2;
166. g.drawString(xTitle,titleX,Y_START-10);
167. g.drawLine(X_START+avgScale*i, Y_START,
168. X_START+avgScale*i, Y_START-2);
169. }
170. }
171.
172. //绘制Y坐标轴
173. private void drawY(Graphics g,Map<Integer,Integer> map) {174. g.setColor(Color.RED);
175. //刻度间距
176. int avgScale=Y_HEIGHT/y.getValue();
177.
178. g.drawLine(X_START,Y_START, X_START, Y_START+Y_HEIGHT+50);
179. Font font=this.getFont();
180. //测量文本大小所需的信息容器
181. FontRenderContext frc = new FontRenderContext(new AffineTransform(),
182. true,true);
183. //绘制Y坐标轴上的刻度标题
184. for(int i=1;i<=y.getValue();i++) {185. String xTitle=String.valueOf(i)+"Gr";
186. //获取文本像素宽度
187. Rectangle titleRec =font.getStringBounds(xTitle, frc).getBounds();
188. //绘制标题
189. //titleHeigth标题高度=基础距离+i倍的刻度间距+文本高度的一半再减5个像素
190. int titleHeigth=Y_START+(avgScale*i)+titleRec.height/2-5;
191. g.setColor(Color.RED);
192. g.drawString(xTitle,X_START-(titleRec.width+5),titleHeigth);
193. g.drawLine(X_START, Y_START+(avgScale*i),
194. X_START-2, Y_START+(avgScale*i));
195. //绘制统计图
196. g.setColor(Color.blue);
197. //计算柱图的宽度
198. double gwidth=map.get(i)/(dataNum.getValue()*1.0/X_WIDTH);
199. gwidth=gwidth>0 && gwidth<1?1:gwidth;
200.
201. g.fillRect(X_START+3, Y_START+avgScale*i-avgScale/4,
202. (int)gwidth,avgScale/2);
203. g.drawString(map.get(i)+"", X_START+13+(int)gwidth,titleHeigth);
204. }
205. }
206.
207. public static void main(String[] args) {208. SwingUtilities.invokeLater(()->new GaussGUI().load());
209. }
210.
211. }
程序运行后,我们可以通过GUI界面上的组件动态的生成正态分布图,需要注意的是,两个小程序中都是用了Lambda表达式和Stream,我们必须在Java8以上的版本中才能运行。上述基于Swing的GUI程序几个运行效果图如下:
Java绘制正态分布统计图相关推荐
- java k线绘制,用Java绘制K线图[Java编程]
赞助商链接 本文"用Java绘制K线图[Java编程]"是由七道奇为您精心收集,来源于网络转载,文章版权归文章作者所有,本站不对其观点以及内容做任何评价,请读者自行判断,以下是其具 ...
- python绘制正态分布曲线
场景:已知mean和variance,绘制正态分布曲线. import numpy as np import matplotlib.pyplot as plt import pandas as pd ...
- python绘制正态分布函数_学好正态分布有多重要?
作者 | Farhad Malik 译者 | Monanfei 责编 | 夕颜 出品 | AI科技大本营(ID: rgznai100) 为什么正态分布如此特殊?为什么大量数据科学和机器学习的文章都围绕 ...
- html一个页面同时加载多个饼图,Html5饼图绘制实现统计图的方法
Html5提供了强大的绘图API,让我们能够使用javascript轻松绘制各种图形.本文将主要讲解使用HTML5绘制饼图(统计图)的方法.先看一下饼图效果: 这个图是动态生成的,根据传入的比例参数( ...
- java绘制图形_java绘制基本图形.doc
java绘制基本图形 java绘制基本图形 1. * *** ***** 2. * * * ***** 3. ************* * * * * ************* 4. ****** ...
- JAVA几何图注水,如何使用java绘制几何形状到图片?
在Java语言编程中,如何使用Java绘制几何形状到图片? 注意:需要访问网址: , 下载一个OpenCV软件包.这里下载最新版本:opencv-3.2.0-vc14.exe并解压此文件到D:soft ...
- Python-Matplotlib可视化(3)——自定义样式绘制精美统计图
Python-Matplotlib可视化(3)--自定义样式绘制精美统计图 前言 控制线条样式和线宽 线条样式 线宽 控制填充样式 控制标记样式 控制标记大小 创建自定义标记 总结--对标记进行更精细 ...
- 正态分布的概率密度函数python_python绘制正态分布及三大抽样分布的概率密度图像...
目录 1.scipy库中各分布对应的方法 2.stats中各分布的常用方法及其功能 3.正态分布的概率密度函数及其图象 1)正态分布的概率密度函数及其图象 2)python绘制正态分布的概率密度函数图 ...
- 京东百万年薪大佬用JAVA绘制“五子棋棋盘”(附代码)
这篇文章主要为大家详细介绍了java绘制五子棋棋盘,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 具体内容如下 源码: import javax.imageio.Ima ...
最新文章
- java排序算法(冒泡,插入,选择,快速,堆,归并,希尔,基数)
- 服务器中加速BIOS启动的方法
- java web开发技巧_java web开发技巧
- shell 中scp 和 ssh密码输入 --expect (转:http://blog.sina.com.cn/s/blog_8ad7d4ca01014lft.html)
- android单独刷入镜像
- python QTreeWidgetItem下面有几个子tree_python-nlp ch1笔记:nlp的基础应用、高级应用、python优势、nltk环境搭建...
- centos7 mysql 5.5.27_centos7上安装mysql-5.7.27
- 实地址模式下的中断向量表
- opencvpython图像代码_PythonOpenCV各种图像库的图像读写 增强 方式的简单介绍(附代码)...
- JNI调用两层C++动态库
- 修饰类方法(静态方法)
- C#按指定长度分割字符串
- 基于余弦相似性的指纹匹配算法在WIFI室内定位上的应用(转)
- ubuntu防火墙问题
- 因计算机中丢失msvcr120.dll,msvcr120.dll一键修复工具 | 麦田一棵葱
- 北京圣思园java视频教程全套_北京圣思园Java8新特性及实战视频教程完整版
- Layabox2初学(一)javascript
- 进击zheng项目zheng-umps-server
- 如何实现报表高精度打印——套打
- 基于JAVAWeb前端开发技术儿童教育网站计算机毕业设计源码+数据库+lw文档+系统+部署