简体   繁体   中英

For Apache poi line chart, how to make first column doesn't display on y-axis

I use poi version is 4.1.1. Now I want to make first column doesn't display on y-axis, means I want to add some space between y-axis and the first column. I notice there is an option "Axis position" on x-axis, when it set to "Between tick marks", it will work as I want. But I don't know how to make it using apache-poi. Is it possible to make it?

here is the "Asis position in excel"

now the line chart looks like

what I want

Thanks everyone!!!

Here is the code example from Apache website:

public class LineChart {

    public static void main(String[] args) throws IOException {
        try (XSSFWorkbook wb = new XSSFWorkbook()) {
            XSSFSheet sheet = wb.createSheet("linechart");
            final int NUM_OF_ROWS = 3;
            final int NUM_OF_COLUMNS = 10;

            // Create a row and put some cells in it. Rows are 0 based.
            Row row;
            Cell cell;
            for (int rowIndex = 0; rowIndex < NUM_OF_ROWS; rowIndex++) {
                row = sheet.createRow((short) rowIndex);
                for (int colIndex = 0; colIndex < NUM_OF_COLUMNS; colIndex++) {
                    cell = row.createCell((short) colIndex);
                    cell.setCellValue(colIndex * (rowIndex + 1.0));
                }
            }

            XSSFDrawing drawing = sheet.createDrawingPatriarch();
            XSSFClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 0, 5, 10, 15);

            XSSFChart chart = drawing.createChart(anchor);
            XDDFChartLegend legend = chart.getOrAddLegend();
            legend.setPosition(LegendPosition.BOTTOM);

            // Use a category axis for the bottom axis.
            XDDFCategoryAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
            //bottomAxis.setTitle("x"); // https://stackoverflow.com/questions/32010765
            XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT);
            //leftAxis.setTitle("f(x)");
            leftAxis.setCrosses(AxisCrosses.AUTO_ZERO);


            XDDFDataSource<Double> xs = XDDFDataSourcesFactory.fromNumericCellRange(sheet, new CellRangeAddress(0, 0, 0, NUM_OF_COLUMNS - 1));
            XDDFNumericalDataSource<Double> ys1 = XDDFDataSourcesFactory.fromNumericCellRange(sheet, new CellRangeAddress(1, 1, 0, NUM_OF_COLUMNS - 1));
            XDDFNumericalDataSource<Double> ys2 = XDDFDataSourcesFactory.fromNumericCellRange(sheet, new CellRangeAddress(2, 2, 0, NUM_OF_COLUMNS - 1));

            XDDFLineChartData data = (XDDFLineChartData) chart.createData(ChartTypes.LINE, bottomAxis, leftAxis);
            XDDFLineChartData.Series series1 = (XDDFLineChartData.Series) data.addSeries(xs, ys1);
            series1.setTitle("a", null); // https://stackoverflow.com/questions/21855842
            //series1.setSmooth(false); // https://stackoverflow.com/questions/29014848
            series1.setMarkerStyle(MarkerStyle.NONE); // https://stackoverflow.com/questions/39636138
            XDDFLineChartData.Series series2 = (XDDFLineChartData.Series) data.addSeries(xs, ys2);
            series2.setTitle("b", null);
            //series2.setSmooth(true);
            //series2.setMarkerSize((short) 6);
            series2.setMarkerStyle(MarkerStyle.NONE); // https://stackoverflow.com/questions/39636138

            CTBoolean ctBoolean = CTBoolean.Factory.newInstance();
            ctBoolean.setVal(false);
            CTPlotArea plotArea = chart.getCTChart().getPlotArea();
            chart.getCTChartSpace().setRoundedCorners(ctBoolean);
            for (CTLineSer ser : plotArea.getLineChartArray()[0].getSerArray()) {
                CTDLbls ctdLbls = ser.addNewDLbls();

                ctdLbls.setShowSerName(ctBoolean);
                ctdLbls.setShowLegendKey(ctBoolean);
                ctdLbls.setShowLeaderLines(ctBoolean);
                ctdLbls.setShowCatName(ctBoolean);
                CTDLblPos ctdLblPos = CTDLblPos.Factory.newInstance();
                ctdLblPos.setVal(STDLblPos.CTR);
                CTDLblPos.Factory.newInstance();
                ctdLbls.setDLblPos(ctdLblPos);
            }

            chart.plot(data);

            // if your series have missing values like https://stackoverflow.com/questions/29014848
            // chart.displayBlanksAs(DisplayBlanks.GAP);

            // https://stackoverflow.com/questions/24676460
            solidLineSeries(data, 0, PresetColor.LIGHT_GREEN);
            solidLineSeries(data, 1, PresetColor.DARK_RED);

            // Write the output to a file
            try (FileOutputStream fileOut = new FileOutputStream("ooxml-line-chart.xlsx")) {
                wb.write(fileOut);
            }
        }
    }
    //CTPresetLineDashProperties
    private static void solidLineSeries(XDDFChartData data, int index, PresetColor color) {
        XDDFSolidFillProperties fill = new XDDFSolidFillProperties(XDDFColor.from(color));
        XDDFLineProperties line = new XDDFLineProperties();
        if (index == 0) {
            line.setPresetDash(new XDDFPresetLineDash(PresetLineDash.DOT));
        }
        line.setFillProperties(fill);
        XDDFChartData.Series series = data.getSeries().get(index);
        XDDFShapeProperties properties = series.getShapeProperties();
        if (properties == null) {
            properties = new XDDFShapeProperties();
        }
        properties.setLineProperties(line);
        series.setShapeProperties(properties);
    }
}

Per default the value axis and the category axis crosses exactly on category point. So if value axis crosses category axis at point 0, then it looks like your result now.

But if x axis is a category axis, then there is a setting XDDFValueAxis.setCrossBetween . If that is set to AxisCrossBetween.BETWEEN then the value axis crosses the category axis between the category points. This looks as you want.

So in your case:

...
            // Use a category axis for the bottom axis.
            XDDFCategoryAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
            //bottomAxis.setTitle("x"); // https://stackoverflow.com/questions/32010765
            XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT);
            //leftAxis.setTitle("f(x)");
            leftAxis.setCrosses(AxisCrosses.AUTO_ZERO);

            leftAxis.setCrossBetween(AxisCrossBetween.BETWEEN);
...

Btw.: You should get rid of deprecated methods.

For example the get...Array() methods of ooxml-schemas are deprecated. Either you get a concrete item from the array using get...Array(item) or you get a List using get...List() .

In your case:

...
            //for (CTLineSer ser : plotArea.getLineChartArray()[0].getSerArray()) {
            for (CTLineSer ser : plotArea.getLineChartArray(0).getSerList()) {
...

And also XDDFChartData.getSeries() is deprecated. If you need one series do using XDDFChartData.getSeries(index)

In your case:

...
        //XDDFChartData.Series series = data.getSeries().get(index);
        XDDFChartData.Series series = data.getSeries(index);
...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM