使用 openpyxl 生成 excel 折线图
使用 openpyxl 生成 excel 折线图
需求:有一个问本文件,读取后转为 excel,并且同时生成折线图。
Python:3.11.5
openpyxl:3.1.5
在文本文件中的数据如下图:
读取文件并提取数据
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 并生成图表:
def export_to_excel(header, df, output_file):# 写入 Exceldf.to_excel(output_file, index=False, sheet_name='sheel1')# 使用 openpyxl 添加图表wb = Workbook()ws = wb.activews.append(header)for row in df.itertuples():ws.append(row[1:]) # 跳过索引# 创建折线图chart = LineChart()chart.width = 30chart.height = 14chart.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)
依赖:
import pandas as pd
from openpyxl import Workbook
from openpyxl.chart import LineChart, Reference
主流程:
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 交流后,做以下修改:
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 交流一番,并没有很好的解决,并且在此中发现,实际横纵坐标显示只与这两行有关,其他的代码只是与设置刻度线相关:
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 中,绘图区都比较合适的位置参数即上述所列。
经过调整,导出函数修改如下:
from openpyxl.chart.layout import Layout, ManualLayoutdef export_to_excel(header, df, output_file):# 写入 Exceldf.to_excel(output_file, index=False, sheet_name='sheel1')# 创建折线图wb = Workbook()ws = wb.activews.append(header)for row in df.itertuples():ws.append(row[1:])# 创建折线图chart = LineChart()chart.width = 30chart.height = 14chart.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 = Falsechart.y_axis.delete = Falsews.add_chart(chart, "F2")wb.save(output_file)
生成的 Excel 及折线图如下:
此时,由于需求变更,只有一列数据呢,即修改这里,只返回一个人数据:
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 切换为「多系列对比模式」,此时会禁用单系列内的颜色变化,转而用不同颜色区分系列。 |
经过各种参数尝试后,做如下修改:
# ...
# 创建折线图
chart = LineChart()
chart.varyColors = False # 禁止 office 的多色线条
chart.width = 30
chart.height = 14
# ...
再看结果,如图:
对于线的颜色做到了统一,可能还有些许瑕疵,比如在 Excel 中标题太小以及太靠上,底部空白太多,但是至少保持了 Excel 和 WPS 内容上的一致,算是比较成功了。
当然如果只需要其中一种格式,可以做出修改使其更符合某一种格式,也不乏还有其他方法可以实现。
这就是本文研究的内容,如何将文本数据转为折线图,并解决在 Excel 折线图缺少坐标值、以及折现图中单线条多颜色的问题。