首页 > 编程语言 >Java使用poi导出excel折线图--以三温层车辆运输单据温度为例(含如何更改各标题大小)

Java使用poi导出excel折线图--以三温层车辆运输单据温度为例(含如何更改各标题大小)

时间:2024-06-07 15:22:44浏览次数:32  
标签:rPr 字体大小 为例 -- chart 标题 fontSize new Java

maven依赖引入

<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi</artifactId>
			<version>4.1.2</version>
		</dependency>
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi-ooxml</artifactId>
			<version>4.1.2</version>
		</dependency>

代码示例

/**
 * @author alin
 * @date 2024-06-03
 */
public class ExportChart {
    public static void main(String[] args) throws Exception {
        testCreateChart();
    }

    /**
     * 创建折线图
     *
     * @throws Exception
     */
    public static void testCreateChart() throws Exception {
        try (XSSFWorkbook wb = new XSSFWorkbook()) {
            String sheetName = "温度折线图";
            XSSFSheet sheet = wb.createSheet(sheetName);
            XSSFDrawing drawing = sheet.createDrawingPatriarch();
            // TODO 样式可以根据数据长度自行调整
            XSSFClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 2, 4, 30, 50);
            XSSFChart chart = drawing.createChart(anchor);
            // 折线图标题
            chart.setTitleText("单据: ****运输过程温度数据 车牌:豫P12345");
            // 标题是否覆盖图表
            chart.setTitleOverlay(false);
            // 设置图表标题字体大小
            setChartTitleFontSize(chart, 16);
            XDDFChartLegend legend = chart.getOrAddLegend();
            // 图例位置:上下左右
            legend.setPosition(LegendPosition.TOP_RIGHT);
            // 创建x轴
            XDDFCategoryAxis xAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
            // X轴标题
            xAxis.setTitle("采集时间");
            // 设置X轴标题字体大小
            setAxisTitleFontSize(xAxis, 16);

            // 左侧标题, Y轴
            XDDFValueAxis yAxis = chart.createValueAxis(AxisPosition.TOP);
            yAxis.setTitle("温度");
            // 刻度
            yAxis.setMajorUnit(5);
            // 设置Y轴标题字体大小
            setAxisTitleFontSize(yAxis, 16);

            // 获取mock数据
            List<TemperatureModel> list = getResult();
            // x轴标题数据
            List<String> xTitleData = new ArrayList<>(list.size());
            // y轴数据
            List<Double> yData1 = new ArrayList<>(list.size());
            List<Double> yData2 = new ArrayList<>(list.size());
            List<Double> yData3 = new ArrayList<>(list.size());
            for (TemperatureModel layer : list) {
                xTitleData.add(layer.getGatherTime());
                yData1.add(layer.getTemperature() == null ? 0D : layer.getTemperature());
                yData2.add(layer.getTemperature2() == null ? 0D : layer.getTemperature2());
                yData3.add(layer.getTemperature3() == null ? 0D : layer.getTemperature3());
            }

            // 数据源
            XDDFDataSource<String> date = XDDFDataSourcesFactory.fromArray(xTitleData.toArray(new String[0]));
            XDDFNumericalDataSource<Double> one = XDDFDataSourcesFactory.fromArray(yData1.toArray(new Double[0]));
            XDDFNumericalDataSource<Double> two = XDDFDataSourcesFactory.fromArray(yData2.toArray(new Double[0]));
            XDDFNumericalDataSource<Double> three = XDDFDataSourcesFactory.fromArray(yData3.toArray(new Double[0]));

            // 创建折线图
            XDDFLineChartData data = (XDDFLineChartData) chart.createData(ChartTypes.LINE, xAxis, yAxis);

            // 折线1
            XDDFLineChartData.Series series1 = (XDDFLineChartData.Series) data.addSeries(date, one);
            // 折线标题
            series1.setTitle("温度1(℃)", null);
            // 折线是否平滑
            series1.setSmooth(true);
            // 折线节点样式
            series1.setMarkerStyle(MarkerStyle.CIRCLE);

            // 折线2
            XDDFLineChartData.Series series2 = (XDDFLineChartData.Series) data.addSeries(date, two);
            series2.setTitle("温度2(℃)", null);
            series2.setSmooth(true);
            series2.setMarkerStyle(MarkerStyle.CIRCLE);
            chart.plot(data);

            // 折线3
            XDDFLineChartData.Series series3 = (XDDFLineChartData.Series) data.addSeries(date, three);
            series3.setTitle("温度3(℃)", null);
            series3.setSmooth(true);
            series3.setMarkerStyle(MarkerStyle.CIRCLE);
            chart.plot(data);

            // 输出文件到指定路径
            try (FileOutputStream fileOut = new FileOutputStream("d:/豫P12345运输温度折线图.xlsx")) {
                wb.write(fileOut);
                wb.close();
            }
        }
    }

    /**
     * 模拟数据
     *
     * @return
     */
    public static List<TemperatureModel> getResult() {
        List<TemperatureModel> list = new ArrayList<>();
        for (int i = 0; i < 30; i++) {
            ExportChart.TemperatureModel temperatureModel = new ExportChart.TemperatureModel();
            temperatureModel.setGatherTime("2024-06-03 10:" + String.format("%02d", i * 2) + ":00");
            temperatureModel.setTemperature(i % 2 == 0 ? -RandomUtils.nextDouble(0, 30) : RandomUtils.nextDouble(0, 30));
            temperatureModel.setTemperature2(RandomUtils.nextDouble(0, 30));
            temperatureModel.setTemperature3(i % 2 == 0 ? -RandomUtils.nextDouble(0, 30) : RandomUtils.nextDouble(0, 30));
            list.add(temperatureModel);
        }
        return list;
    }


    /**
     * 设置图表标题字体大小
     * 无法直接设置图表标题字体大小, 可以使用底层的XML对象来实现
     *
     * @param chart
     * @param fontSize
     */
    private static void setChartTitleFontSize(XSSFChart chart, double fontSize) {
        CTChart ctChart = chart.getCTChart();
        if (ctChart.isSetTitle()) {
            CTTitle title = ctChart.getTitle();
            if (title.isSetTx()) {
                CTTextBody rich = title.getTx().getRich();
                CTTextParagraph para = rich.getPArray(0);
                CTTextCharacterProperties rPr = para.getRArray(0).getRPr();
                // 字号大小 fontSize * 100 = fontSize pt
                rPr.setSz((int) (fontSize * 100));
                //rPr.setB(true); // 加粗
                //rPr.setI(true); // 斜体
            }
        }
    }

    /**
     * 设置X轴标题字体大小
     * 无法直接设置X轴标题字体大小, 可以通过反射获取到CTCatAx对象, 然后设置字体大小
     *
     * @param axis
     * @param fontSize
     */
    private static void setAxisTitleFontSize(XDDFCategoryAxis axis, double fontSize) {
        try {
            Field ctCatAx1 = XDDFCategoryAxis.class.getDeclaredField("ctCatAx");
            ctCatAx1.setAccessible(true);
            CTCatAx ctCatAx = (CTCatAx) ctCatAx1.get(axis);
            if (ctCatAx.isSetTitle()) {
                CTTitle title = ctCatAx.getTitle();
                if (title.isSetTx()) {
                    CTTextBody rich = title.getTx().getRich();
                    if (rich != null && rich.sizeOfPArray() > 0) {
                        CTTextParagraph para = rich.getPArray(0);
                        if (para.sizeOfRArray() > 0) {
                            CTTextCharacterProperties rPr = para.getRArray(0).getRPr();
                            if (rPr == null) {
                                rPr = para.getRArray(0).addNewRPr();
                            }
                            rPr.setSz((int) (fontSize * 100));
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 设置Y轴标题字体大小
     * 无法直接设置Y轴标题字体大小, 可以通过反射获取到CTValAx对象, 然后设置字体大小
     *
     * @param axis
     * @param fontSize
     */
    private static void setAxisTitleFontSize(XDDFValueAxis axis, double fontSize) {
        try {
            Field ctValAx1 = XDDFValueAxis.class.getDeclaredField("ctValAx");
            ctValAx1.setAccessible(true);
            CTValAx ctValAx = (CTValAx) ctValAx1.get(axis);
            if (ctValAx.isSetTitle()) {
                CTTitle title = ctValAx.getTitle();
                if (title.isSetTx()) {
                    CTTextBody rich = title.getTx().getRich();
                    if (rich != null && rich.sizeOfPArray() > 0) {
                        CTTextParagraph para = rich.getPArray(0);
                        if (para.sizeOfRArray() > 0) {
                            CTTextCharacterProperties rPr = para.getRArray(0).getRPr();
                            if (rPr == null) {
                                rPr = para.getRArray(0).addNewRPr();
                            }
                            rPr.setSz((int) (fontSize * 100));
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Data
    public static class TemperatureModel {

        /**
         * 采集时间
         */
        private String gatherTime;

        /**
         * 温度1
         */
        private Double temperature;

        /**
         * 温度2
         */
        private Double temperature2;

        /**
         * 温度3
         */
        private Double temperature3;

    }

}

导出效果图

标签:rPr,字体大小,为例,--,chart,标题,fontSize,new,Java
From: https://www.cnblogs.com/menghl/p/18237261

相关文章

  • GET 和 POST 的区别
    根据技术规格文档,GET和POST最大的区别是语义。区别一:幂等性(重复操作不改变结果)由于GET是读,POST是写,所以GET是幂等的,POST不是幂等的。由于GET是读,POST是写,所以用浏览器打开网页会发送GET请求,想要POST打开网页要用form标签。由于GET是读,POST是写,所以GE......
  • 再谈技术研究与技术开发的差异
    什么是技术研究?    技术研究不同于技术开发,研究型的项目更偏向于前沿技术和热点技术,主要包括下面四个方面的方向:1)技术创新:研究阶段主要是进行概念/框架研究、关键技术先期研究(包括理论分析、仿真、实验等)、或直接参与重要标准中的课题研究;2)通过专利保护所发明的技术......
  • 鸿蒙HarmonyOS实战-ArkTS语言基础类库(通知)
    ......
  • PyQT5之菜单栏和工具栏
    fromPyQt5importQtWidgetsfromPyQt5importQtCore,QtGuiimportsysimportcv2classButtonPanel(QtWidgets.QWidget):def__init__(self,*args,**kwargs):super().__init__(*args,**kwargs)select_btn=QtWidgets.QPushButton("图......
  • 从缺陷到创新:质量保障的新视角
    1.背景:最近一段时间研发大佬们在积极的治理告警,经过一段时间的治理,现在告警情况已经有了很大的改观,但难免还有漏网之鱼;具体我们可以以下边一个例子来看:这是一个生产的UMP告警,通过这个告警我们发现XXX这个应用的堆内存使用率为90.18%,超过了设置的告警阈值85%,所以产生了这样的......
  • 206. 反转链表
    packagemainimport"fmt"typeListNodestruct{ Valint Next*ListNode}funcreverseList(head*ListNode)*ListNode{ varpre*ListNode//前驱节点指针 cur:=head//当前节点指针 forcur!=nil{ next:=cur.Next//临时存储next指针 cur.N......
  • ClickHouse内幕(1)数据存储与过滤机制
    本文主要讲述ClickHouse中的数据存储结构,包括文件组织结构和索引结构,以及建立在其基础上的数据过滤机制,从Part裁剪到Mark裁剪,最后到基于SIMD的行过滤机制。数据过滤机制实质上是构建在数据存储格式之上的算法,所以在介绍过滤机制前先介绍下ClickHouse中数据存储格式。PS:本文基于C......
  • 【Socket】解决UDP丢包问题
    一、介绍UDP是一种不可靠的、无连接的、基于数据报的传输层协议。相比于TCP就比较简单,像写信一样,直接打包丢过去,就不用管了,而不用TCP这样的反复确认。所以UDP的优势就是速度快,开销小。但是随之而来的就是不稳定,面向无连接的,无法确认数据包。会导致丢包问题。二、丢包原因1、服......
  • MainWindows移动View文件夹和使用Window.DataContext单例绑定需要修改的地方
    项目结构移动文件夹后需要修改的三个地方1、App.xaml2、MainWindow.xaml3、MainWindow.xaml.cs单例绑定需要修改的地方MainWindow.xaml ......
  • ClickHouse内幕(2)基础数据结构
    ClickHouse以性能好被大家所熟知,而一个数据库的性能优化是一个庞大的系统性工程。本文着眼于ClickHouse内部的基础数据结构,以揭露ClickHouse性能优化的冰山一角。在软件工程中并不是所有的执行路径都需要优化,只有关键执行路径才需要花费大力气进行优化。对于数据库领域来说关键执......