4. Excel 文件处理:用 openpyxl 和 pandas 读写 Excel
Excel 在测绘数据处理中,说实话,是绕不过去的坎。外业数据汇总、内业成果提交、甲方要求报表……十有八九都是 Excel 格式。我见过太多同事还在手动复制粘贴,几百行数据改到凌晨。其实用 Python 处理 Excel,几分钟就能搞定。
这一章,我们就来啃下这块硬骨头。核心工具是两个库:pandas 负责快速读写和数据分析,openpyxl 负责精细的样式控制和格式调整。两者配合,基本能覆盖测绘数据导出 90% 的场景。
4.1 环境准备与库的安装
先装好这两个库。我个人习惯在虚拟环境里装,避免版本冲突。
pip install pandas openpyxl
pandas 默认的 Excel 引擎是 openpyxl(处理 .xlsx 文件)。如果你要处理老的 .xls 文件,还需要装 xlrd 和 xlwt。不过现在测绘项目基本都用 .xlsx 了,咱们就聚焦这个。
4.2 pandas 快速读写 Excel
pandas 读写 Excel 非常简洁。我经常用它来批量读取外业采集的表格,然后统一处理。
4.2.1 读取 Excel 文件
import pandas as pd
# 读取第一个工作表
df = pd.read_excel('外业数据.xlsx', sheet_name=0)
# 读取指定工作表
df = pd.read_excel('外业数据.xlsx', sheet_name='控制点成果')
# 读取多个工作表
dfs = pd.read_excel('外业数据.xlsx', sheet_name=['控制点成果', '水准路线'])
# 读取所有工作表
all_sheets = pd.read_excel('外业数据.xlsx', sheet_name=None)
避坑指南: 我曾经遇到过读取大文件时内存爆掉的情况。后来发现是文件里有很多空行和合并单元格。建议读取时加上 header=0 和 skiprows 参数,跳过无关行。
4.2.2 写入 Excel 文件
# 单个工作表写入
df.to_excel('成果输出.xlsx', sheet_name='平差结果', index=False)
# 多个工作表写入
with pd.ExcelWriter('成果输出.xlsx', engine='openpyxl') as writer:
df_control.to_excel(writer, sheet_name='控制点', index=False)
df_level.to_excel(writer, sheet_name='水准', index=False)
df_gps.to_excel(writer, sheet_name='GPS成果', index=False)
这里有个小技巧:index=False 一定要加上,否则 pandas 会把行索引也写进去,甲方看到那个莫名其妙的数字列,肯定会问你的。
4.3 openpyxl 精细操作
pandas 写出来的表格,样式是默认的,说白了就是白底黑字。但测绘成果报告通常要求有表头颜色、边框、字体对齐等。这时候就得 openpyxl 上场了。
4.3.1 加载工作簿与工作表
from openpyxl import load_workbook
from openpyxl.styles import Font, PatternFill, Alignment, Border, Side
# 加载已有的 Excel 文件
wb = load_workbook('成果输出.xlsx')
# 选择工作表
ws = wb['控制点']
# 或者创建新工作表
ws_new = wb.create_sheet('汇总表')
4.3.2 样式设置实战
嗯,这里要注意,openpyxl 的样式设置是逐单元格或逐范围操作的。我一般先定义好样式模板,然后批量应用。
# 定义样式
header_font = Font(name='微软雅黑', size=11, bold=True, color='FFFFFF')
header_fill = PatternFill(start_color='4472C4', end_color='4472C4', fill_type='solid')
header_alignment = Alignment(horizontal='center', vertical='center', wrap_text=True)
thin_border = Border(
left=Side(style='thin'),
right=Side(style='thin'),
top=Side(style='thin'),
bottom=Side(style='thin')
)
# 应用到表头区域(假设表头在第1行,A到F列)
for col in range(1, 7):
cell = ws.cell(row=1, column=col)
cell.font = header_font
cell.fill = header_fill
cell.alignment = header_alignment
cell.border = thin_border
# 应用到数据区域(第2行到第100行)
for row in range(2, 101):
for col in range(1, 7):
cell = ws.cell(row=row, column=col)
cell.border = thin_border
cell.alignment = Alignment(horizontal='center', vertical='center')
apply_header_style(ws, row, max_col) 函数,项目里到处都能调。
4.4 多工作表操作
测绘项目的数据结构通常比较复杂。一个测区可能有控制点、水准点、GPS点、导线点等多个表格。把它们放在同一个工作簿的不同工作表里,管理起来最方便。
| 工作表名称 | 内容说明 | 典型列 |
|---|---|---|
| 控制点成果 | 平面控制点坐标 | 点号、X、Y、H、等级 |
| 水准路线 | 水准观测数据 | 测段、起点、终点、高差、距离 |
| GPS基线 | 基线向量解算结果 | 起点、终点、DX、DY、DZ、精度 |
| 平差报告 | 平差结果汇总 | 点名、平差X、平差Y、中误差 |
4.4.1 工作表增删改查
# 获取所有工作表名称
sheet_names = wb.sheetnames
# 重命名工作表
ws.title = '控制点成果_v2'
# 复制工作表
ws_copy = wb.copy_worksheet(ws)
ws_copy.title = '控制点备份'
# 删除工作表
del wb['临时数据']
# 移动工作表顺序
wb.move_sheet('控制点成果', offset=-1) # 向前移动一位
避坑指南: 我曾经在复制工作表时,忘记复制样式。结果备份表里的数据全变成了默认格式。后来我改用 copy_worksheet 方法,它会连样式一起复制,省心多了。
4.5 条件格式:让数据自己“说话”
条件格式是 Excel 里非常实用的功能。在测绘数据检查中,我们经常需要标记超限的点、不合格的精度、异常的闭合差。手动去标?几百个点你得标到什么时候。用 openpyxl 的条件格式,一键搞定。
4.5.1 基本条件格式
from openpyxl.formatting.rule import CellIsRule, FormulaRule
# 标记中误差大于 0.05 的单元格为红色
red_fill = PatternFill(start_color='FFC7CE', end_color='FFC7CE', fill_type='solid')
red_font = Font(color='9C0006')
ws.conditional_formatting.add(
'E2:E101',
CellIsRule(
operator='greaterThan',
formula=['0.05'],
fill=red_fill,
font=red_font
)
)
# 标记闭合差超限(使用公式)
ws.conditional_formatting.add(
'F2:F101',
FormulaRule(
formula=['ABS(F2)>0.02'],
fill=PatternFill(start_color='FFC7CE', end_color='FFC7CE', fill_type='solid'),
font=Font(color='9C0006', bold=True)
)
)
4.5.2 数据条和色阶
除了标记异常,我还喜欢用数据条来直观展示精度分布。甲方一看就懂,不用你多解释。
from openpyxl.formatting.rule import DataBarRule
# 给中误差列添加数据条
rule = DataBarRule(
start_type='min',
end_type='max',
color='5B9BD5',
showValue=True,
minLength=None,
maxLength=None
)
ws.conditional_formatting.add('E2:E101', rule)
4.6 实战:生成一份完整的测绘成果报表
说了这么多,咱们来整合一下。假设我们要生成一份控制点成果报表,要求:
- 表头蓝色底白字,加粗
- 数据区域有边框,居中对齐
- 中误差超过 0.05 的单元格标红
- 每个测区一个工作表
import pandas as pd
from openpyxl import load_workbook
from openpyxl.styles import Font, PatternFill, Alignment, Border, Side
from openpyxl.formatting.rule import CellIsRule
# 1. 用 pandas 准备数据
data = {
'点号': ['GP01', 'GP02', 'GP03', 'GP04'],
'X': [3456789.12, 3456790.45, 3456788.78, 3456791.23],
'Y': [512345.67, 512347.89, 512344.56, 512348.90],
'H': [125.34, 126.78, 124.56, 127.01],
'中误差': [0.02, 0.06, 0.03, 0.08]
}
df = pd.DataFrame(data)
# 2. 写入 Excel
df.to_excel('控制点报表.xlsx', sheet_name='A区控制点', index=False)
# 3. 用 openpyxl 美化
wb = load_workbook('控制点报表.xlsx')
ws = wb['A区控制点']
# 定义样式
header_font = Font(name='微软雅黑', size=11, bold=True, color='FFFFFF')
header_fill = PatternFill(start_color='4472C4', end_color='4472C4', fill_type='solid')
center_align = Alignment(horizontal='center', vertical='center')
thin_border = Border(
left=Side(style='thin'), right=Side(style='thin'),
top=Side(style='thin'), bottom=Side(style='thin')
)
# 应用表头样式
for col in range(1, 6):
cell = ws.cell(row=1, column=col)
cell.font = header_font
cell.fill = header_fill
cell.alignment = center_align
cell.border = thin_border
# 应用数据区域样式
for row in range(2, len(df) + 2):
for col in range(1, 6):
cell = ws.cell(row=row, column=col)
cell.border = thin_border
cell.alignment = center_align
# 添加条件格式:中误差 > 0.05 标红
red_fill = PatternFill(start_color='FFC7CE', end_color='FFC7CE', fill_type='solid')
red_font = Font(color='9C0006', bold=True)
ws.conditional_formatting.add(
'E2:E101',
CellIsRule(operator='greaterThan', formula=['0.05'], fill=red_fill, font=red_font)
)
# 保存
wb.save('控制点报表.xlsx')
print('报表生成完成!')
4.7 本章知识体系
下面这张图,帮你理清 pandas 和 openpyxl 的分工与协作关系。
说白了,pandas 和 openpyxl 就像测绘外业和内业的关系。pandas 负责把外业数据“采”回来,openpyxl 负责把成果“绘”成漂亮的报告。两者缺一不可。
这一章的内容,足够你应对日常测绘数据导出 80% 的需求了。剩下的 20%,无非是遇到具体问题时,查查文档、搜搜案例。记住,多动手写代码,比看十遍教程都管用。