4. Excel 文件处理:用 openpyxl 和 pandas 读写 Excel

Excel 在测绘数据处理中,说实话,是绕不过去的坎。外业数据汇总、内业成果提交、甲方要求报表……十有八九都是 Excel 格式。我见过太多同事还在手动复制粘贴,几百行数据改到凌晨。其实用 Python 处理 Excel,几分钟就能搞定。

这一章,我们就来啃下这块硬骨头。核心工具是两个库:pandas 负责快速读写和数据分析,openpyxl 负责精细的样式控制和格式调整。两者配合,基本能覆盖测绘数据导出 90% 的场景。

核心思路: pandas 做“搬运工”,openpyxl 做“装修工”。数据清洗、合并、计算用 pandas;设置单元格颜色、边框、字体、条件格式用 openpyxl。

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)
注意: openpyxl 的条件格式在 Excel 中打开是有效的,但在 WPS 或其他表格软件中可能显示异常。如果成果要提交给甲方,建议先确认对方用什么软件打开。

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('报表生成完成!')
避坑指南: 保存前最好先关闭 Excel 文件,否则 openpyxl 会报权限错误。我曾经因为这个 bug 排查了半天,最后发现是文件没关。

4.7 本章知识体系

下面这张图,帮你理清 pandas 和 openpyxl 的分工与协作关系。

Excel 文件处理知识体系 Excel 文件处理 pandas 快速读写 read_excel / to_excel 多工作表批量读写 ExcelWriter 写入 openpyxl 精细控制 样式设置(字体/填充/边框) 工作表增删改查 条件格式(数据条/色阶) 协作模式 pandas 负责数据搬运 → openpyxl 负责样式装修

说白了,pandas 和 openpyxl 就像测绘外业和内业的关系。pandas 负责把外业数据“采”回来,openpyxl 负责把成果“绘”成漂亮的报告。两者缺一不可。

这一章的内容,足够你应对日常测绘数据导出 80% 的需求了。剩下的 20%,无非是遇到具体问题时,查查文档、搜搜案例。记住,多动手写代码,比看十遍教程都管用。