• 【Java/Graphics】Graphics2D绘制直方图例子


    先上图:

    代码:

    package graphics;
    
    import java.awt.BasicStroke;
    import java.awt.Color;
    import java.awt.Font;
    import java.awt.FontMetrics;
    import java.awt.Graphics2D;
    import java.awt.Stroke;
    import java.awt.geom.AffineTransform;
    import java.awt.image.BufferedImage;
    import java.io.FileOutputStream;
    import java.util.ArrayList;
    import java.util.List;
    
    import javax.imageio.ImageIO;
    
    class Bar{
        String name;
        int value;
        
        public Bar(String name,int value) {
            this.name=name;
            this.value=value;
        }
    }
    /**
     * 直方图生成器
     * @author ufo
     * 2022年1月31日
     */
    public class BarchartMaker {
        // 图片宽度
        private int width;
        
        // 图片高度
        private int height;
        
        // img对象
        private BufferedImage img;
        
        // 绘图环境
        private Graphics2D g2d;
        
        // 垂直方向起点
        private int yStart;
        
        // 垂直方向终点
        private int yEnd;
        
        // 直方图数据
        private List<Bar> bars;
        
        // 构造函数
        public BarchartMaker(int width,int height,int yStart,int yEnd){
            this.width=width;
            this.height=height;
            this.img=new BufferedImage(this.width,this.height,BufferedImage.TYPE_INT_RGB);
            this.g2d=(Graphics2D)img.getGraphics();
            this.yStart=yStart;
            this.yEnd=yEnd;
        }
        
        // 添加一项直方图数据
        public void addBar(String name,int value) {
            if(bars==null) {
                bars=new ArrayList<Bar>();
            }
            
            bars.add(new Bar(name,value));
        }
    
        // 重置屏幕坐标系为笛卡尔坐标系
        private void resetCoodinate() {
            AffineTransform trans = new AffineTransform();
            trans.translate(0,this.height-this.yStart);
            trans.rotate(getRad(180.0),0,0);
            trans.scale(-1,1);        
            this.g2d.setTransform(trans);
        }
        
        // 绘制图案
        public void draw() {
            resetCoodinate();
            
            // 设置背景为天蓝色
            g2d.setColor(new Color(135,206,235));
            g2d.fillRect(0, -this.yStart, this.width, this.height);
            
            final int yMax=this.yEnd;
            final int barCnt=this.bars.size();
            
            // --往下是竖向网格线
            final float stepx=this.width/barCnt;
            final float CW=stepx/3;// CW:Column Width
    
            // LINE_TYPE_DASHED   
            Stroke dashed=new BasicStroke(1,BasicStroke.CAP_BUTT,   
                                                      BasicStroke.JOIN_BEVEL,   0,   
                                                      new   float[]{16,   4},   0);
            
            g2d.setColor(Color.gray);
            
            for(int i=0;i<barCnt;i++) {
                float x=i*stepx;
                float y=yMax;
                
                g2d.setStroke(new BasicStroke(1.0f));
                g2d.drawLine((int)x, 0, (int)x, (int)y);
                
                g2d.setStroke(dashed);
                g2d.drawLine((int)(x+CW), 0, (int)(x+CW), (int)y);
                g2d.drawLine((int)(x+2*CW), 0, (int)(x+2*CW), (int)y);
            }
            
            // 以最高点定比例
            float maxCnt=-1;
            for(Bar b:bars) {
                if(b.value>maxCnt) {
                    maxCnt=b.value;
                }
            }
            final float ratio=yMax/maxCnt;
            
            // --往下是画横向网格线
            final float stepy=yMax/barCnt;
            final float GH=stepy/3;// GH:Grid Width
            
            for(int i=0;i<=barCnt;i++){
                float y=i*stepy;
                
                g2d.setStroke(new BasicStroke(1.0f));
                g2d.drawLine(0,(int)y, this.width, (int)y);
                
                g2d.setFont(new Font("宋体",Font.BOLD,16));
                g2d.setColor(Color.black);
                int yValue=(int)(y*maxCnt/yMax);
                putString(g2d,yValue+"",15,(int)y);
                
                if(i>0) {
                    g2d.setStroke(dashed);
                    g2d.drawLine(0,(int)(y-GH), this.width, (int)(y-GH));
                    g2d.drawLine(0,(int)(y-2*GH), this.width, (int)(y-2*GH));
                }
            }
            
            // --往下是画柱状图
            for(int i=0;i<this.bars.size();i++){
                Bar bar=this.bars.get(i);
                
                float x=i*stepx+(CW);
                float y=0;
                float w=CW;
                float h=bar.value*ratio;
                
                g2d.setColor(getColor(i));
                g2d.fillRect((int)x, (int)y, (int)(w), (int)(h));
                
                // 在柱子顶写文字
                g2d.setFont(new Font("宋体",Font.BOLD,16));
                g2d.setColor(Color.black);
                putString(g2d,bar.name+"="+bar.value,(int)(x+CW/2),(int)(h-15));
            }
            
            // 写标题
            g2d.setFont(new Font("宋体",Font.BOLD,36));
            g2d.setColor(Color.black);
            putString(g2d,"g2d绘制直方图示例",this.width/2,this.yEnd+50);
            
            // 写作者
            g2d.setFont(new Font("宋体",Font.BOLD,12));
            g2d.setColor(Color.black);
            putString(g2d,"逆火绘制于2022年1月31日",this.width-100,-25);
    
            g2d.dispose();// g2d使命完成
        }
        
        // 写入图片
        public void write2File(String path) {
            try {
                ImageIO.write(img, "PNG", new FileOutputStream(path));
            } catch (Exception e) {
                e.printStackTrace();
            } 
        }
        
        // 写文字
        private void putString(Graphics2D g2d,String text,int x,int y) {
            AffineTransform previousTrans = g2d.getTransform();
            
            AffineTransform newtrans = new AffineTransform();
    
            FontMetrics fm2=g2d.getFontMetrics();
            int textWidth=fm2.stringWidth(text);
            
            newtrans.translate(x-textWidth/2, (this.height-this.yStart)-y);
            
            g2d.setTransform(newtrans);
            g2d.drawString(text,0,0);
            
            g2d.setTransform(previousTrans);
        }
        
        // 传入度数,返回弧度
        private static double getRad(double degree) {
            return degree*Math.PI/180.0f;
        }
        
        // 取一种颜色
        private static Color getColor(int idx) {
            Color[] colors= {Color.red,Color.yellow,Color.blue,Color.magenta,Color.green,Color.orange,Color.cyan};
            
            int i=idx % colors.length;
            return colors[i];
        }
        
        public static void main(String[] args) {
            BarchartMaker pm=new BarchartMaker(1200,960,50,800);
            pm.addBar("勇气", 80);
            pm.addBar("毅力", 120);
            pm.addBar("果敢", 450);
            pm.addBar("机敏", 32);
            pm.addBar("决心", 360);
            pm.addBar("明智", 230);
            pm.addBar("忍耐", 420);
            
            pm.draw();
            
            pm.write2File("c:\\hy\\4.png");
            System.out.println("直方图做成");
        }
    }

    谨以以上代码纪念即将逝去的牛年,愿各位读者在新年里都健康多福!

    2022年1月31日19点44分

    END

  • 相关阅读:
    BZOJ4669 抢夺(网络流)
    三元环&四元环计数
    P3768 简单的数学题(杜教筛)
    P1829 [国家集训队]Crash的数字表格(莫比乌斯反演)
    P5221 Product(欧拉函数)
    P3704 [SDOI2017]数字表格(莫比乌斯反演)
    P4619 [SDOI2018]旧试题
    Loj6102. 「2017 山东二轮集训 Day1」第三题(min-max 反演)
    Leetcode220 存在重复元素III
    Leetcode219 存在重复元素II 滑动窗口
  • 原文地址:https://www.cnblogs.com/heyang78/p/15858556.html
Copyright © 2020-2023  润新知