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绘制正态分布统计图相关推荐

  1. java k线绘制,用Java绘制K线图[Java编程]

    赞助商链接 本文"用Java绘制K线图[Java编程]"是由七道奇为您精心收集,来源于网络转载,文章版权归文章作者所有,本站不对其观点以及内容做任何评价,请读者自行判断,以下是其具 ...

  2. python绘制正态分布曲线

    场景:已知mean和variance,绘制正态分布曲线. import numpy as np import matplotlib.pyplot as plt import pandas as pd ...

  3. python绘制正态分布函数_学好正态分布有多重要?

    作者 | Farhad Malik 译者 | Monanfei 责编 | 夕颜 出品 | AI科技大本营(ID: rgznai100) 为什么正态分布如此特殊?为什么大量数据科学和机器学习的文章都围绕 ...

  4. html一个页面同时加载多个饼图,Html5饼图绘制实现统计图的方法

    Html5提供了强大的绘图API,让我们能够使用javascript轻松绘制各种图形.本文将主要讲解使用HTML5绘制饼图(统计图)的方法.先看一下饼图效果: 这个图是动态生成的,根据传入的比例参数( ...

  5. java绘制图形_java绘制基本图形.doc

    java绘制基本图形 java绘制基本图形 1. * *** ***** 2. * * * ***** 3. ************* * * * * ************* 4. ****** ...

  6. JAVA几何图注水,如何使用java绘制几何形状到图片?

    在Java语言编程中,如何使用Java绘制几何形状到图片? 注意:需要访问网址: , 下载一个OpenCV软件包.这里下载最新版本:opencv-3.2.0-vc14.exe并解压此文件到D:soft ...

  7. Python-Matplotlib可视化(3)——自定义样式绘制精美统计图

    Python-Matplotlib可视化(3)--自定义样式绘制精美统计图 前言 控制线条样式和线宽 线条样式 线宽 控制填充样式 控制标记样式 控制标记大小 创建自定义标记 总结--对标记进行更精细 ...

  8. 正态分布的概率密度函数python_python绘制正态分布及三大抽样分布的概率密度图像...

    目录 1.scipy库中各分布对应的方法 2.stats中各分布的常用方法及其功能 3.正态分布的概率密度函数及其图象 1)正态分布的概率密度函数及其图象 2)python绘制正态分布的概率密度函数图 ...

  9. 京东百万年薪大佬用JAVA绘制“五子棋棋盘”(附代码)

    这篇文章主要为大家详细介绍了java绘制五子棋棋盘,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 具体内容如下 源码: import javax.imageio.Ima ...

最新文章

  1. java排序算法(冒泡,插入,选择,快速,堆,归并,希尔,基数)
  2. 服务器中加速BIOS启动的方法
  3. java web开发技巧_java web开发技巧
  4. shell 中scp 和 ssh密码输入 --expect (转:http://blog.sina.com.cn/s/blog_8ad7d4ca01014lft.html)
  5. android单独刷入镜像
  6. python QTreeWidgetItem下面有几个子tree_python-nlp ch1笔记:nlp的基础应用、高级应用、python优势、nltk环境搭建...
  7. centos7 mysql 5.5.27_centos7上安装mysql-5.7.27
  8. 实地址模式下的中断向量表
  9. opencvpython图像代码_PythonOpenCV各种图像库的图像读写 增强 方式的简单介绍(附代码)...
  10. JNI调用两层C++动态库
  11. 修饰类方法(静态方法)
  12. C#按指定长度分割字符串
  13. 基于余弦相似性的指纹匹配算法在WIFI室内定位上的应用(转)
  14. ubuntu防火墙问题
  15. 因计算机中丢失msvcr120.dll,msvcr120.dll一键修复工具 | 麦田一棵葱
  16. 北京圣思园java视频教程全套_北京圣思园Java8新特性及实战视频教程完整版
  17. Layabox2初学(一)javascript
  18. 进击zheng项目zheng-umps-server
  19. 如何实现报表高精度打印——套打
  20. 基于JAVAWeb前端开发技术儿童教育网站计算机毕业设计源码+数据库+lw文档+系统+部署

热门文章

  1. Android 音视频深入 十八 FFmpeg播放视频,有声音(附源码下载)
  2. 采集资源结束后,图片不显示解决办法
  3. Android 调用谷歌原生语音识别
  4. 获取图片上任意一点的颜色值
  5. 【刷题】BZOJ 2959 长跑
  6. Visio中添加连接点的方法
  7. 高效发表科技论文的写作方法与技巧
  8. 15个有效学习方法【转载】
  9. 微信iOS新版支持手机、iPad、电脑同时在线
  10. 【最新】2020年注册测绘师考试测绘综合能力真题及参考答案