You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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,它直接支持数据坐标,无需手动转换:

  1. 解析目标日期2021-01-02为Date对象,再转换为DateAxis使用的时间戳数值;
  2. 创建XYDotAnnotation,传入交点坐标、圆点大小、边框色和填充色;
  3. 将注释添加到图表的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,步骤如下:

  1. 获取目标日期的时间戳数值作为起点x坐标;
  2. 获取域轴(日期轴)的最大值作为终点x坐标;
  3. 创建XYLineAnnotation,设置起点、终点、线条样式和颜色;
  4. 将注释添加到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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 03:59:56