I'm trying to create a candlestick chart, which user can zoom and pan, exacly like this TradingView chart.
// Domain axis
DateAxis dateAxis = new DateAxis();
// Range axis
NumberAxis priceAxis = new NumberAxis("Price");
priceAxis.setRangeType(RangeType.POSITIVE);
priceAxis.setAutoRange(true);
priceAxis.setAutoRangeIncludesZero(false);
// Plot
CandlestickRenderer renderer = new CandlestickRenderer();
XYPlot plot = new XYPlot(mPriceDataSet, dateAxis, priceAxis, renderer);
plot.setDomainPannable(true);
plot.setRangePannable(false);
// Chart
mChart = new JFreeChart("Price History", plot);
which mPriceDataSet
is my data set and is of type DefaultOHLCDataset
. And here is how I create the ChartPanel
:
ChartPanel chartPanel = new ChartPanel(mChart);
chartPanel.setMouseZoomable(true);
chartPanel.setRangeZoomable(false);
chartPanel.setMouseWheelEnabled(true);
Behavior: When the chart is rendered everything is okay, however when user zooms and/or pans the view port, the range axis doesn't scale and shows the very first range.
Desired Behavior: While zooming/panning range axis should dynamically set its range. Exactly like TrandingView charts.
MCVE
I've created an MCVE based on your Sample8. To reproduce the problem, just run the app and select the candle at 12:5 using mouse dragging. As you can see, the chart after zoom/selection will not be auto ranged and user has to manually do so using the context menu.
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.*;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.renderer.xy.CandlestickRenderer;
import org.jfree.data.time.Minute;
import org.jfree.data.time.ohlc.OHLCSeries;
import org.jfree.data.time.ohlc.OHLCSeriesCollection;
import javax.swing.*;
import java.awt.*;
import java.text.SimpleDateFormat;
public class AutoRangeTestApp {
private final ChartPanel chartPanel;
private final OHLCSeriesCollection seriesCollection = new OHLCSeriesCollection();
public AutoRangeTestApp() {
JFreeChart chart = ChartFactory.createCandlestickChart(
"Sample8", "Time", "Price", seriesCollection, true);
chart.getXYPlot().setOrientation(PlotOrientation.VERTICAL);
chart.getXYPlot().setDomainPannable(true);
CandlestickRenderer r = (CandlestickRenderer) chart.getXYPlot().getRenderer();
r.setAutoWidthMethod(CandlestickRenderer.WIDTHMETHOD_SMALLEST);
// Y-axis
NumberAxis numberAxis = (NumberAxis) chart.getXYPlot().getRangeAxis();
numberAxis.setAutoRangeIncludesZero(false);
numberAxis.setAutoRangeStickyZero(false);
// X-axis
DateAxis dateAxis = (DateAxis) chart.getXYPlot().getDomainAxis();
dateAxis.setDateFormatOverride(new SimpleDateFormat("HH:mm"));
dateAxis.setTickUnit(new DateTickUnit(DateTickUnitType.MINUTE, 1));
dateAxis.setTickMarkPosition(DateTickMarkPosition.MIDDLE);
// chartPanel
chartPanel = new ChartPanel(chart) {
@Override
public Dimension getPreferredSize() {
return new Dimension(800, 400);
}
};
chartPanel.setMouseWheelEnabled(true);
chartPanel.setMouseZoomable(true);
chartPanel.setRangeZoomable(false);
// series
addSeries1();
}
private void addSeries1() {
OHLCSeries series = new OHLCSeries("One");
series.add(new Minute(0, 12, 1, 1, 2014), 97.23D, 98.47D, 97.15D, 97.43);
series.add(new Minute(1, 12, 1, 1, 2014), 96.47D, 98.81D, 96.27D, 97.49);
series.add(new Minute(2, 12, 1, 1, 2014), 95.88D, 96.87D, 96.11D, 96.75);
series.add(new Minute(3, 12, 1, 1, 2014), 96.05D, 96.94D, 95.89D, 96.59);
series.add(new Minute(4, 12, 1, 1, 2014), 95.92D, 97.00D, 95.69D, 96.92);
series.add(new Minute(5, 12, 1, 1, 2014), 96.34D, 96.71D, 95.68D, 96.70);
series.add(new Minute(6, 12, 1, 1, 2014), 96.65D, 96.87D, 94.91D, 96.38);
series.add(new Minute(7, 12, 1, 1, 2014), 97.75D, 98.20D, 96.90D, 97.24);
series.add(new Minute(8, 12, 1, 1, 2014), 97.72D, 98.47D, 97.35D, 97.64);
series.add(new Minute(9, 12, 1, 1, 2014), 98.30D, 98.77D, 97.56D, 97.99);
seriesCollection.addSeries(series);
}
public ChartPanel getChartPanel() {
return chartPanel;
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
AutoRangeTestApp app = new AutoRangeTestApp();
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(app.getChartPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}