【问题标题】:Setting axis title and adding values to the bar设置轴标题并向栏添加值
【发布时间】:2022-07-30 14:11:14
【问题描述】:

我需要更改标题轴的属性(如字体大小)(红色圈出)

我正在使用 apache-poi 库,这是生成两个标题的代码部分

                XDDFCategoryAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
                bottomAxis.setTitle("Client Name");
                XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT);
                leftAxis.setTitle("Value ("+clientDataObjectRequest.getDataFormatCodeValue()+")");
                leftAxis.setCrosses(AxisCrosses.AUTO_ZERO);
                leftAxis.setCrossBetween(AxisCrossBetween.BETWEEN);

我已经尝试使用 getOrAddTextProperties().setFontSize() 方法,但这只会改变标签的大小(客户名称和数字),而不是标题本身。

在黄色中,我想添加值的精确数字。例如,“client 3”的值为 53,78,所以我需要将这个值放入图表中,就在 bar 结束之后(标记为黄色)。

【问题讨论】:

  • 查看XDDFValueAxis 的JavaDoc,它有很多很好的信息,您可以使用getOrAddTextProperties(),它返回一个XDDFRunProperties 对象,您可以在其上调用@987654331 之类的东西@ 或 setHighlight(...) 等等
  • @sorifiend 正如我所说, getOrAddTextProperties().setFontSize() 仅适用于标签。它不适用于轴标题(红色圆圈)。
  • 轴标题见stackoverflow.com/questions/68893190/…。添加数据标签见stackoverflow.com/…
  • @AxelRichter 我想我没有说清楚:我的意思是一种将值放在栏末尾的方法?我的意思是,在每个栏中,我想相应地放置值(数字)?

标签: java spring-boot apache-poi


【解决方案1】:

关于格式化坐标轴标题的问题已经得到解答。见Resizing legend and axis title in a apache poi bar chart

“要精确地添加值的数量”到数据条意味着设置数据标签。直到现在,这不是直接支持 ny Apache POI。所以使用低级别的org.openxmlformats.schemas.drawingml.x2006.chart.* 类是必要的。见https://stackoverflow.com/search?tab=newest&q=user%3a3915431%20add%20data%20labels。当然,这不是很舒服。所以我尝试为此创建一个方法void setDataLabels(XDDFChartData.Series series, int pos, boolean... show)

int pos 可以是以下之一:

INT_BEST_FIT   1 - positions data label at best fit to be readable
INT_B          2 - positions data label at bottom
INT_CTR        3 - positions data label at center
INT_IN_BASE    4 - positions data label inside at base
INT_IN_END     5 - positions data label inside at the end
INT_L          6 - positions data label at left
INT_OUT_END    7 - positions data label outside at the end
INT_R          8 - positions data label at right
INT_T          9 - positions data label at top

并非所有图表类型都支持所有仓位。

boolean... show 是一个布尔值列表,用于判断数据标签中哪些内容应可见 (true) 或不可见 (false)。顺序如下:

ShowVal, ShowLegendKey, ShowCatName, ShowSerName, ShowPercent, ShowBubbleSize, ShowLeaderLines

完整示例:

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

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xddf.usermodel.PresetColor;
import org.apache.poi.xddf.usermodel.XDDFColor;
import org.apache.poi.xddf.usermodel.XDDFShapeProperties;
import org.apache.poi.xddf.usermodel.XDDFSolidFillProperties;
import org.apache.poi.xddf.usermodel.chart.AxisCrosses;
import org.apache.poi.xddf.usermodel.chart.AxisCrossBetween;
import org.apache.poi.xddf.usermodel.chart.AxisPosition;
import org.apache.poi.xddf.usermodel.chart.BarDirection;
import org.apache.poi.xddf.usermodel.chart.ChartTypes;
import org.apache.poi.xddf.usermodel.chart.LegendPosition;
import org.apache.poi.xddf.usermodel.chart.XDDFBarChartData;
import org.apache.poi.xddf.usermodel.chart.XDDFLineChartData;
import org.apache.poi.xddf.usermodel.chart.XDDFPieChartData;
import org.apache.poi.xddf.usermodel.chart.XDDFCategoryAxis;
import org.apache.poi.xddf.usermodel.chart.XDDFChartData;
import org.apache.poi.xddf.usermodel.chart.XDDFChartLegend;
import org.apache.poi.xddf.usermodel.chart.XDDFDataSource;
import org.apache.poi.xddf.usermodel.chart.XDDFDataSourcesFactory;
import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource;
import org.apache.poi.xddf.usermodel.chart.XDDFValueAxis;
import org.apache.poi.xddf.usermodel.chart.XDDFTitle;
import org.apache.poi.xssf.usermodel.XSSFChart;
import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
import org.apache.poi.xssf.usermodel.XSSFDrawing;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

/**
 * Bar chart example.
 */
public final class BarChart {
    private BarChart() {}

    public static void main(String[] args) throws IOException {
        
        Object[][] chartData = new Object[][]{
            new Object[]{"Client 1", "Client 2", "Client 3", "Client 4", "Client 5", "Client 6", "Client 7", "Client 8"},    
            new Object[]{12, 2.345d, 34, 6, 45.6d, .456d, 50.5d, 12.345d},    
        };
        
        try (XSSFWorkbook wb = new XSSFWorkbook()) {
            XSSFSheet sheet = wb.createSheet("barchart");
            
            // put sheet data
            Row row;
            Cell cell;
            int rowIndex = 0;
            int colIndex = 0;
            for (Object[] dataRow : chartData) {
                row = sheet.createRow((short) rowIndex);
                colIndex = 0;
                for (Object value : dataRow) {
                    cell = row.createCell((short) colIndex);
                    if (value instanceof String) cell.setCellValue((String)value);
                    if (value instanceof Number) cell.setCellValue(((Number)value).doubleValue());
                    colIndex++;
                }
                rowIndex++;
            }
            
            // create the chart
            
            // chart data sources
            XDDFDataSource<String> xs = XDDFDataSourcesFactory.fromStringCellRange(sheet, new CellRangeAddress(0, 0, 0, colIndex - 1));
            XDDFNumericalDataSource<Double> ys1 = XDDFDataSourcesFactory.fromNumericCellRange(sheet, new CellRangeAddress(1, 1, 0, colIndex - 1));

            // chart in drawing
            XSSFDrawing drawing = sheet.createDrawingPatriarch();
            XSSFClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 0, 3, 8, 20);
            XSSFChart chart = drawing.createChart(anchor);
            chart.setTitleText("Turnover Rate");
            chart.setTitleOverlay(false);
            chart.getFormattedTitle().getParagraph(0).addDefaultRunProperties().setFontSize(20d);

            // category axis
            XDDFCategoryAxis catAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
            XDDFTitle title = getOrSetAxisTitle(catAxis);
            title.setOverlay(false);
            title.setText("Client Name");
            title.getBody().getParagraph(0).addDefaultRunProperties().setFontSize(12d);

            // value axis
            XDDFValueAxis valAxis = chart.createValueAxis(AxisPosition.LEFT);
            title = getOrSetAxisTitle(valAxis);
            title.setOverlay(false);
            title.setText("Value (Percentage)");
            title.getBody().getParagraph(0).addDefaultRunProperties().setFontSize(12d);
 
            // cross axes 
            valAxis.setCrosses(AxisCrosses.AUTO_ZERO);
            valAxis.setCrossBetween(AxisCrossBetween.BETWEEN);

            // chart data
            XDDFChartData data = chart.createData(ChartTypes.BAR, catAxis, valAxis);
            // series
            XDDFChartData.Series series1 = data.addSeries(xs, ys1);
            series1.setTitle("Series 1", null); // there must be a series title even if no legend is needed
            // add data labels
            setDataLabels(series1, 7, true); // pos 7 = INT_OUT_END, showVal = true
            
            // plot chart
            chart.plot(data);

            // in order to transform a bar chart into a column chart, you just need to change the bar direction
            XDDFBarChartData bar = (XDDFBarChartData) data;
            // bar.setBarDirection(BarDirection.COL);

            // set series fill color
            solidFillSeries(data, 0, PresetColor.BLUE);

            // Write the output to a file
            try (FileOutputStream fileOut = new FileOutputStream("./ooxml-bar-chart.xlsx")) {
                wb.write(fileOut);
            }
        }
    }

    private static void solidFillSeries(XDDFChartData data, int index, PresetColor color) {
        XDDFSolidFillProperties fill = new XDDFSolidFillProperties(XDDFColor.from(color));
        XDDFChartData.Series series = data.getSeries(index);
        XDDFShapeProperties properties = series.getShapeProperties();
        if (properties == null) {
            properties = new XDDFShapeProperties();
        }
        properties.setFillProperties(fill);
        series.setShapeProperties(properties);
    }
    
    private static XDDFTitle getOrSetAxisTitle(XDDFValueAxis axis) {
        try {
            java.lang.reflect.Field _ctValAx = XDDFValueAxis.class.getDeclaredField("ctValAx");
            _ctValAx.setAccessible(true);
            org.openxmlformats.schemas.drawingml.x2006.chart.CTValAx ctValAx =
                (org.openxmlformats.schemas.drawingml.x2006.chart.CTValAx)_ctValAx.get(axis);
            if (!ctValAx.isSetTitle()) {
                ctValAx.addNewTitle();
            }
            XDDFTitle title = new XDDFTitle(null, ctValAx.getTitle());
            return title;
        } catch (Exception ex) {
            ex.printStackTrace();
            return null;            
        }
    }

    private static XDDFTitle getOrSetAxisTitle(XDDFCategoryAxis axis) {
        try {
            java.lang.reflect.Field _ctCatAx = XDDFCategoryAxis.class.getDeclaredField("ctCatAx");
            _ctCatAx.setAccessible(true);
            org.openxmlformats.schemas.drawingml.x2006.chart.CTCatAx ctCatAx =
                (org.openxmlformats.schemas.drawingml.x2006.chart.CTCatAx)_ctCatAx.get(axis);
            if (!ctCatAx.isSetTitle()) {
                ctCatAx.addNewTitle();
            }
            XDDFTitle title = new XDDFTitle(null, ctCatAx.getTitle());
            return title;
        } catch (Exception ex) {
            ex.printStackTrace();
            return null;            
        }
    }
    
    private static void setDataLabels(XDDFChartData.Series series, int pos, boolean... show) {
        /*
        INT_BEST_FIT   1
        INT_B          2
        INT_CTR        3
        INT_IN_BASE    4
        INT_IN_END     5
        INT_L          6
        INT_OUT_END    7
        INT_R          8
        INT_T          9                             
        */
        try {
            org.openxmlformats.schemas.drawingml.x2006.chart.CTDLbls ctDLbls = null;
            if (series instanceof XDDFBarChartData.Series) {
                java.lang.reflect.Field _ctBarSer = XDDFBarChartData.Series.class.getDeclaredField("series");
                _ctBarSer.setAccessible(true);
                org.openxmlformats.schemas.drawingml.x2006.chart.CTBarSer ctBarSer =
                    (org.openxmlformats.schemas.drawingml.x2006.chart.CTBarSer)_ctBarSer.get((XDDFBarChartData.Series)series);
                if (ctBarSer.isSetDLbls()) ctBarSer.unsetDLbls();
                ctDLbls = ctBarSer.addNewDLbls();                                                        
                if (!(pos == 3 || pos == 4 || pos == 5 || pos == 7)) pos = 3; // bar chart does not provide other pos
                ctDLbls.addNewDLblPos().setVal(org.openxmlformats.schemas.drawingml.x2006.chart.STDLblPos.Enum.forInt(pos));
            } else if (series instanceof XDDFLineChartData.Series) {
                java.lang.reflect.Field _ctLineSer = XDDFLineChartData.Series.class.getDeclaredField("series");
                _ctLineSer.setAccessible(true);
                org.openxmlformats.schemas.drawingml.x2006.chart.CTLineSer ctLineSer =
                    (org.openxmlformats.schemas.drawingml.x2006.chart.CTLineSer)_ctLineSer.get((XDDFLineChartData.Series)series);
                if (ctLineSer.isSetDLbls()) ctLineSer.unsetDLbls();
                ctDLbls = ctLineSer.addNewDLbls();                                                      
                if (!(pos == 3 || pos == 6 || pos == 8 || pos == 9 || pos == 2)) pos = 3; // line chart does not provide other pos
                ctDLbls.addNewDLblPos().setVal(org.openxmlformats.schemas.drawingml.x2006.chart.STDLblPos.Enum.forInt(pos));
            } else if (series instanceof XDDFPieChartData.Series) {
                java.lang.reflect.Field _ctPieSer = XDDFPieChartData.Series.class.getDeclaredField("series");
                _ctPieSer.setAccessible(true);
                org.openxmlformats.schemas.drawingml.x2006.chart.CTPieSer ctPieSer =
                    (org.openxmlformats.schemas.drawingml.x2006.chart.CTPieSer)_ctPieSer.get((XDDFPieChartData.Series)series);
                if (ctPieSer.isSetDLbls()) ctPieSer.unsetDLbls();
                ctDLbls = ctPieSer.addNewDLbls();                                                      
                if (!(pos == 3 || pos == 1 || pos == 4 || pos == 5)) pos = 3; // pie chart does not provide other pos
                ctDLbls.addNewDLblPos().setVal(org.openxmlformats.schemas.drawingml.x2006.chart.STDLblPos.Enum.forInt(pos));
            }// else if ...                                                          
                                                               
            if (ctDLbls != null) {
                ctDLbls.addNewShowVal().setVal((show.length>0)?show[0]:false);
                ctDLbls.addNewShowLegendKey().setVal((show.length>1)?show[1]:false);
                ctDLbls.addNewShowCatName().setVal((show.length>2)?show[2]:false);
                ctDLbls.addNewShowSerName().setVal((show.length>3)?show[3]:false);
                ctDLbls.addNewShowPercent().setVal((show.length>4)?show[4]:false);
                ctDLbls.addNewShowBubbleSize().setVal((show.length>5)?show[5]:false);
                ctDLbls.addNewShowLeaderLines().setVal((show.length>6)?show[8]:false);
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }                              
    }          
   
}

结果:

【讨论】:

    猜你喜欢
    • 2018-10-29
    • 2011-10-21
    • 1970-01-01
    • 2022-07-26
    • 2021-04-26
    • 1970-01-01
    • 2015-12-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多