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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:18:43