POI制作折线图表setMajorUnit不生效问题

我用poi生成图表,想把刻度标记间隔调大一点

img

设置bottomAxis.setMajorUnit(10),但是不生效,点开源码看

img

点开源码看,源码直接就nothing

img

我需要通过什么才可以调整刻度标记间隔呢?下面是完整的代码


package echarts.echarts;

import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Calendar;
import java.util.Date;
import java.util.Random;

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.chart.AxisPosition;
import org.apache.poi.xddf.usermodel.chart.AxisTickLabelPosition;
import org.apache.poi.xddf.usermodel.chart.AxisTickMark;
import org.apache.poi.xddf.usermodel.chart.ChartTypes;
import org.apache.poi.xddf.usermodel.chart.LegendPosition;
import org.apache.poi.xddf.usermodel.chart.MarkerStyle;
import org.apache.poi.xddf.usermodel.chart.XDDFCategoryAxis;
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.XDDFLineChartData;
import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource;
import org.apache.poi.xddf.usermodel.chart.XDDFValueAxis;
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;

import cn.hutool.core.date.DateUtil;

public class App2 {
    
    public static void main(String[] args) throws IOException {
        XSSFWorkbook wb = new XSSFWorkbook();
        FileOutputStream fileOut = null;
        try {
            
            
            
            // 轨迹点Sheet
            XSSFSheet sheet = wb.createSheet("轨迹点");
          
            Row row = sheet.createRow(0);
            Cell cell = row.createCell(0);
            cell.setCellValue("时间");
            cell = row.createCell(1);
            cell.setCellValue("温度");
            
            Date date = DateUtil.parse("2023-05-10 00:00:00");
            Calendar cal = Calendar.getInstance();
            cal.setTime(date);
            
            double wd = -20.1;
            for (int i = 1; i <= 5000; i++) {
                row = sheet.createRow(i);
                cell = row.createCell(0);
                cal.set(Calendar.SECOND, cal.get(Calendar.SECOND) + 30);
                cell.setCellValue( DateUtil.format(cal.getTime(), "yyyy-mm-dd HH:mm:ss"));
                cell = row.createCell(1);
//                cell.setCellValue(RD());
//                cell.setCellValue(wd);
                cell.setCellValue(Math.abs(wd));
                wd = wd + (0.0059 * Math.abs(RD()));
            }
            
            // 温度图表Sheet
            XSSFSheet sheet2 = wb.createSheet("温度图表");
            
            // 创建一个画布
            XSSFDrawing drawing = sheet2.createDrawingPatriarch();
            // 前四个默认0,[1,1]:从1列1行开始;[17,36]:到18列32行结束
            // 默认宽度(14-8)*12
            XSSFClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 1, 1, 18, 32);
            // 创建一个chart对象
            XSSFChart chart = drawing.createChart(anchor);
            // 标题
            chart.setTitleText("温度图表");
            // 标题覆盖
            chart.setTitleOverlay(false);
            
            // 图例位置
            XDDFChartLegend legend = chart.getOrAddLegend();
            legend.setPosition(LegendPosition.RIGHT);

            // 分类轴标(X轴),标题位置
            XDDFCategoryAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
            bottomAxis.setTickLabelPosition(AxisTickLabelPosition.LOW);
            bottomAxis.setMajorUnit(10);
            bottomAxis.setMajorTickMark(AxisTickMark.OUT);
            
            // 值(Y轴)轴,标题位置
            XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT);
//            leftAxis.setTitle("温度");

            // CellRangeAddress(起始行号,终止行号, 起始列号,终止列号)
            // 分类轴标(X轴)数据,单元格范围位置[0, 0]到[0, 6]
            XDDFDataSource<String> countries = XDDFDataSourcesFactory.fromStringCellRange(sheet, new CellRangeAddress(1, 5001, 0, 0));
            // 数据1,单元格范围位置[1, 0]到[1, 6]
            XDDFNumericalDataSource<Double> area = XDDFDataSourcesFactory.fromNumericCellRange(sheet, new CellRangeAddress(1, 5001, 1, 1));
//            // LINE:折线图,
            XDDFLineChartData data = (XDDFLineChartData) chart.createData(ChartTypes.LINE, bottomAxis, leftAxis);
            // 图表加载数据,折线1
            XDDFLineChartData.Series series1 = (XDDFLineChartData.Series) data.addSeries(countries, area);
            // 折线图例标题
//            CellReference cf = new CellReference();
            series1.setTitle("温度", null);
            // 直线
            series1.setSmooth(false);
            // 设置标记大小
//            series1.setMarkerSize((short) 0);
            // 设置标记样式,星星
            series1.setMarkerStyle(MarkerStyle.NONE);
            
            
//            // 绘制
            chart.plot(data);
 
            // 打印图表的xml
             System.out.println(chart.getCTChart());
 
            // 将输出写入excel文件
            String filename = "排行榜前七的国家.xlsx";
            fileOut = new FileOutputStream(filename);
            wb.write(fileOut);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            wb.close();
            if (fileOut != null) {
                fileOut.close();
            }
        }
 
    }
    
    
    
    //随机数产生机器
    static int min = -5;
    static int max = 10;

    static int RD() {
        Random random = new Random();
        int n = random.nextInt(10);
        if (Math.abs(min) > Math.abs(max)) {// 这里去了最大的绝对值最为正负数的范围,需要负数部分直产生负数的话可以分开做
            if (n == 1 || n == 3 || n == 5 || n == 7 || n == 9) {
                // 如果是13579进入负数生产机器
                String str = "-" + random.nextInt(Math.abs(min));// 加个负号
                int a = Integer.parseInt(str);// 把字符串str封装成实数a
                return a;
            } else {
                // 否则产生正数,也就是说02468产生正数
                int a = random.nextInt(Math.abs(min));
                return a;
            }
        } else {
            if (n == 1 || n == 3 || n == 5 || n == 7 || n == 9) {
                // 如果是13579进入负数生产机器
                String str = "-" + random.nextInt(Math.abs(min));// 加个负号
                int a = Integer.parseInt(str);// 把字符串str封装成实数a
                return a;
            } else {
                // 否则产生正数,也就是说02468产生正数
                int a = random.nextInt(Math.abs(min));
                return a;
            }
        }
    }

}


XDDFCategoryAxis 这个不支持设置刻度标记间隔,你可能得用XDDFValueAxis 这个类

要调整X轴刻度标记间隔,可以使用XDDFCategoryAxis类的setMajorUnit()方法。这个方法的参数是一个double类型的值,表示刻度标记之间的距离。例如,如果想让刻度标记之间的距离为10,则可以调用setMajorUnit(10)。

在您的代码中,可以在以下行添加调用setMajorUnit()方法的代码,以调整X轴刻度标记间隔:

Copy
XDDFCategoryAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
bottomAxis.setTickLabelPosition(AxisTickLabelPosition.LOW);
bottomAxis.setMajorUnit(10); // 设置刻度标记间隔为10
bottomAxis.setMajorTickMark(AxisTickMark.OUT);
这样,X轴上的刻度标记将以10个时间单位为间隔显示。您可以根据需要调整这个值。

可以借鉴下

//字体样式  宋体  加粗  11
HSSFFont font = workbook.createFont();
font.setBold(true);
font.setFontHeightInPoints((short)11);
font.setFontName("宋体");

//创建表格样式 文字居中,四边边框
HSSFCellStyle style=workbook.createCellStyle();
style.setFont(font);
style.setWrapText(true);
style.setAlignment(HorizontalAlignment.CENTER);
style.setVerticalAlignment(VerticalAlignment.CENTER);
style.setBorderBottom(BorderStyle.THIN); //下边框
style.setBorderLeft(BorderStyle.THIN);//左边框
style.setBorderTop(BorderStyle.THIN);//上边框
style.setBorderRight(BorderStyle.THIN);//右边框
//设置背景色的时候需要先设置填充样式,在设置颜色(个人理解)
//设置前景填充样式
style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
//前景填充色
style.setFillForegroundColor(IndexedColors.SKY_BLUE.getIndex());


基于GPT4和Treabhar的编写:

  • 根据描述和代码,用Apache POI库来在Excel中创建图表,并且希望调整图表的刻度标记间隔。然而,你发现bottomAxis.setMajorUnit(10)这个方法并没有生效。这可能是因为POI库并不完全支持所有Excel的功能,特别是一些高级的图表功能。
  • 在你的代码中,你是在用XSSF类来创建一个折线图,但是在Apache POI的XSSF实现中,并没有提供一个直接设置刻度标记间隔的方法。bottomAxis.setMajorUnit(10)这个方法在POI的源代码中是空的,也就是说它实际上并没有做任何事情。
  • 如果你要更精细地控制Excel中的图表,可能要寻找一些其他的解决方案。以下是一些可能的选项:
  1. 用更底层的XML API来直接修改底层的OpenXML格式。这需要对OpenXML格式有深入的理解,但是它可以让你访问到Excel的所有功能。你可以在POI的官方文档中找到更多关于这个选项的信息。
  2. 用VBA宏来创建和修改图表。你可以在Excel中录制一个宏,然后查看生成的VBA代码来了解如何编程地操作图表。然后,你可以使用POI来将这个宏嵌入到你的Excel文件中。
  3. 寻找一个更强大的库,比如Aspose.Cells。这个库是商业的,但是它提供了比POI更全面的Excel功能支持。
  • 这些选项都有一些优缺点,你需要根据你的具体需求来选择最适合你的解决方案。

引用ChatGPT部分内容作参考:
您好,根据您提供的代码,可以通过设置XDDFCategoryAxis的setMajorUnit方法来调整刻度标记间隔。在您的代码中,已经有以下代码:

// 分类轴标(X轴),标题位置
XDDFCategoryAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
bottomAxis.setTickLabelPosition(AxisTickLabelPosition.LOW);
bottomAxis.setMajorUnit(10);
bottomAxis.setMajorTickMark(AxisTickMark.OUT);

其中,setMajorUnit方法可以设置刻度标记的间隔,这里设置为10。如果想要调整间隔,只需要修改这个值即可。另外,如果刻度标记过于密集,可以考虑使用setTickLabelSkip方法来跳过一些刻度标记的显示,例如:

bottomAxis.setTickLabelSkip(10);

这样可以每隔10个刻度标记显示一个

以下答案由GPT-3.5大模型与博主波罗歌共同编写:
根据代码,你创建了一个XDDFCategoryAxis作为X轴,但是在设置标记间隔时,你使用的是setMajorUnit方法,这个方法是设置每个主刻度标记之间的类别宽度,而不是设置刻度标记之间的间隔。

要设置刻度标记间隔,可以使用setTickUnit方法,例如:bottomAxis.setTickUnit(10);就可以将刻度标记的间隔设置为10。

以下是更正后的代码:

import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Calendar;
import java.util.Date;
import java.util.Random;

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.chart.AxisPosition;
import org.apache.poi.xddf.usermodel.chart.AxisTickLabelPosition;
import org.apache.poi.xddf.usermodel.chart.AxisTickMark;
import org.apache.poi.xddf.usermodel.chart.ChartTypes;
import org.apache.poi.xddf.usermodel.chart.LegendPosition;
import org.apache.poi.xddf.usermodel.chart.MarkerStyle;
import org.apache.poi.xddf.usermodel.chart.XDDFCategoryAxis;
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.XDDFLineChartData;
import org.apache.poi.xddf.usermodel.chart.XDDFNumericalDataSource;
import org.apache.poi.xddf.usermodel.chart.XDDFValueAxis;
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;

import cn.hutool.core.date.DateUtil;

public class App2 {

public static void main(String[] args) throws IOException {
    XSSFWorkbook wb = new XSSFWorkbook();
    FileOutputStream fileOut = null;
    try {
        // 轨迹点Sheet
        XSSFSheet sheet = wb.createSheet("轨迹点");
      
        Row row = sheet.createRow(0);
        Cell cell = row.createCell(0);
        cell.setCellValue("时间");
        cell = row.createCell(1);
        cell.setCellValue("温度");
        
        Date date = DateUtil.parse("2023-05-10 00:00:00");
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        
        double wd = -20.1;
        for (int i = 1; i <= 5000; i++) {
            row = sheet.createRow(i);
            cell = row.createCell(0);
            cal.set(Calendar.SECOND, cal.get(Calendar.SECOND) + 30);
            cell.setCellValue(DateUtil.format(cal.getTime(), "yyyy-mm-dd HH:mm:ss"));
            cell = row.createCell(1);
            cell.setCellValue(Math.abs(wd));
            wd = wd + (0.0059 * Math.abs(RD()));
        }
        
        // 温度图表Sheet
        XSSFSheet sheet2 = wb.createSheet("温度图表");
        
        // 创建一个画布
        XSSFDrawing drawing = sheet2.createDrawingPatriarch();
        // 前四个默认0,[1,1]:从1列1行开始;[17,36]:到18列32行结束
        // 默认宽度(14-8)*12
        XSSFClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 1, 1, 18, 32);
        // 创建一个chart对象
        XSSFChart chart = drawing.createChart(anchor);
        // 标题
        chart.setTitleText("温度图表");
        // 标题覆盖
        chart.setTitleOverlay(false);
        
        // 图例位置
        XDDFChartLegend legend = chart.getOrAddLegend();
        legend.setPosition(LegendPosition.RIGHT);

        // 分类轴标(X轴),标题位置
        XDDFCategoryAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
        bottomAxis.setTickLabelPosition(AxisTickLabelPosition.LOW);
        bottomAxis.setTickUnit(10);
        bottomAxis.setMajorTickMark(AxisTickMark.OUT);
        
        // 值(Y轴)轴,标题位置
        XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT);

        // CellRangeAddress(起始行号,终止行号, 起始列号,终止列号)
        // 分类轴标(X轴)数据,单元格范围位置[0, 0]到[0, 6]
        XDDFDataSource<String> countries = XDDFDataSourcesFactory.fromStringCellRange(sheet, new CellRangeAddress(1, 5001, 0, 0));
        // 数据1,单元格范围位置[1, 0]到[1, 6]
        XDDFNumericalDataSource<Double> area = XDDFDataSourcesFactory.fromNumericCellRange(sheet, new CellRangeAddress(1, 5001, 1, 1));

        XDDFLineChartData data = (XDDFLineChartData) chart.createData(ChartTypes.LINE, bottomAxis, leftAxis);
        // 图表加载数据,折线1
        XDDFLineChartData.Series series1 = (XDDFLineChartData.Series) data.addSeries(countries, area);
        // 折线图例标题
        series1.setTitle("温度", null);
        // 直线
        series1.setSmooth(false);
        // 设置标记样式,星星
        series1.setMarkerStyle(MarkerStyle.NONE);
        
        // 绘制
        chart.plot(data);

        // 打印图表的xml
        System.out.println(chart.getCTChart());

        // 将输出写入excel文件
        String filename = "排行榜前七的国家.xlsx";
        fileOut = new FileOutputStream(filename);
        wb.write(fileOut);
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        wb.close();
        if (fileOut != null) {
            fileOut.close();
        }
    }
}

//随机数产生机器
static int min = -5;
static int max = 10;

static int RD() {
    Random random = new Random();
    int n = random.nextInt(10);
    if (Math.abs(min) > Math.abs(max)) {
        if (n == 1 || n == 3 || n == 5 || n == 7 || n == 9) {
            String str = "-" + random.nextInt(Math.abs(min));
            int a = Integer.parseInt(str);
            return a;
        } else {
            int a = random.nextInt(Math.abs(min));
            return a;
        }
    } else {
        if (n == 1 || n == 3 || n == 5 || n == 7 || n == 9) {
            String str = "-" + random.nextInt(Math.abs(min));
            int a = Integer.parseInt(str);
            return a;
        } else {
            int a = random.nextInt(Math.abs(min));
            return a;
        }
    }
}

}
如果我的回答解决了您的问题,请采纳!

以下答案由GPT-4.5Plus大模型(语音)与博主A努力中.......共同编写:

根据你的代码和描述,出现setMajorUnit()不生效的原因可能有以下几个:

  1. bottomAxis实际类型不为XDDFCategoryAxis。你的代码中bottomAxis的类型应为:

java
XDDFCategoryAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);

如果类型不匹配,setMajorUnit()方法将不生效。

  1. majorUnit值设置过大。如果将刻度间隔设置为原有刻度数的很大倍数,POI可能忽略这一设置,以免刻度间隔过大影响显示效果。

  2. bottomAxis的刻度已经固定。如果底轴刻度已经通过其他方式固定,则后续setMajorUnit()调用将不生效。

  3. 图表类型不支持刻度间隔调整。个别图表类型的底轴刻度间隔不可调整,setMajorUnit()设置将失效。

  4. POI版本问题。不同POI版本的图表实现细节可能不同,导致setMajorUnit()在某版本下不生效。

解决方法:

  1. 确认bottomAxis为XDDFCategoryAxis类型。
  2. 设置适当的majorUnit值,不要过大。
  3. 避免重复设置bottomAxis的刻度相关属性。
  4. 根据图表类型选择合适的轴设置方法。
  5. 升级POI版本到最新,确保方法调用在最新版本下有效。