Search code examples
javajfreechart

Why circle is not displayed in JFreeChart?


I am currently experimenting with the JFreeChart library to create an OHLC chart. I would like to draw a horizontal line at a certain price level, for example, at 10.5, and place a point on the line at a specific date, for example, "2021-01-02". Although my code successfully draws the axis, bars, and a horizontal line at 10.5, but the filled circle/point (point2d) I tried to add is not visible by some reason (probably because of wrong coordinates).

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);
    }
}

How can I draw a filled circle at the intersection of the horizontal line at level (FEX)10.5 and the date (FEX)"2021-01-02"? Alternatively, how can I draw a horizontal line starting from that point and extending to the right end of the chart?


Solution

  • XYShapeAnnotation notes that "shape coordinates are specified in data space." For a DateAxis, this is milliseconds since the Java epoch. As an example, the following ad hoc fragment added to your example produces the ellipse show below. It's a half-day wide and one price unit high.

    double w = 12 * 60 * 60 * 1000;
    double t = dataset.getX(0, 1).doubleValue() - w;
    final Ellipse2D point2d =
        new Ellipse2D.Double(t + w / 2, 10, w, 1);
    

    Annotation image