【java/awt】绘制直方图例子,此例适应于值有正有负的情况
注意当前只是初稿状态,还有待修改。
先上图:
代码:
package flexChart; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics2D; import java.awt.RenderingHints; 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; } } // 点类 class Point{ public Point(float x,float y) { this.x=x; this.y=y; } float x; float y; } /** * 直方图 * @author ufo * 2022年2月15日 */ public class FlexChartMaker { // 图片宽度 private final int WIDTH; // 图片高度 private final int HEIGHT; // 上下边界宽度 private final int MARGIN; // 标题栏高度 private final int TITLE_HEIGHT; // img对象 private BufferedImage img; // 绘图环境 private Graphics2D g2d; // 直方图数据 private List<Bar> bars; private int yStart=0; /** * 构造函数 * @param width * @param height * @param margin * @param titleHeight */ public FlexChartMaker(int width,int height,int margin,int titleHeight) { this.WIDTH=width; this.HEIGHT=height; this.MARGIN=margin; this.TITLE_HEIGHT=titleHeight; this.img=new BufferedImage(this.WIDTH,this.HEIGHT,BufferedImage.TYPE_INT_RGB); this.g2d=(Graphics2D)img.getGraphics(); } // 写入图片 public void write2File(String path) { try { ImageIO.write(this.img, "PNG", new FileOutputStream(path)); } catch (Exception e) { e.printStackTrace(); } } // 绘制图案 public void draw() { // 消除线条锯齿 g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); // 白色底漆 g2d.setColor(Color.white); g2d.fillRect(0, 0, this.WIDTH, this.HEIGHT); // 画脚标 g2d.setFont(new Font("黑体",Font.PLAIN,8)); FontMetrics fm1=g2d.getFontMetrics(); String text="逆火狂飙绘制"; int textWidth=fm1.stringWidth(text); g2d.setColor(Color.black); g2d.drawString(text,(this.WIDTH-textWidth)/2,this.HEIGHT-this.MARGIN/2); // 标题栏区域 g2d.setColor(new Color(135,206,200)); g2d.fillRect(this.MARGIN, this.MARGIN, this.WIDTH-2*this.MARGIN, this.TITLE_HEIGHT); // 画标题 g2d.setFont(new Font("宋体",Font.BOLD,36)); FontMetrics fm2=g2d.getFontMetrics(); text="g2d绘制直方图示例"; textWidth=fm2.stringWidth(text); g2d.setColor(Color.white); g2d.drawString(text,(this.WIDTH-textWidth)/2,this.MARGIN+this.TITLE_HEIGHT/2+10); // 天蓝色可绘制区域 g2d.setColor(new Color(135,206,235)); g2d.fillRect(this.MARGIN, this.MARGIN+this.TITLE_HEIGHT, this.WIDTH-2*this.MARGIN, this.HEIGHT-2*this.MARGIN-this.TITLE_HEIGHT); // 算y起点 int max=-this.HEIGHT; int min= this.HEIGHT; // 取极值 for(Bar b:bars) { if(b.value>max) { max=b.value; } if(b.value<min) { min=b.value; } } System.out.println("max="+max+" min="+min); int yZero=0; if(max>0 && min>0) { yZero=this.HEIGHT-this.MARGIN; }else if(max<0 && min<0) { yZero=this.TITLE_HEIGHT+this.MARGIN; }else if(max>0 && min<0) { yZero=(this.HEIGHT-2*this.MARGIN-this.TITLE_HEIGHT)/2+this.TITLE_HEIGHT+this.MARGIN; this.yStart=yZero; // 基准线 g2d.setColor(Color.yellow); g2d.setStroke(new BasicStroke(1.0f)); g2d.drawLine(this.MARGIN,yZero, this.WIDTH-this.MARGIN, yZero); // 进行坐标变换,上面为屏幕坐标系,下面为平面直角坐标系(笛卡尔坐标系) resetCoodinate(yZero); // 绘图区域的端点 int xStart=0; int xEnd=xStart+this.WIDTH-2*this.MARGIN; int yMin=yZero-(this.HEIGHT-this.MARGIN); int yMax=(this.HEIGHT)-yZero-this.MARGIN; System.out.println(String.format("xStart=%d,xEnd=%d,yMin=%d,yMax=%d,", xStart,xEnd,yMin,yMax)); // 柱子数量 final int barCnt=this.bars.size(); // 竖向网格线开始 final float stepx=(this.WIDTH-2*this.MARGIN)/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; g2d.setStroke(new BasicStroke(1.0f)); g2d.drawLine((int)x, yMin, (int)x, yMax); g2d.setStroke(dashed); g2d.drawLine((int)(x+CW), yMin, (int)(x+CW), yMax); g2d.drawLine((int)(x+2*CW), yMin, (int)(x+2*CW), yMax); } // 竖向网格线结束 // 以最指定比例 float maxCnt=-1; for(Bar b:bars) { int abs=Math.abs(b.value); if(abs>maxCnt) { maxCnt=abs; } } final float ratio=yMax/maxCnt; // 横向网格线开始 final float stepy=(yMax-yMin)/barCnt; final float GH=stepy/3;// GH:Grid Width for(int i=0;i<=barCnt;i++){ float y=yMin+i*stepy; g2d.setStroke(new BasicStroke(1.0f)); g2d.drawLine(xStart,(int)y, xEnd, (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); yValue=(int)((y-GH)*maxCnt/yMax); g2d.drawLine(xStart,(int)(y-GH), xEnd, (int)(y-GH)); putString(g2d,yValue+"",xEnd+15,(int)(y-GH)); g2d.drawLine(xStart,(int)(y-2*GH), xEnd, (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 w=CW; float y=0,h=0; if(bar.value>0) { y=0; h=bar.value*ratio; }else { y=bar.value*ratio; h=Math.abs(bar.value*ratio); } g2d.setColor(getColor(i)); g2d.fillRect((int)x, (int)y, (int)(w), (int)(h)); // 在柱子顶写文字 float textX=x+CW/2+17; float textY=y+h/2; g2d.setFont(new Font("宋体",Font.BOLD,16)); g2d.setColor(Color.black); putString(g2d,bar.name+"="+bar.value,(int)(textX),(int)(textY)); } } } // 重置屏幕坐标系为笛卡尔坐标系 private void resetCoodinate(int yStart) { AffineTransform trans = new AffineTransform(); trans.translate(this.MARGIN,this.HEIGHT-yStart+this.TITLE_HEIGHT); trans.rotate(getRad(180.0),0,0); trans.scale(-1,1); this.g2d.setTransform(trans); } // 添加一项直方图柱子 public void addBar(String name,int value) { if(bars==null) { bars=new ArrayList<Bar>(); } bars.add(new Bar(name,value)); } // 传入度数,返回弧度 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]; } // 写文字 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+this.TITLE_HEIGHT)-y); g2d.setTransform(newtrans); g2d.drawString(text,0,0); g2d.setTransform(previousTrans); } public static void main(String[] args) { FlexChartMaker fcm=new FlexChartMaker(1200,960,20,80); fcm.addBar("a", 180); fcm.addBar("b", 40); fcm.addBar("c", -122); fcm.addBar("d", 30); fcm.addBar("e", 30); fcm.addBar("f", 20); fcm.draw(); fcm.write2File("c:\\hy\\220215.png"); System.out.println("图片做成"); } }
END
分类:
Java.Graphics2D
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
2020-02-15 将高考成绩流水表转化成高考成绩汇总表
2020-02-15 万里挑一进清北
2020-02-15 生成十万考生的语数英理化高考成绩流水表
2017-02-15 【Canvas与艺术】绘制六叶草繁花似锦桌面(1920*1080)