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

如何在Java Apache POI折线图中交换类别与数值坐标轴

如何在Apache POI中实现折线图坐标轴互换(类别轴Y轴、数值轴X轴)

我当前的XLSX折线图中,类别轴位于X轴、数值轴位于Y轴,需要将两者位置互换,实现数值在X轴,类别在Y轴的效果。

我尝试了以下代码,但无法实现预期效果:

XSSFChart chart = drawing.createChart(anchor);
chart.setTitleText("Test Line Chart");
chart.setTitleOverlay(false);
XDDFChartLegend legend = chart.getOrAddLegend();
legend.setPosition(LegendPosition.TOP_RIGHT);

XDDFCategoryAxis leftAxis = chart.createCategoryAxis(AxisPosition.LEFT);
leftAxis.setTitle("Test Category");
XDDFValueAxis bottomAxis = chart.createValueAxis(AxisPosition.BOTTOM);
bottomAxis.setTitle("Test Values");
bottomAxis.setCrosses(AxisCrosses.AUTO_ZERO);

int firstRowNum = sheet.getFirstRowNum() + 1; //此处也用于柱状图组件
int lastRowNum = sheet.getLastRowNum();
XDDFLineChartData data = (XDDFLineChartData) chart.createData(ChartTypes.LINE, leftAxis, bottomAxis);

另外,我尝试为类别轴设置AxisOrientation.MAX_MIN,导出效果仍不符合预期。

我的数据添加代码如下:

int indexColor = 0;
MutableInt mutableRow = new MutableInt(-1);
byte[] colorChart = vpsChartsXlsxDocumentExportService.setColorChart(colors.get(indexColor));
XDDFSolidFillProperties fill = new XDDFSolidFillProperties(XDDFColor.from(colorChart));

String[] rawCategoryData = translationService.translate(language, null, chartData.getCaptions().toArray(new String[chartData.getCaptions().size()]));
BigDecimal[] rawValueData = chartData.getValues().get(0).toArray(new BigDecimal[chartData.getValues().get(0).size()]); //不止取数组第一个索引的数据

Row row = sheet.getRow(firstRowNum);
int cellValues = row.getLastCellNum() - 1;
int cellCategories = row.getFirstCellNum();

XDDFDataSource<String> categoriesData = XDDFDataSourcesFactory.fromStringCellRange(
        (XSSFSheet) sheet,
        new CellRangeAddress(firstRowNum, lastRowNum, cellCategories, cellCategories));

final int numOfPoints = rawCategoryData.length;
final String valuesDataRange = chart.formatRange(new CellRangeAddress(mutableRow.intValue(), numOfPoints, cellValues, cellValues));
final XDDFNumericalDataSource<BigDecimal> valuesData = XDDFDataSourcesFactory.fromArray(rawValueData, valuesDataRange, cellValues);

xddfLineChartData.addSeries(categoriesData, valuesData);
chart.plot(xddfLineChartData);
XDDFChartData.Series series = xddfLineChartData.getSeries(0);

解决方案

普通的LINE类型图表(类别轴+数值轴)默认只能将类别放在X轴、数值放在Y轴,无法直接互换位置。要实现类别在Y轴、数值在X轴的横向折线效果,需要使用XY折线图(ChartTypes.XYLINE),并通过自定义Y轴标签模拟类别轴。

具体步骤及示例代码如下:

XSSFChart chart = drawing.createChart(anchor);
chart.setTitleText("Test Horizontal Line Chart");
chart.setTitleOverlay(false);
XDDFChartLegend legend = chart.getOrAddLegend();
legend.setPosition(LegendPosition.TOP_RIGHT);

// 创建数值轴作为X轴(底部,绑定数值数据)
XDDFValueAxis bottomAxis = chart.createValueAxis(AxisPosition.BOTTOM);
bottomAxis.setTitle("Test Values");
bottomAxis.setCrosses(AxisCrosses.AUTO_ZERO);

// 创建数值轴作为Y轴(左侧,绑定类别索引)
XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT);
leftAxis.setTitle("Test Category");

// 准备数据:类别名称、对应数值、类别索引(用于Y轴绑定)
String[] rawCategoryData = translationService.translate(language, null, chartData.getCaptions().toArray(new String[chartData.getCaptions().size()]));
BigDecimal[] rawValueData = chartData.getValues().get(0).toArray(new BigDecimal[chartData.getValues().get(0).size()]);
Double[] categoryIndices = new Double[rawCategoryData.length];
for (int i = 0; i < rawCategoryData.length; i++) {
    categoryIndices[i] = (double) (i + 1); // 每个类别对应一个递增的数值索引
}

// 创建X轴(数值)和Y轴(类别索引)的数据源
XDDFNumericalDataSource<BigDecimal> xData = XDDFDataSourcesFactory.fromArray(rawValueData, "Values", 0);
XDDFNumericalDataSource<Double> yData = XDDFDataSourcesFactory.fromArray(categoryIndices, "Categories", 1);

// 创建XY折线图数据并绑定轴
XDDFXYChartData data = (XDDFXYChartData) chart.createData(ChartTypes.XYLINE, bottomAxis, leftAxis);
XDDFXYChartData.Series series = data.addSeries(xData, yData);
series.setTitle("Series", null);

// 自定义Y轴标签:用类别名称替换默认的数值索引
XDDFDataAxis dataAxis = (XDDFDataAxis) leftAxis;
dataAxis.setAxisBetweenCategories(false);
List<Double> tickPositions = new ArrayList<>();
List<String> tickLabels = new ArrayList<>();
for (int i = 0; i < rawCategoryData.length; i++) {
    tickPositions.add((double) (i + 1));
    tickLabels.add(rawCategoryData[i]);
}
dataAxis.setTickLabels(tickLabels);
dataAxis.setTickMarkPositions(tickPositions);
leftAxis.setMajorGridlinesVisible(false); // 可选:隐藏Y轴网格线

// 绘制图表并设置系列样式
chart.plot(data);
byte[] colorChart = vpsChartsXlsxDocumentExportService.setColorChart(colors.get(0));
XDDFSolidFillProperties fill = new XDDFSolidFillProperties(XDDFColor.from(colorChart));
XDDFLineProperties line = new XDDFLineProperties();
line.setFillProperties(fill);
series.setLineProperties(line);

关键说明

  • 普通LINE图表依赖「类别轴+数值轴」的固定组合,无法直接互换位置;XYLINE图表基于双数值轴,灵活性更高,适合实现横向折线效果。
  • 通过将类别转换为数值索引绑定到Y轴,再自定义Y轴标签为类别名称,模拟出类别轴的显示效果。
  • 需确保Y轴刻度位置与类别索引一一对应,保证标签显示准确。

内容的提问来源于stack exchange,提问作者beanairputih

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 02:45:36