JFreeChart自定义标注/标签位置及解决线条遮挡问题
JFreeChart 图表复刻问题解决方案
目标效果与当前实现
目标图表:
当前开发效果:
待解决问题
- 如何在
setLabelLocation()方法允许的边界外添加轴标签; - 如何在指定位置添加数值标签;
- 最右侧的绿色竖线被虚线轮廓遮挡,添加右侧次坐标轴后仍处于底层的解决办法。
问题解决方案
1. 边界外添加轴标签
JFreeChart默认轴标签的位置受限于setLabelLocation()的可选值,若要超出边界,可直接创建独立的TextTitle作为轴标签,通过调整偏移量放置到目标位置:
// 添加Y轴标签到左侧边界外 TextTitle yAxisLabel = new TextTitle("Fr(mN)"); yAxisLabel.setFont(new Font("SansSerif", Font.PLAIN, 12)); yAxisLabel.setPaint(Color.BLUE); yAxisLabel.setRotation(Math.PI / 2); // 垂直旋转 yAxisLabel.setHorizontalAlignment(HorizontalAlignment.CENTER); yAxisLabel.setPosition(RectangleEdge.LEFT); // 调整左偏移,让标签显示在轴外侧 yAxisLabel.setInsets(new RectangleInsets(0, -40, 0, 0)); chart.addSubtitle(yAxisLabel);
2. 指定位置添加数值标签
使用XYTextAnnotation可以在图表任意坐标位置添加文本标签,只需指定目标坐标和文本内容:
// 添加x=4竖线的数值标签 XYTextAnnotation xMarkerLabel = new XYTextAnnotation("4s", 4.2, 0); xMarkerLabel.setFont(new Font("SansSerif", Font.PLAIN, 10)); xMarkerLabel.setPaint(Color.GREEN); plot.addAnnotation(xMarkerLabel); // 添加y=4横线的数值标签 XYTextAnnotation yMarkerLabel = new XYTextAnnotation("4mN", 9.5, 4); yMarkerLabel.setFont(new Font("SansSerif", Font.PLAIN, 10)); yMarkerLabel.setPaint(Color.GREEN); plot.addAnnotation(yMarkerLabel);
3. 解决绿色竖线被遮挡问题
ValueMarker会被plot的虚线轮廓遮挡,改用XYLineAnnotation绘制竖线即可,因为annotation会绘制在所有plot元素的最上层:
// 用XYLineAnnotation绘制绿色竖线,覆盖整个Y轴范围 XYLineAnnotation greenVerticalLine = new XYLineAnnotation(4, -3, 4, 6, new BasicStroke(1.5f), Color.GREEN); plot.addAnnotation(greenVerticalLine);
修改后的完整代码
package javaapplication; import java.awt.BasicStroke; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.Stroke; import java.text.DecimalFormat; import java.text.NumberFormat; import java.util.Locale; import javax.swing.JFrame; import javax.swing.JPanel; import org.jfree.chart.ChartColor; import org.jfree.chart.ChartFactory; import org.jfree.chart.ChartPanel; import org.jfree.chart.JFreeChart; import org.jfree.chart.annotations.XYLineAnnotation; import org.jfree.chart.annotations.XYTextAnnotation; import org.jfree.chart.axis.AxisLabelLocation; import org.jfree.chart.axis.AxisLocation; import org.jfree.chart.axis.NumberAxis; import org.jfree.chart.plot.PlotOrientation; import org.jfree.chart.plot.ValueMarker; import org.jfree.chart.plot.XYPlot; import org.jfree.chart.renderer.xy.XYItemRenderer; import org.jfree.chart.title.TextTitle; import org.jfree.data.xy.XYSeries; import org.jfree.data.xy.XYSeriesCollection; import org.jfree.ui.HorizontalAlignment; import org.jfree.ui.Layer; import org.jfree.ui.RectangleEdge; import org.jfree.ui.RectangleInsets; public class JavaApplication { public static void main(String[] args){ PlotWindow pw = new PlotWindow(); pw.setVisible(true); } } public class PlotWindow extends JFrame { final double t_init = 0; final double step = 0.1; final double t_fin = 10; int lengthValues; double [] yValues; double [] xValues; //params double Fmax = 5; double Tau = 3; double alpha = 3; double deltaX; public PlotWindow() { super("Test JFreechart"); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setLocationRelativeTo(null); // x y values this.lengthValues = (int) ((this.t_fin-t_init)/this.step) + 1; this.setTimeValues(); this.computeDeltaX(); this.setForceValues(); JPanel jp = createChartPanel(); jp.setPreferredSize(new java.awt.Dimension(546, 447)); this.add(jp, BorderLayout.CENTER); this.pack(); this.setPreferredSize(new Dimension(546, 447)); } private void setTimeValues() { this.xValues = new double[this.lengthValues]; for(int i = 0; i < this.lengthValues; ++i) { this.xValues[i] = this.t_init + i*this.step; } } private void computeDeltaX() { this.deltaX = Math.sqrt(-this.Tau*Math.log(this.alpha/(1+this.alpha))); } private void setForceValues() { this.yValues = new double[lengthValues]; for(int i = 0; i < lengthValues; ++i) { double A = this.Fmax*(1+1/this.alpha); double B = 1-Math.exp(-Math.pow(this.xValues[i]-this.deltaX, 2)/this.Tau); this.yValues[i] = A*B-this.Fmax/this.alpha; } } private XYSeriesCollection createDataset() { boolean autoSort = false; boolean allowDuplicateXValues = false; XYSeriesCollection dataset = new XYSeriesCollection(); XYSeries series1 = new XYSeries("",autoSort,allowDuplicateXValues); for(int i = 0; i < lengthValues; ++i) { series1.add(this.xValues[i], this.yValues[i]); } dataset.addSeries(series1); return dataset; } private JPanel createChartPanel() { String chartTitle = "Wetting balance curve"; String xAxisLabel = ""; String yAxisLabel = ""; XYSeriesCollection dataset = createDataset(); JFreeChart chart = ChartFactory.createXYLineChart(chartTitle, xAxisLabel, yAxisLabel, dataset,PlotOrientation.VERTICAL,false,true,false); XYPlot plot = chart.getXYPlot(); //title TextTitle tt = new TextTitle(); tt.setText("C:\\MENISCO ST60\\Mesures\\22-5912-100.PM1"); tt.setPaint(Color.BLUE); tt.setFont( new java.awt.Font( "SansSerif", java.awt.Font.PLAIN, 10 ) ); chart.setTitle(tt); //empty subtitle (offset for the title) TextTitle tts = new TextTitle(); tts.setText(" "); tts.setPaint(Color.BLUE); tts.setFont( new java.awt.Font( "SansSerif", java.awt.Font.PLAIN, 6 ) ); chart.addSubtitle(tts); // norm subtitle TextTitle normtt = new TextTitle(" " + "Norme : J-STD-002E"); normtt.setFont(new Font("SansSerif", Font.BOLD, 12)); normtt.setPosition(RectangleEdge.BOTTOM); normtt.setPaint(Color.BLACK); normtt.setHorizontalAlignment(HorizontalAlignment.LEFT); chart.addSubtitle(normtt); // fmoy subtitle TextTitle fmoytt = new TextTitle(" " + "Force moyenne à 0.900 S: 0.25mN"); fmoytt.setFont(new Font("SansSerif", Font.PLAIN, 10)); fmoytt.setPosition(RectangleEdge.BOTTOM); fmoytt.setPaint(Color.BLUE); fmoytt.setHorizontalAlignment(HorizontalAlignment.LEFT); chart.addSubtitle(fmoytt); // 新增:添加Y轴标签到边界外 TextTitle yAxisLabel = new TextTitle("Fr(mN)"); yAxisLabel.setFont(new Font("SansSerif", Font.PLAIN, 12)); yAxisLabel.setPaint(Color.BLUE); yAxisLabel.setRotation(Math.PI / 2); yAxisLabel.setHorizontalAlignment(HorizontalAlignment.CENTER); yAxisLabel.setPosition(RectangleEdge.LEFT); yAxisLabel.setInsets(new RectangleInsets(0, -40, 0, 0)); chart.addSubtitle(yAxisLabel); // axis //domain axis plot.getDomainAxis().setLowerMargin(0.0); plot.getDomainAxis().setUpperMargin(0.0); NumberAxis domain = (NumberAxis) plot.getDomainAxis(); NumberFormat formatterd = DecimalFormat.getInstance(); formatterd.setMinimumFractionDigits(0); domain.setNumberFormatOverride(formatterd); domain.setStandardTickUnits(NumberAxis.createIntegerTickUnits()); domain.setTickMarksVisible(false); plot.getDomainAxis().setAxisLineVisible(false); //range axis plot.getRangeAxis().setLabelAngle(Math.PI/2); plot.getRangeAxis().setLabelLocation(AxisLabelLocation.HIGH_END); NumberAxis range = (NumberAxis) plot.getRangeAxis(); NumberFormat formatter = DecimalFormat.getInstance(Locale.ENGLISH); formatter.setMinimumFractionDigits(2); range.setNumberFormatOverride(formatter); plot.getRangeAxis().setAxisLineStroke(new BasicStroke(1.5f)); plot.getRangeAxis().setAxisLinePaint(Color.BLUE); plot.getRangeAxis().setTickMarksVisible(true); plot.getRangeAxis().setTickMarkPaint(Color.BLACK); plot.getRangeAxis().setTickMarkStroke(new BasicStroke(1.5f)); float lg = plot.getRangeAxis().getTickMarkOutsideLength(); plot.getRangeAxis().setTickMarkInsideLength(lg); plot.getRangeAxis().setRange(-3, 6); // background;gridline;outline plot.setAxisOffset(new RectangleInsets(0, 0, 0, 0)); plot.setDomainGridlinePaint(Color.DARK_GRAY); plot.setRangeGridlinePaint(Color.DARK_GRAY); plot.setBackgroundPaint(Color.white); plot.setOutlineStroke(plot.getDomainGridlineStroke()); //dashed outline plot.setOutlinePaint(Color.DARK_GRAY); XYItemRenderer renderer = plot.getRenderer(); renderer.setSeriesPaint(0, ChartColor.VERY_DARK_GREEN); // set green color to the xyline // vertical lines ValueMarker marker0 = new ValueMarker(0.2,Color.MAGENTA,new BasicStroke(1.5f)); ValueMarker marker1 = new ValueMarker(1,Color.MAGENTA,new BasicStroke(1.5f)); plot.addDomainMarker(marker0, Layer.FOREGROUND); plot.addDomainMarker(marker1,Layer.FOREGROUND); // 修改:用XYLineAnnotation绘制绿色竖线,避免被遮挡 XYLineAnnotation greenVerticalLine = new XYLineAnnotation(4, -3, 4, 6, new BasicStroke(1.5f), Color.GREEN); plot.addAnnotation(greenVerticalLine); //horizontal lines XYLineAnnotation line = new XYLineAnnotation(0, 4, 10, 4, new BasicStroke(2.0f), Color.green); plot.addAnnotation(line); XYLineAnnotation line0 = new XYLineAnnotation(0, 0, 10, 0, new BasicStroke(1.0f), Color.BLUE); plot.addAnnotation(line0); //dashed horizontal line float[] dash = {10.0f, 3.0f, 3.0f}; Stroke dashed = new BasicStroke(1.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10.0f, dash, 0.0f); XYLineAnnotation line1 = new XYLineAnnotation(0, -1, 10, -1, dashed, Color.MAGENTA); plot.addAnnotation(line1); // 新增:添加指定位置的数值标签 XYTextAnnotation xMarkerLabel = new XYTextAnnotation("4s", 4.2, 0); xMarkerLabel.setFont(new Font("SansSerif", Font.PLAIN, 10)); xMarkerLabel.setPaint(Color.GREEN); plot.addAnnotation(xMarkerLabel); XYTextAnnotation yMarkerLabel = new XYTextAnnotation("4mN", 9.5, 4); yMarkerLabel.setFont(new Font("SansSerif", Font.PLAIN, 10)); yMarkerLabel.setPaint(Color.GREEN); plot.addAnnotation(yMarkerLabel); //right side axis NumberAxis range2 = new NumberAxis(" "); range2.setAxisLinePaint(Color.GREEN); range2.setAxisLineStroke(new BasicStroke(1.5f)); range2.setTickMarksVisible(false); range2.setTickLabelsVisible(false); plot.setRangeAxis(1, range2); plot.setRangeAxisLocation(1, AxisLocation.BOTTOM_OR_RIGHT); return new ChartPanel(chart); } }
内容的提问来源于stack exchange,提问作者vivier
相关产品推荐
相关产品推荐

