使用 openpyxl 生成 excel 折线图

使用 openpyxl 生成 excel 折线图

需求:有一个问本文件,读取后转为 excel,并且同时生成折线图。

Python:3.11.5

openpyxl:3.1.5

在文本文件中的数据如下图:

读取文件并提取数据

py 复制代码
def extract_sum_data(file_path):
    headers = []  # 表格行头
    time_points = []  # 第一列
    xiao = []  # 第二列
    duan = []  # 第三列
    xu = []  # 第四列

    with open(file_path, 'r', encoding='utf8') as file:
        for line in file:
            if '姓名' in line:
                headers = [x for x in line.split('\t') if x]
            else:
                words = [x for x in line.split('\t') if x]
                time_points.append(words[0])
                xiao.append(float(words[1]))
                duan.append(float(words[2]))
                xu.append(float(words[3]))
    return headers, pd.DataFrame({
        'Time': time_points,
        'xiao': xiao,
        'duan': duan,
        'xu': xu
    })

导出到 Excel 并生成图表:

py 复制代码
def export_to_excel(header, df, output_file):
    # 写入 Excel
    df.to_excel(output_file, index=False, sheet_name='sheel1')

    # 使用 openpyxl 添加图表
    wb = Workbook()
    ws = wb.active
    ws.append(header)
    for row in df.itertuples():
        ws.append(row[1:])  # 跳过索引

    # 创建折线图
    chart = LineChart()
    chart.width = 30
    chart.height = 14
    chart.title = "kongfu"
    chart.x_axis.title = "Time"
    chart.y_axis.title = "Value"

    # 设置数据范围
    data = Reference(ws, min_col=2, min_row=1, max_col=4, max_row=len(df) + 1)
    categories = Reference(ws, min_col=1, min_row=2, max_row=len(df) + 1)

    chart.add_data(data, titles_from_data=True)
    chart.set_categories(categories)

    # 将图表插入工作表
    ws.add_chart(chart, "F2")
    wb.save(output_file)

依赖:

py 复制代码
import pandas as pd
from openpyxl import Workbook
from openpyxl.chart import LineChart, Reference

主流程:

py 复制代码
if __name__ == "__main__":
    input_file = "D:\workspace\\code\\test.txt"  # 文件路径
    output_file = f"z1.xlsx"

    header, df = extract_sum_data(input_file)
    export_to_excel(header, df, output_file)

结果:

WPS 如图:

Excel 如图:

可以看到 office 没有横纵坐标轴。

经过一番 AI 交流后,做以下修改:

py 复制代码
from openpyxl.chart.axis import ChartLines
from openpyxl.chart.shapes import GraphicalProperties
from openpyxl.drawing.line import LineProperties

# ...
chart.add_data(data, titles_from_data=True)
chart.set_categories(categories)
# ===== 新增代码:显示坐标轴 =====
# 1. X 轴设置
chart.x_axis.axisLine = ChartLines()  # 启用轴线
chart.x_axis.axisLine.spPr = GraphicalProperties(
    ln=LineProperties(solidFill="000000", w=0.75)
)
chart.x_axis.majorTickMark = "out"  # 刻度线朝外
chart.x_axis.tickLblPos = "low"     # 标签在轴下方
# 2. Y 轴设置
chart.y_axis.axisLine = ChartLines()
chart.y_axis.axisLine.spPr = GraphicalProperties(
    ln=LineProperties(solidFill="000000", w=0.75)
)
chart.y_axis.majorTickMark = "out"
# 3. 防止标签隐藏
chart.x_axis.delete = False  # 禁止 Excel 自动删除轴
chart.y_axis.delete = False
# ...

Excel 中效果如图:

但是,横纵坐标轴的标题与坐标轴的值重合了,再次与 AI 交流一番,并没有很好的解决,并且在此中发现,实际横纵坐标显示只与这两行有关,其他的代码只是与设置刻度线相关:

py 复制代码
chart.x_axis.delete = False  # 禁止 Excel 自动删除轴
chart.y_axis.delete = False

继续持续不断与 AI 交流,最终发现,需要设置的是绘图区与图表区的间隔,然后发现可以这样设置:

chart.layout = Layout(manualLayout=ManualLayout(x=0, y=-0.07, w=0.9, h=0.78))

layout 即代表绘图区,x、y 代表绘图区左边、上边开始位置,w、h 代表宽高,经过不断的尝试,在 WPS 和 Excel 中,绘图区都比较合适的位置参数即上述所列。

经过调整,导出函数修改如下:

py 复制代码
from openpyxl.chart.layout import Layout, ManualLayout

def export_to_excel(header, df, output_file):
    # 写入 Excel
    df.to_excel(output_file, index=False, sheet_name='sheel1')

    # 创建折线图
    wb = Workbook()
    ws = wb.active
    ws.append(header)
    for row in df.itertuples():
        ws.append(row[1:])

    # 创建折线图
    chart = LineChart()
    chart.width = 30
    chart.height = 14
    chart.title = "kongfu"
    chart.x_axis.title = "Time"
    chart.y_axis.title = "Value"

    # 图例位置
    chart.legend.position = 'tr'
    # 绘图区位置 x从左往右开始 y从上往下开始 w宽占比 h高占比
    chart.layout = Layout(manualLayout=ManualLayout(x=0, y=-0.07, w=0.9, h=0.78))

    data = Reference(ws, min_col=2, min_row=1, max_col=4, max_row=len(df) + 1)
    categories = Reference(ws, min_col=1, min_row=2, max_row=len(df) + 1)
    chart.add_data(data, titles_from_data=True)
    chart.set_categories(categories)

    # 设置坐标轴的刻度线
    chart.x_axis.axisLine = ChartLines()  # 启用轴线
    chart.x_axis.axisLine.spPr = GraphicalProperties(
        ln=LineProperties(solidFill="000000", w=0.25)
    )
    # 刻度线向外
    chart.x_axis.majorTickMark = "out"
    # 设置刻度线显示间隔
    chart.x_axis.tickMarkSkip = 60
    # 防止标签隐藏,真正显示坐标轴的值,禁止 Excel 自动删除轴
    chart.x_axis.delete = False
    chart.y_axis.delete = False

    ws.add_chart(chart, "F2")
    wb.save(output_file)

生成的 Excel 及折线图如下:

此时,由于需求变更,只有一列数据呢,即修改这里,只返回一个人数据:

py 复制代码
return headers, pd.DataFrame({
    'Time': time_points,
    'xiao': xiao,
    # 'duan': duan,
    # 'xu': xu
})

再将 data = Reference(ws, min_col=2, min_row=1, max_col=4, max_row=len(df) + 1) max_col 改为 2。

来看看结果:

WPS:

Excel:

WPS 依然没问题,Excel 竟然不一样了,线条是一条多彩的线。每一段对应一个时间点。

再次经过一番与 AI 交流,可能与 Excel 图表引擎的默认行为差异有关。

数据系列数量 Excel 默认行为 底层逻辑
单条数据线 自动分段多色显示 Excel 会尝试在单系列中启用「依数据点着色」功能(即使未手动开启),目的是通过颜色变化强调数据分段。这是 Excel 的「条件格式图表」遗留设计。
两条及以上数据线 每条线固定单色(红/蓝) Excel 切换为「多系列对比模式」,此时会禁用单系列内的颜色变化,转而用不同颜色区分系列。

经过各种参数尝试后,做如下修改:

py 复制代码
# ...
# 创建折线图
chart = LineChart()
chart.varyColors = False  # 禁止 office 的多色线条
chart.width = 30
chart.height = 14
# ...

再看结果,如图:

对于线的颜色做到了统一,可能还有些许瑕疵,比如在 Excel 中标题太小以及太靠上,底部空白太多,但是至少保持了 Excel 和 WPS 内容上的一致,算是比较成功了。

当然如果只需要其中一种格式,可以做出修改使其更符合某一种格式,也不乏还有其他方法可以实现。

这就是本文研究的内容,如何将文本数据转为折线图,并解决在 Excel 折线图缺少坐标值、以及折现图中单线条多颜色的问题。

相关推荐
努力也学不会java2 小时前
【Java并发】揭秘Lock体系 -- 深入理解ReentrantReadWriteLock
java·开发语言·python·机器学习
我的xiaodoujiao5 小时前
从 0 到 1 搭建 Python 语言 Web UI自动化测试学习系列 15--二次开发--封装公共方法 3
python·学习·测试工具
AI视觉网奇5 小时前
pyqt 触摸屏监听
开发语言·python·pyqt
香菜+5 小时前
python脚本加密之pyarmor
开发语言·python
Brian Xia5 小时前
# tchMaterial-parser 入门指南
python·ai
啃啃大瓜5 小时前
常用库函数
开发语言·python
楼田莉子6 小时前
python学习:爬虫+项目测试
后端·爬虫·python·学习
总有刁民想爱朕ha6 小时前
Python自动化从入门到实战(17)python flask框架 +Html+Css开发一个实用的在线奖状生成器
python·flask·自动化·在线奖状生成器
修炼室6 小时前
如何将Python脚本输出(含错误)全量保存到日志文件?实战指南
开发语言·python