如何在JFreeChart同一绘图区添加蜡烛图与成交量柱形图
没问题!要在JFreeChart里实现蜡烛图+下方透明成交量柱的布局,核心是用CombinedDomainXYPlot把蜡烛图的主图和成交量的柱形图绑定到同一个X轴上,这样两者的时间维度就能完美对齐。下面是完整的可运行示例代码,你可以直接参考:
import org.jfree.chart.ChartFactory; import org.jfree.chart.ChartPanel; import org.jfree.chart.JFreeChart; import org.jfree.chart.axis.DateAxis; import org.jfree.chart.plot.CombinedDomainXYPlot; import org.jfree.chart.plot.PlotOrientation; import org.jfree.chart.plot.XYPlot; import org.jfree.chart.renderer.xy.CandlestickRenderer; import org.jfree.chart.renderer.xy.XYBarRenderer; import org.jfree.data.time.Day; import org.jfree.data.time.TimeSeries; import org.jfree.data.time.TimeSeriesCollection; import org.jfree.data.xy.DefaultOHLCDataset; import org.jfree.data.xy.OHLCDataset; import org.jfree.data.xy.XYDataset; import org.jfree.ui.ApplicationFrame; import org.jfree.ui.RefineryUtilities; import java.awt.*; import java.text.SimpleDateFormat; import java.util.Date; public class CandlestickWithVolumeChart extends ApplicationFrame { public CandlestickWithVolumeChart(String title) { super(title); JFreeChart chart = createCombinedChart(); ChartPanel chartPanel = new ChartPanel(chart); chartPanel.setPreferredSize(new Dimension(800, 600)); setContentPane(chartPanel); } private JFreeChart createCombinedChart() { // 1. 创建蜡烛图数据集(OHLC数据) OHLCDataset candleDataset = createCandleDataset(); // 2. 创建成交量数据集 XYDataset volumeDataset = createVolumeDataset(); // 创建蜡烛图子图 JFreeChart candleChart = ChartFactory.createCandlestickChart( null, null, "Price", candleDataset, false ); XYPlot candlePlot = candleChart.getXYPlot(); // 自定义蜡烛图渲染器(可选,调整颜色等) CandlestickRenderer candleRenderer = (CandlestickRenderer) candlePlot.getRenderer(); candleRenderer.setUpPaint(Color.GREEN); candleRenderer.setDownPaint(Color.RED); // 创建成交量柱形图子图 JFreeChart volumeChart = ChartFactory.createXYBarChart( null, null, false, "Volume", volumeDataset, PlotOrientation.VERTICAL, false, false, false ); XYPlot volumePlot = volumeChart.getXYPlot(); // 设置柱形图透明效果 XYBarRenderer volumeRenderer = (XYBarRenderer) volumePlot.getRenderer(); volumeRenderer.setAlpha(0.5f); // 0.0全透明,1.0不透明 volumeRenderer.setSeriesPaint(0, Color.BLUE); // 3. 组合两个图,共享X轴 CombinedDomainXYPlot combinedPlot = new CombinedDomainXYPlot(new DateAxis("Date")); // 添加蜡烛图(占比70%高度)和成交量图(占比30%高度) combinedPlot.add(candlePlot, 7); combinedPlot.add(volumePlot, 3); // 创建最终图表 JFreeChart combinedChart = new JFreeChart("Stock Price & Volume", JFreeChart.DEFAULT_TITLE_FONT, combinedPlot, false); // 格式化X轴日期显示 DateAxis domainAxis = (DateAxis) combinedPlot.getDomainAxis(); domainAxis.setDateFormatOverride(new SimpleDateFormat("yyyy-MM-dd")); return combinedChart; } // 模拟生成OHLC蜡烛图数据 private OHLCDataset createCandleDataset() { double[][] data = new double[10][5]; Day[] days = new Day[10]; Date baseDate = new Date(); for (int i = 0; i < 10; i++) { days[i] = new Day(baseDate); double open = 100 + Math.random() * 10; double high = open + Math.random() * 5; double low = open - Math.random() * 5; double close = low + Math.random() * (high - low); double volume = 10000 + Math.random() * 5000; data[i] = new double[]{days[i].getMiddleMillisecond(), open, high, low, close, volume}; baseDate = new Date(baseDate.getTime() + 86400000); // 加一天 } return new DefaultOHLCDataset("Stock", data); } // 模拟生成成交量数据 private XYDataset createVolumeDataset() { TimeSeries series = new TimeSeries("Volume"); Date baseDate = new Date(); for (int i = 0; i < 10; i++) { Day day = new Day(baseDate); double volume = 10000 + Math.random() * 5000; series.add(day, volume); baseDate = new Date(baseDate.getTime() + 86400000); } return new TimeSeriesCollection(series); } public static void main(String[] args) { CandlestickWithVolumeChart chartFrame = new CandlestickWithVolumeChart("Candlestick + Volume Chart"); chartFrame.pack(); RefineryUtilities.centerFrameOnScreen(chartFrame); chartFrame.setVisible(true); } }
你可以重点关注这几个关键点:
- 使用
CombinedDomainXYPlot实现双图共享X轴,确保蜡烛图和成交量的时间轴完全对齐 - 通过
XYBarRenderer.setAlpha()设置成交量柱的透明度,数值范围0.0到1.0,你可以根据需求调整 - 两个子图的高度占比通过
add(plot, weight)方法设置,示例里是7:3的比例,你也可以改成更适合的数值 - 蜡烛图的颜色可以通过
CandlestickRenderer的setUpPaint()和setDownPaint()自定义上涨/下跌的颜色
运行这段代码就能得到类似你需求的效果啦!
内容的提问来源于stack exchange,提问作者ACz
相关产品推荐
相关产品推荐

