如何在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
相关产品推荐
相关产品推荐

