JFreeChart OHLC图指定位置实心圆不显示及画线需求咨询
问题:在JFreeChart的OHLC图中添加指定交点的实心圆或延伸水平线
我正在使用JFreeChart库开发OHLC图,希望在价格水平10.5处绘制一条水平线,并在特定日期“2021-01-02”与该水平线的交点处放置一个实心圆。目前我的代码已成功绘制坐标轴、K线以及10.5处的水平线,但尝试添加的实心圆(point2d)因坐标问题无法显示。
附上当前代码:
import java.awt.BasicStroke; import java.awt.Color; import java.awt.geom.Ellipse2D; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import org.jfree.chart.ChartFactory; import org.jfree.chart.ChartPanel; import org.jfree.chart.JFreeChart; import org.jfree.chart.annotations.XYShapeAnnotation; import org.jfree.chart.axis.DateAxis; import org.jfree.chart.axis.NumberAxis; import org.jfree.chart.plot.ValueMarker; import org.jfree.chart.plot.XYPlot; import org.jfree.chart.renderer.xy.CandlestickRenderer; import org.jfree.data.xy.DefaultHighLowDataset; import org.jfree.data.xy.OHLCDataset; import org.jfree.data.xy.XYDataset; import org.jfree.ui.ApplicationFrame; import org.jfree.ui.RectangleInsets; public class OHLCChartDemo extends ApplicationFrame { public OHLCChartDemo(final String title) throws ParseException { super(title); final JFreeChart chart = createChart(createDataset()); setContentPane(new ChartPanel(chart)); } private OHLCDataset createDataset() throws ParseException { final SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd"); final DefaultHighLowDataset dataset = new DefaultHighLowDataset("Series 1", new Date[] { new Date(df.parse("2021-01-01").getTime()), new Date(df.parse("2021-01-02").getTime()), new Date(df.parse("2021-01-03").getTime()), new Date(df.parse("2021-01-04").getTime()) }, new double[] { 11.0, 13.0, 9.0, 12.0 }, new double[] { 8.0, 9.0, 7.0, 8.5 }, new double[] { 10.0, 11.0, 8.0, 10.5 }, new double[] { 9.0, 10.0, 8.5, 9.5 }, new double[] { 11.0, 11.0, 9.0, 9.5 }); return dataset; } private JFreeChart createChart(final XYDataset dataset) throws ParseException { final JFreeChart chart = ChartFactory.createCandlestickChart("OHLC Chart", "Date", "Price", (OHLCDataset) dataset, false); chart.setBackgroundPaint(Color.white); final XYPlot plot = (XYPlot) chart.getPlot(); plot.setBackgroundPaint(Color.white); plot.setDomainGridlinePaint(Color.lightGray); plot.setRangeGridlinePaint(Color.lightGray); plot.setAxisOffset(new RectangleInsets(5.0, 5.0, 5.0, 5.0)); plot.setDomainCrosshairVisible(true); plot.setRangeCrosshairVisible(true); final CandlestickRenderer renderer = new CandlestickRenderer(); renderer.setDrawVolume(false); plot.setRenderer(renderer); final DateAxis axis = (DateAxis) plot.getDomainAxis(); axis.setDateFormatOverride(new SimpleDateFormat("yyyy-MM-dd")); final NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis(); rangeAxis.setAutoRangeIncludesZero(false); double price = 10.5; final ValueMarker marker = new ValueMarker(price); marker.setPaint(Color.blue); plot.addRangeMarker(marker); final Ellipse2D point2d = new Ellipse2D.Double(2.5, 10.5, 20, 20); XYShapeAnnotation annotation = new XYShapeAnnotation(point2d, new BasicStroke(2.0f), Color.BLACK, Color.BLUE); plot.addAnnotation(annotation); return chart; } public static void main(final String[] args) throws ParseException { final OHLCChartDemo demo = new OHLCChartDemo("OHLC Chart Demo"); demo.pack(); demo.setVisible(true); } }
现咨询:如何在10.5价格线与“2021-01-02”日期的交点处绘制实心圆?或如何从该交点向右绘制延伸至图表末端的水平线?
解决方案1:绘制指定交点的实心圆
你之前使用XYShapeAnnotation出错,是因为直接用了不符合数据坐标的数值定义椭圆位置。更简便的方式是使用XYDotAnnotation,它直接支持数据坐标,无需手动转换:
- 解析目标日期
2021-01-02为Date对象,再转换为DateAxis使用的时间戳数值; - 创建
XYDotAnnotation,传入交点坐标、圆点大小、边框色和填充色; - 将注释添加到图表的
XYPlot中。
修改createChart方法中添加注释的部分:
// 替换原来的Ellipse2D和XYShapeAnnotation代码 SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd"); Date targetDate = df.parse("2021-01-02"); double x = targetDate.getTime(); // DateAxis使用时间戳作为x轴数值 double y = 10.5; // 创建实心圆点注释:参数依次是x坐标、y坐标、圆点大小、边框颜色、填充颜色 XYDotAnnotation dot = new XYDotAnnotation(x, y, 10, Color.BLACK, Color.BLUE); plot.addAnnotation(dot);
解决方案2:从交点向右绘制延伸至末端的水平线
要实现从交点向右延伸到图表末端的水平线,可以使用XYLineAnnotation,步骤如下:
- 获取目标日期的时间戳数值作为起点x坐标;
- 获取域轴(日期轴)的最大值作为终点x坐标;
- 创建
XYLineAnnotation,设置起点、终点、线条样式和颜色; - 将注释添加到
XYPlot中。
修改createChart方法的对应部分:
// 替换原来的注释代码 SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd"); Date targetDate = df.parse("2021-01-02"); double startX = targetDate.getTime(); double y = 10.5; // 获取域轴的最大值(图表末端的x坐标) DateAxis domainAxis = (DateAxis) plot.getDomainAxis(); double endX = domainAxis.getUpperBound(); // 创建水平线注释:参数依次是起点x、起点y、终点x、终点y、线条样式、线条颜色 XYLineAnnotation line = new XYLineAnnotation(startX, y, endX, y, new BasicStroke(2.0f), Color.RED); plot.addAnnotation(line);
注意:如果图表数据更新后域轴范围变化,需要重新计算endX的值,或者监听轴的范围变化事件来更新注释。
内容的提问来源于stack exchange,提问作者Igor Choriy
相关产品推荐
相关产品推荐

