【问题标题】:Color BarChart bars depending on data using Apache POI颜色条形图条取决于使用 Apache POI 的数据
【发布时间】:2021-02-18 15:43:24
【问题描述】:

我正在尝试将图表的每个单独条形的填充颜色设置为单独的自定义颜色,但我还没有发现如何。

到目前为止,这是我的代码。布局很好,但图表栏都是相同的颜色(矢车菊蓝色)。我知道我可以使用 XDDFChartData:setVaryColors 选项来使用不同的颜色,但我找不到指定使用哪种颜色的方法(比如在我的示例中,红色的“书籍”,蓝色的“DVD”等。 )。

final Workbook workbook = new XSSFWorkbook();
final Sheet sheet = workbook.createSheet("MySheet");

Row row = sheet.createRow(1);

Cell cell = row.createCell(1);
cell.setCellValue("Product");

cell = row.createCell(2);
cell.setCellValue("Orders");

row = sheet.createRow(2);

cell = row.createCell(1);
cell.setCellValue("Books");

cell = row.createCell(2);
cell.setCellValue(50);

row = sheet.createRow(3);

cell = row.createCell(1);
cell.setCellValue("DVDs");

cell = row.createCell(2);
cell.setCellValue(25);

row = sheet.createRow(4);

cell = row.createCell(1);
cell.setCellValue("CDs");

cell = row.createCell(2);
cell.setCellValue(140);

XSSFDrawing drawing = ((XSSFSheet) sheet).createDrawingPatriarch();
XSSFClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 4, 1, 12, 15 );

XSSFChart chart = drawing.createChart(anchor);
chart.setTitleText("Products");
chart.setTitleOverlay(false);

CTBoolean FALSE = CTBoolean.Factory.newInstance();
FALSE.setVal(false);
chart.getCTChartSpace().setRoundedCorners(FALSE);

XDDFCategoryAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
bottomAxis.setMajorTickMark(AxisTickMark.NONE);

XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT);
leftAxis.setCrosses(AxisCrosses.AUTO_ZERO);
leftAxis.setCrossBetween(AxisCrossBetween.BETWEEN);

XDDFDataSource<String> compliances = XDDFDataSourcesFactory.fromStringCellRange((XSSFSheet) sheet, new CellRangeAddress(2, 4, 1, 1));

XDDFNumericalDataSource<Double> components = XDDFDataSourcesFactory.fromNumericCellRange((XSSFSheet) sheet, new CellRangeAddress(2, 4, 2, 2));

XDDFChartData data = chart.createData(ChartTypes.BAR, bottomAxis, leftAxis);

XDDFChartData.Series series1 = data.addSeries(compliances, components);
series1.setTitle("Components by Compliance", null);

chart.plot(data);

XDDFBarChartData bar = (XDDFBarChartData) data;
bar.setBarDirection(BarDirection.BAR);

CTSRgbColor rgb = CTSRgbColor.Factory.newInstance();

Color col1 = new Color(100, 149, 237);
rgb.setVal(new byte[]{(byte) col1.getRed(), (byte) col1.getGreen(), (byte) col1.getBlue()});

CTSolidColorFillProperties fillProp = CTSolidColorFillProperties.Factory.newInstance();
fillProp.setSrgbClr(rgb);

CTShapeProperties ctShapeProperties = CTShapeProperties.Factory.newInstance();
ctShapeProperties.setSolidFill(fillProp);
        chart.getCTChart().getPlotArea().getBarChartList().get(0).getSerList().get(0).setSpPr(ctShapeProperties);

IntStream.range(0, 10).forEach(sheet::autoSizeColumn);

有什么想法吗?

干杯!

【问题讨论】:

  • apache poi 示例 svn.apache.org/repos/asf/poi/trunk/src/examples/src/org/apache/… 提供 private static void solidFillSeries(XDDFChartData data, int index, PresetColor color) 来设置条形颜色。
  • 所以只能在每个系列的基础上着色条?我的图表只有一个系列。我原以为这是可行的。毕竟我可以在 Excel 中手动指定颜色...
  • 如果您被限制为每个系列一种颜色(看起来确实如此),您可以为每个数据项创建一个系列(或每个所需颜色一个系列)。之前我不得不对其他具有类似限制的图表库执行此操作。这是一个繁重的黑客,但有时你必须做你必须做的......

标签: java apache-poi bar-chart


【解决方案1】:

似乎您想要为每个数据点而不是条形系列着色。如果是这样,那么这与how to set custom colors in pie 3D Chart using Apache poi 4.1.2 的问题相同。区别只是图表类型。

目前还没有XDDF 方法来设置数据点颜色。只能使用XDDF 方法设置系列颜色。所以必须使用底层的org.openxmlformats.schemas.drawingml.x2006.chart.* 类。以下完整示例显示了这一点。它从一堆以前设置的 rgb 字节数组中设置数据点颜色。

import java.io.FileOutputStream;
import java.io.IOException;

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xddf.usermodel.chart.*;
import org.apache.poi.xssf.usermodel.*;

import org.openxmlformats.schemas.drawingml.x2006.chart.*;

public class BarChartOneSeries {

  public static void main(String[] args) throws IOException {
    final Workbook workbook = new XSSFWorkbook();
    final Sheet sheet = workbook.createSheet("MySheet");

    Row row = sheet.createRow(1);

    Cell cell = row.createCell(1);
    cell.setCellValue("Product");

    cell = row.createCell(2);
    cell.setCellValue("Orders");

    row = sheet.createRow(2);

    cell = row.createCell(1);
    cell.setCellValue("Books");

    cell = row.createCell(2);
    cell.setCellValue(50);

    row = sheet.createRow(3);

    cell = row.createCell(1);
    cell.setCellValue("DVDs");

    cell = row.createCell(2);
    cell.setCellValue(25);

    row = sheet.createRow(4);

    cell = row.createCell(1);
    cell.setCellValue("CDs");

    cell = row.createCell(2);
    cell.setCellValue(140);

    XSSFDrawing drawing = ((XSSFSheet) sheet).createDrawingPatriarch();
    XSSFClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 4, 1, 12, 15 );

    XSSFChart chart = drawing.createChart(anchor);
    chart.setTitleText("Products");
    chart.setTitleOverlay(false);

    CTBoolean FALSE = CTBoolean.Factory.newInstance();
    FALSE.setVal(false);
    chart.getCTChartSpace().setRoundedCorners(FALSE);

    XDDFCategoryAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
    bottomAxis.setMajorTickMark(AxisTickMark.NONE);

    XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT);
    leftAxis.setCrosses(AxisCrosses.AUTO_ZERO);
    leftAxis.setCrossBetween(AxisCrossBetween.BETWEEN);

    XDDFDataSource<String> compliances = XDDFDataSourcesFactory.fromStringCellRange((XSSFSheet) sheet, new CellRangeAddress(2, 4, 1, 1));

    XDDFNumericalDataSource<Double> components = XDDFDataSourcesFactory.fromNumericCellRange((XSSFSheet) sheet, new CellRangeAddress(2, 4, 2, 2));

    XDDFChartData data = chart.createData(ChartTypes.BAR, bottomAxis, leftAxis);

    XDDFChartData.Series series = data.addSeries(compliances, components);
    series.setTitle("Components by Compliance", null);

    chart.plot(data);

    XDDFBarChartData bar = (XDDFBarChartData) data;
    bar.setBarDirection(BarDirection.BAR);


    // do not auto delete the title; is necessary for showing title in Calc
    if (chart.getCTChart().getAutoTitleDeleted() == null) chart.getCTChart().addNewAutoTitleDeleted();
    chart.getCTChart().getAutoTitleDeleted().setVal(false);

    // data point colors; is necessary for showing data points in Calc
    // some rgb colors to choose
    byte[][] colors = new byte[][] {
      new byte[] {127,(byte)255, 127},
      new byte[] {(byte)200, (byte)200, (byte)200},
      new byte[] {(byte)255,(byte)255, 127},
      new byte[] {(byte)255, 127, 127},
      new byte[] {(byte)255, 0, 0},
      new byte[] {0, (byte)255, 0},
      new byte[] {0, 0, (byte)255},
      new byte[] {80, 80, 80}
    };
    // set data point colors
    int pointCount = series.getCategoryData().getPointCount();
    for (int p = 0; p < pointCount; p++) {
      chart.getCTChart().getPlotArea().getBarChartArray(0).getSerArray(0).addNewDPt().addNewIdx().setVal(p);
      chart.getCTChart().getPlotArea().getBarChartArray(0).getSerArray(0).getDPtArray(p)
        .addNewSpPr().addNewSolidFill().addNewSrgbClr().setVal(colors[p]);
    }
    // write the output to a file
    try (FileOutputStream fileOut = new FileOutputStream("ooxml-bar-chart.xlsx")) {
      workbook.write(fileOut);
    }
    workbook.close();
  }
}

【讨论】:

  • 嗯,我的 IDE 找不到 CTDLbls。有不同的依赖吗?我在 5.0.0 版本中使用 org.apache.poi/poi 和 org.apache.poi/poi-ooxml。
  • 这很有效,比多系列方法更可取。非常感谢!
猜你喜欢
  • 2017-08-10
  • 1970-01-01
  • 2015-09-27
  • 2012-12-25
  • 2021-06-23
  • 2020-09-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多