JFreeChart - Timeseries and CandleStick on the same chart

Richard B picture Richard B · Aug 29, 2012 · Viewed 8.7k times · Source

I'm trying to produce a single chart in JFreeChart that consists of an overlaid candlestick chart and Timeseries plot. (a little like this)

candlestick trend overlay
(source: prices-oil.org)

I have tried creating the Candlestick chart and then adding an additional XY series and it renderer but this results in a runtime error of org.jfree.data.xy.XYSeriesCollection cannot be cast to org.jfree.data.xy.OHLCDataset

A snippet of my code is as follows

private XYPlot plot;
private XYSeriesCollection dataTrend;
private XYItemRenderer renderer;

public OhlcChart(BarCollection bars)
{

JFreeChart jfreechart = ChartFactory.createCandlestickChart("FX Trader Prototype", "Time", "Value", getDataset(bars), true);
plot = (XYPlot)jfreechart.getPlot();
plot.setDomainPannable(true);


NumberAxis numberAxis = (NumberAxis)plot.getRangeAxis();
numberAxis.setAutoRangeIncludesZero(false);
    numberAxis.setAutoRangeStickyZero(false);
numberAxis.setUpperMargin(0.0D);
numberAxis.setLowerMargin(0.0D);

DateAxis dateAxis = (DateAxis) plot.getDomainAxis();
    SimpleDateFormat formatter  = new SimpleDateFormat("dd MMM HH:mm.ss");
    dateAxis.setDateFormatOverride(formatter);

    this.renderer = plot.getRenderer();
    Stroke myStroke = new BasicStroke((float) 1.0);

    this.renderer = new XYLineAndShapeRenderer();
    this.renderer.setSeriesPaint(0, Color.blue);
    this.renderer.setSeriesStroke(0, myStroke);

}

public OhlcChart update(Timeseries<Double> ts)
{
    Stroke myStroke = new BasicStroke((float) 1.0);
    XYLineAndShapeRenderer timeSeriesRenderer = new XYLineAndShapeRenderer();
    timeSeriesRenderer.setBaseShapesVisible(false);
    timeSeriesRenderer.setSeriesPaint(0, Color.blue);
    timeSeriesRenderer.setSeriesStroke(0, myStroke);

    UiTimeseries series = new UiTimeseries(ts);
    dataTrend.addSeries(series);
    plot.setDataset(plot.getDatasetCount()+1, dataTrend);
    plot.setRenderer(plot.getDatasetCount()+1, timeSeriesRenderer);

    return this;
}

Any advice would be gratefully received

Answer

GrahamA picture GrahamA · Aug 29, 2012

This is possible using JFreeChart, the key is to create an additional dataset and renderer

You will need to create a new TimeSeriesCollection to hold the data for the three additional series

TimeSeriesCollection otherDataSet = new TimeSeriesCollection();
TimeSeries ts1 = new TimeSeries("Series 1");
otherDataSet.addSeries(ts1);
TimeSeries ts2 = new TimeSeries("Series 2");
otherDataSet.addSeries(ts2);
TimeSeries ts3 = new TimeSeries("Series 2");
otherDataSet.addSeries(ts3);

Then add the data to the TimeSeries as normal.

You will then need to add the otherDataSet to the Plot in OhlcChart map it to the same axis at the original plot (mapDatasetToRangeAxis) and provide a Renderer

//Add the otherDataSet to the plot and map it to the same axis at the original plot 
int index = 1;
plot.setDataset(index, otherDataSet);
plot.mapDatasetToRangeAxis(index, 0);

XYItemRenderer renderer2 = new XYLineAndShapeRenderer();
plot.setRenderer(1, renderer2);
plot.setDatasetRenderingOrder(DatasetRenderingOrder.FORWARD);

Here is an example using an OHLCDataset rather than a BoxAndWhiskerXYDataset

enter image description here