【Python】xlsxwriter的使用

第一章:xlsxwriter 入门与核心概念
1.1 xlsxwriter 概述

xlsxwriter 是一个 Python 模块,用于将文本、数字、公式以及格式化信息写入 Microsoft Excel 2007+ .xlsx 格式的文件。

主要特点:

仅创建新文件:这是最重要的特性。它不能读取或修改现有的 Excel 文件。
高性能:对于写入大量数据,xlsxwriter 通常比其他库有更好的性能,部分原因在于其流式写入和内存优化选项。
丰富的功能集

支持几乎所有的 Excel 单元格格式化选项。
可以创建多种类型的图表。
支持单元格合并、数据验证、条件格式、表格、筛选器等。
可以写入超链接、注释、图片。
支持 VBA 宏(通过嵌入现有包含宏的 vbaProject.bin 文件)。
提供内存优化模式 (constant_memory),用于处理非常大的数据集。

跨平台:与 Python 本身一样,可以在 Windows, macOS, Linux 等多种操作系统上运行。
不依赖 Excel: 生成的 .xlsx 文件完全符合 Office Open XML (OOXML) 规范,不需要在服务器或运行环境中安装 Microsoft Excel。
与 Pandas 集成: 可以作为 Pandas ExcelWriter 的引擎,方便地将 DataFrame 导出到 Excel。

openpyxl 的关键区别:

特性 xlsxwriter openpyxl
文件操作 仅创建新文件 (.xlsx) 创建、读取、修改现有文件 (.xlsx, .xlsm)
依赖性 无外部依赖 (除了Python标准库) 无外部依赖 (除了Python标准库)
性能 通常在写入新大文件时性能更优 读取和修改操作灵活,写入性能尚可
图表API 较底层,但功能全面 提供了较好的图表对象模型
VBA宏 可以嵌入 vbaProject.bin 可以读取和保存包含宏的文件 (.xlsm)
内存优化 提供 constant_memory 模式 也有只读/只写优化模式

选择哪个库取决于具体需求。如果你的任务是从头生成 Excel 文件,特别是需要高性能或特定高级格式化功能时,xlsxwriter 是一个绝佳的选择。如果需要读取或修改现有文件,则应选择 openpyxl

1.2 安装 xlsxwriter

安装 xlsxwriter 非常简单,使用 pip 即可:

pip install XlsxWriter

这条命令会从 Python Package Index (PyPI) 下载并安装最新版本的 xlsxwriter

1.3 基本工作流程

使用 xlsxwriter 创建 Excel 文件的基本步骤如下:

导入 xlsxwriter 模块。
创建一个新的 Workbook 对象:这是 Excel 文件在内存中的表示。在创建 Workbook 对象时,需要指定要输出的文件名。
Workbook 中添加一个或多个 Worksheet 对象:每个工作表对应 Excel 文件中的一个 sheet。
Worksheet 的单元格中写入数据:可以使用 worksheet.write() 方法或其特定类型的变体(如 write_string(), write_number(), write_formula() 等)。
(可选)应用格式化:创建 Format 对象并将其应用于单元格或行/列。
(可选)执行其他操作:如插入图表、图片、设置列宽、合并单元格等。
关闭 Workbook 对象:调用 workbook.close() 方法。这个步骤至关重要,它会将所有数据和格式写入到磁盘上的 .xlsx 文件中。如果不调用 close(),文件可能不会被正确创建或内容不完整。 推荐使用 with 语句来自动管理 Workbook 的关闭。

1.4 第一个 xlsxwriter 程序:Hello Excel

让我们创建一个简单的 Excel 文件,包含一些基本数据。

import xlsxwriter # 导入 xlsxwriter 模块

# 1. 创建一个新的 Excel 文件并添加一个工作表。
# 构造函数 Workbook() 接受文件名作为参数。
workbook = xlsxwriter.Workbook('hello_excel.xlsx') # 创建一个名为 'hello_excel.xlsx' 的 Workbook 对象

# add_worksheet() 方法添加一个新的工作表。
# 如果不指定名称,工作表将按默认名称命名,如 Sheet1, Sheet2 等。
worksheet = workbook.add_worksheet('问候') # 向工作簿中添加一个名为 '问候' 的工作表

# 2. 向单元格写入数据。
# write() 方法用于向单元格写入数据。
# 参数可以是:(row, col, item, cell_format=None) 或 (cell_name, item, cell_format=None)
# row 和 col 是从0开始的索引。

# 使用 A1 单元格引用方式写入字符串
worksheet.write('A1', '你好,世界!') # 在 A1 单元格写入字符串 '你好,世界!'

# 使用行号和列号 (row, col) 方式写入数字
worksheet.write(1, 0, 123.45) # 在第2行第1列 (即 A2 单元格,索引为 1,0) 写入数字 123.45

# 写入公式
worksheet.write(2, 0, '=SUM(A2, 10)') # 在 A3 单元格写入公式 '=SUM(A2, 10)'

# 写入日期 (需要使用 workbook.add_format() 来格式化日期)
import datetime # 导入 datetime 模块
date_format = workbook.add_format({
            'num_format': 'yyyy-mm-dd hh:mm:ss'}) # 创建一个日期格式对象
a_date = datetime.datetime(2023, 11, 15, 10, 30, 0) # 创建一个 datetime 对象
worksheet.write_datetime('A4', a_date, date_format) # 在 A4 单元格写入日期,并应用日期格式

# 3. 关闭 Workbook 对象。
# 这会将数据写入 Excel 文件并关闭它。
workbook.close() # 关闭工作簿,将内存中的数据写入到磁盘文件

print("文件 'hello_excel.xlsx' 已成功创建。") # 打印成功创建文件的消息

打开生成的 hello_excel.xlsx 文件,你会看到:

一个名为 “问候” 的工作表。
A1 单元格包含文本 “你好,世界!”。
A2 单元格包含数字 123.45。
A3 单元格包含公式 =SUM(A2,10),并且其显示值为 133.45。
A4 单元格包含日期 “2023-11-15 10:30:00”。

使用 with 语句管理 Workbook (推荐)

为了确保 workbook.close() 总是被调用,即使在发生异常时也是如此,推荐使用 with 语句:

import xlsxwriter # 导入 xlsxwriter 模块
import datetime # 导入 datetime 模块

file_name_with_with = 'hello_with_statement.xlsx' # 定义文件名

with xlsxwriter.Workbook(file_name_with_with) as workbook: # 使用 with 语句创建 Workbook 对象,确保自动关闭
    worksheet = workbook.add_worksheet("示例Sheet") # 添加一个名为 "示例Sheet" 的工作表

    worksheet.write_string(0, 0, "使用with语句") # 在 A1 单元格写入字符串
    worksheet.write_number(1, 0, 999) # 在 A2 单元格写入数字
    worksheet.write_formula(2, 0, '=B2*2') # 在 A3 单元格写入公式
    
    date_fmt = workbook.add_format({
            'num_format': 'yyyy/mm/dd'}) # 创建日期格式
    worksheet.write_datetime(3, 0, datetime.date(2024, 1, 1), date_fmt) # 在 A4 单元格写入日期

print(f"文件 '{
              file_name_with_with}' 已通过 with 语句成功创建。") # 打印成功消息

with 语句块结束时,workbook 对象的 __exit__ 方法会被调用,该方法内部会执行 self.close()

第二章:写入不同数据类型到单元格

xlsxwriter 提供了多种 write_*() 方法来显式地处理不同类型的数据,这有助于确保数据在 Excel 中被正确解释和存储。虽然通用的 write() 方法通常能根据 Python 数据类型自动选择合适的 Excel 类型,但使用特定类型的方法可以提供更精细的控制。

2.1 write_string(row, col, string, cell_format=None)

用于写入字符串。

# ... (假设 workbook 和 worksheet 已创建) ...
# worksheet = workbook.add_worksheet()

worksheet.write_string(0, 0, "这是一个字符串") # 在 A1 写入字符串
worksheet.write_string('B1', "另一个字符串") # 在 B1 写入字符串

Excel 对单元格中的字符串长度有限制(通常是32767个字符)。如果字符串超过此限制,xlsxwriter 会截断它或引发异常,具体行为取决于版本和配置。

2.2 write_number(row, col, number, cell_format=None)

用于写入整数或浮点数。

# ... (worksheet 已创建) ...
worksheet.write_number(1, 0, 123) # 在 A2 写入整数 123
worksheet.write_number('B2', 3.14159) # 在 B2 写入浮点数 3.14159
worksheet.write_number(1, 2, -50.5) # 在 C2 写入负数 -50.5
2.3 write_blank(row, col, blank, cell_format=None)

用于写入一个空单元格。这与单元格中有一个空字符串 "" 不同。一个真正的空单元格通常用于格式化或作为公式的占位符。
参数 blank 通常是 None

# ... (worksheet 已创建) ...
# 创建一个带边框的格式,用于空单元格
blank_format = workbook.add_format({
            'border': 1}) # 创建一个带单线边框的格式
worksheet.write_blank(2, 0, None, blank_format) # 在 A3 写入一个空单元格,并应用边框格式
worksheet.write_string(2, 1, "", blank_format)  # 在 B3 写入一个空字符串,并应用边框格式 (注意区别)

在Excel中,A3单元格将是真正的空(但有边框),而B3单元格包含一个零长度的字符串。

2.4 write_formula(row, col, formula, cell_format=None, value=None)

用于写入 Excel 公式。

formula: 字符串形式的 Excel 公式,必须以 = 开头。
cell_format: 可选的单元格格式。
value: 可选参数,用于设置公式计算的初始结果。如果 Excel 文件被不支持公式计算的应用程序(如某些查看器)打开,这个值会被显示。如果省略,xlsxwriter 通常会将值设置为0。

# ... (worksheet 已创建) ...
worksheet.write_number('A5', 10) # 在 A5 写入数字 10
worksheet.write_number('B5', 20) # 在 B5 写入数字 20

# 写入简单公式
worksheet.write_formula('C5', '=A5+B5') # 在 C5 写入公式 '=A5+B5'

# 写入带结果的公式
worksheet.write_formula('D5', '=SUM(A5:B5)', None, 30) # 在 D5 写入公式 '=SUM(A5:B5)',并指定结果为30

# 写入引用其他工作表的公式
worksheet2 = workbook.add_worksheet('Sheet2') # 添加另一个工作表 Sheet2
worksheet2.write_number('A1', 100) # 在 Sheet2 的 A1 写入数字 100
# 假设当前 worksheet 是 'Sheet1'
worksheet.write_formula('E5', "=Sheet2!A1 * 2") # 在 Sheet1 的 E5 写入引用 Sheet2!A1 的公式

# 动态公式 (字符串函数等)
worksheet.write_formula('F5', '=LEFT(A1, 2)') # 在 F5 写入公式 '=LEFT(A1, 2)' (假设A1是 "这是一个字符串")

# 数组公式 (见后续高级部分)
# worksheet.write_array_formula('A6:A8', '{=TREND(C1:C3,B1:B3)}')

公式的语法和函数名必须是英文的,即使在非英文版的 Excel 中也是如此。Excel 会在打开文件时自动将它们本地化。

2.5 write_datetime(row, col, datetime_obj, cell_format=None)

用于写入 Python datetime.datetime, datetime.date, 或 datetime.time 对象。Excel 将日期和时间存储为序列号。xlsxwriter 会自动进行转换。为了正确显示日期/时间,通常需要提供一个包含数字格式的 cell_format

import datetime # 导入 datetime 模块
# ... (workbook 和 worksheet 已创建) ...

# 创建日期时间格式
date_fmt_full = workbook.add_format({
            'num_format': 'yyyy-mm-dd hh:mm:ss', 'align': 'left'}) # 创建完整日期时间格式
date_fmt_ymd = workbook.add_format({
            'num_format': 'yyyy"年"mm"月"dd"日"'}) # 创建年月日格式
time_fmt = workbook.add_format({
            'num_format': 'hh:mm AM/PM'}) # 创建时间格式

# 写入 datetime.datetime 对象
dt_obj = datetime.datetime(2023, 12, 25, 14, 30, 55) # 创建一个 datetime 对象
worksheet.write_datetime('A7', dt_obj, date_fmt_full) # 在 A7 写入完整的日期时间

# 写入 datetime.date 对象
d_obj = datetime.date(2024, 7, 1) # 创建一个 date 对象
worksheet.write_datetime('B7', d_obj, date_fmt_ymd) # 在 B7 写入日期 (年月日)

# 写入 datetime.time 对象 (Excel 中时间是日期的一部分,通常是序列号的小数部分)
# 单独的时间对象会被视为从1899-12-30 (或1904-01-01,取决于日期系统) 开始的小数
t_obj = datetime.time(18, 45, 0) # 创建一个 time 对象
worksheet.write_datetime('C7', t_obj, time_fmt) # 在 C7 写入时间
# 注意:如果单元格没有日期部分,Excel可能会显示一个奇怪的日期(如1900-01-00)。
# 如果只想显示时间,通常会将日期时间对象(如 datetime.datetime.now())写入,并仅用时间格式化。
# 或者,如果只已关注时间部分,可以写一个包含时间的完整日期,然后只显示时间。
full_dt_for_time = datetime.datetime(2000, 1, 1, 18, 45, 0) # 创建一个包含日期的 datetime 对象
worksheet.write_datetime('D7', full_dt_for_time, time_fmt) # 在 D7 写入,仅显示时间部分

# 写入当前日期和时间
worksheet.write_datetime('E7', datetime.datetime.now(), date_fmt_full) # 在 E7 写入当前日期时间
2.6 write_boolean(row, col, boolean, cell_format=None)

用于写入布尔值 TrueFalse。Excel 会将它们显示为 TRUE 和 FALSE。

# ... (worksheet 已创建) ...
worksheet.write_boolean(7, 0, True)  # 在 A8 写入布尔值 TRUE
worksheet.write_boolean('B8', False) # 在 B8 写入布尔值 FALSE
2.7 write_url(row, col, url, cell_format=None, string=None, tip=None)

用于写入超链接。

url: 链接的目标地址 (例如 'http://www.python.org/''internal:Sheet2!A1''file:///path/to/file.txt')。
cell_format: 可选,应用到链接文本的格式。xlsxwriter 默认会应用标准的蓝色下划线超链接样式。你可以通过 workbook.get_default_url_format() 获取并修改这个默认格式,或者提供一个全新的格式。
string: 可选,链接显示的文本。如果省略,将显示 url 本身。
tip: 可选,鼠标悬停在链接上时显示的工具提示文本 (屏幕提示)。

# ... (worksheet 已创建) ...

# 获取并修改默认的URL格式 (例如,去掉下划线)
url_format = workbook.get_default_url_format() # 获取默认URL格式对象
url_format.set_underline(False) # 设置URL格式为无下划线
url_format.set_font_color('navy') # 设置URL字体颜色为海军蓝

# 写入外部URL,显示自定义文本和提示
worksheet.write_url('A9', 'https://www.djangoproject.com/', string='Django官网', tip='访问Django项目主页') # 在 A9 写入外部URL

# 写入内部工作表链接
worksheet.write_url('B9', "internal:Sheet2!B5", string="跳转到Sheet2的B5", cell_format=url_format) # 在 B9 写入内部链接,并应用自定义格式

# 写入文件链接
worksheet.write_url('C9', r'file:///C:UsersPublicDocumentsexample.txt', string='打开示例文档') # 在 C9 写入文件链接 (注意路径格式)
                                                                                              # 对于本地文件,路径需要是绝对路径,并且格式正确

# 写入邮件链接
worksheet.write_url('D9', 'mailto:user@example.com?subject=Hello from XlsxWriter', string='发送邮件') # 在 D9 写入邮件链接

# 如果只想显示URL本身作为链接文本
worksheet.write_url('E9', 'https://xlsxwriter.readthedocs.io/') # 在 E9 写入URL,链接文本也是URL本身
2.8 通用 write(row, col, data, cell_format=None) 方法

write() 方法会尝试根据传入的 data 的 Python 类型来调用相应的 write_*() 方法。

str -> write_string()
int, float -> write_number()
bool -> write_boolean()
datetime.datetime, datetime.date, datetime.time -> write_datetime()
如果 data 是以 = 开头的字符串,则调用 write_formula()
如果 dataNone,则调用 write_blank() (除非有格式,否则可能不写入任何内容)。

# ... (worksheet 已创建) ...
worksheet.write(9, 0, "自动类型推断") # 在 A10 写入,自动识别为字符串
worksheet.write(9, 1, 789.01)         # 在 B10 写入,自动识别为数字
worksheet.write(9, 2, True)           # 在 C10 写入,自动识别为布尔值
worksheet.write(9, 3, datetime.date.today(), date_fmt_ymd) # 在 D10 写入,自动识别为日期,并应用格式
worksheet.write(9, 4, '=B10*2')       # 在 E10 写入,自动识别为公式
worksheet.write(9, 5, None)           # 在 F10 写入,识别为blank (如果没格式,单元格会是空的)

虽然 write() 很方便,但在某些情况下,显式使用 write_*() 方法可以提供更好的可读性和控制,特别是当数据类型可能不明确或需要特定处理时。

2.9 行和列的限制

Excel 工作表有最大行数和列数限制:

最大行数: 1,048,576 (即 220)
最大列数: 16,384 (即 214),对应列名 “XFD”

xlsxwriter 会遵守这些限制。尝试写入超出范围的单元格会导致错误。

第三章:单元格格式化 (Formatting)

格式化是 xlsxwriter 的核心强项之一。它允许你对单元格应用丰富的格式,包括字体、数字格式、对齐方式、颜色、边框等。

3.1 Format 对象

xlsxwriter 中,所有的单元格格式化都是通过 Format 对象来定义的。Format 对象由 Workbookadd_format() 方法创建。

# ... (workbook 已创建) ...

# 创建一个 Format 对象
bold_format = workbook.add_format() # 创建一个空的 Format 对象
bold_format.set_bold() # 调用 Format 对象的方法来设置属性,例如设置为粗体

# 或者在创建时通过字典传递属性
red_italic_format = workbook.add_format({
            'bold': False, 'italic': True, 'font_color': 'red'}) # 创建Format对象并初始化属性

# 将 Format 对象应用于单元格
# worksheet = workbook.add_worksheet()
worksheet.write('A1', '粗体文本', bold_format) # 在 A1 单元格写入文本 "粗体文本",并应用 bold_format 格式
worksheet.write('B1', '红色斜体', red_italic_format) # 在 B1 单元格写入文本 "红色斜体",并应用 red_italic_format 格式

add_format() 方法返回一个 Format 对象。你可以多次调用 Format 对象的方法来设置不同的格式属性。Format 对象在工作簿中是共享的,如果多个单元格使用完全相同的格式,它们会引用同一个 Format 对象,这有助于减小文件大小。

3.2 常见的格式属性

Format 对象支持大量的属性设置方法。以下是一些最常用的:

3.2.1 字体 (Font) 属性

set_font_name(font_name): 设置字体名称,如 ‘Arial’, ‘微软雅黑’, ‘Times New Roman’。

font_name_format = workbook.add_format() # 创建格式对象
font_name_format.set_font_name('微软雅黑') # 设置字体为微软雅黑
worksheet.write('A2', '微软雅黑字体', font_name_format) # 应用格式

set_font_size(size): 设置字体大小 (磅)。

font_size_format = workbook.add_format({
              'font_size': 16}) # 创建格式对象并设置字体大小为16
worksheet.write('B2', '16号字', font_size_format) # 应用格式

set_font_color(color_string): 设置字体颜色。颜色可以是HTML样式的 '#RRGGBB' 字符串(如 '#FF0000' 代表红色),或者预定义的颜色名称(如 'red', 'green', 'blue', 'yellow', 'magenta', 'cyan', 'black', 'white', 'gray' 等)。

font_color_format = workbook.add_format() # 创建格式对象
font_color_format.set_font_color('blue') # 设置字体颜色为蓝色
worksheet.write('C2', '蓝色字体', font_color_format) # 应用格式
font_color_hex_format = workbook.add_format({
              'font_color': '#E066FF'}) # 紫色
worksheet.write('D2', '自定义紫色字体', font_color_hex_format) # 应用格式

set_bold(): 设置为粗体。
set_italic(): 设置为斜体。
set_underline(style): 设置下划线。style 可以是:

1True: 单下划线 (默认)
2: 双下划线
33: 单会计式下划线
34: 双会计式下划线

bold_italic_format = workbook.add_format({
              'bold': True, 'italic': True}) # 创建粗斜体格式
worksheet.write('A3', '粗斜体', bold_italic_format) # 应用格式
underline_format = workbook.add_format() # 创建格式对象
underline_format.set_underline(2) # 设置双下划线
worksheet.write('B3', '双下划线', underline_format) # 应用格式

set_font_strikeout(): 设置删除线。
set_font_script(style): 设置上标或下标。style 可以是:

1: 上标
2: 下标

strike_format = workbook.add_format({
              'font_strikeout': True}) # 创建删除线格式
worksheet.write('C3', '删除线', strike_format) # 应用格式

superscript_format = workbook.add_format() # 创建格式对象
superscript_format.set_font_script(1) # 设置为上标
worksheet.write_rich_string('D3', 'E=mc', superscript_format, '2') # 写入 "E=mc²" (见富文本部分)

subscript_format = workbook.add_format({
              'font_script': 2}) # 创建下标格式
worksheet.write_rich_string('E3', 'H', subscript_format, '2', 'O') # 写入 "H₂O"
3.2.2 数字格式 (Number Format)

set_num_format(format_string): 设置单元格的数字显示格式。format_string 是 Excel 的数字格式代码。

# 数字格式示例
num_format_integer = workbook.add_format({
              'num_format': '0'}) # 整数
num_format_decimal = workbook.add_format({
              'num_format': '0.00'}) # 两位小数
num_format_accounting = workbook.add_format({
              'num_format': '_(* #,##0.00_);_(* (#,##0.00);_(* "-"??_);_(@_)'}) # 会计格式
num_format_percent = workbook.add_format({
              'num_format': '0.0%'}) # 百分比,一位小数
num_format_date = workbook.add_format({
              'num_format': 'yyyy-mm-dd'}) # 日期格式
num_format_custom_text = workbook.add_format({
              'num_format': '@ " units"'}) # 文本后加 " units"
num_format_scientific = workbook.add_format({
              'num_format': '0.00E+00'}) # 科学计数法

worksheet.write_number('A12', 12345, num_format_integer) # 写入12345,显示为12345
worksheet.write_number('B12', 123.4567, num_format_decimal) # 写入123.4567,显示为123.46
worksheet.write_number('C12', -5000.78, num_format_accounting) # 写入-5000.78,按会计格式显示
worksheet.write_number('D12', 0.875, num_format_percent) # 写入0.875,显示为87.5%
worksheet.write_datetime('E12', datetime.date(2023,1,1), num_format_date) # 写入日期,按yyyy-mm-dd显示
worksheet.write_number('F12', 15, num_format_custom_text) # 写入15,显示为 "15 units"
worksheet.write_number('G12', 123456789, num_format_scientific) # 写入大数,按科学计数法显示

Excel 内置了许多数字格式,你也可以创建自定义的数字格式字符串。

3.2.3 对齐 (Alignment) 属性

set_align(alignment_string): 设置水平和垂直对齐。

水平对齐:

'left'
'center'
'right'
'fill' (填充单元格)
'justify' (两端对齐)
'center_across' (跨列居中 – 需要先合并单元格)
'distributed' (分散对齐)

垂直对齐:

'top'
'vcenter' (垂直居中)
'bottom'
'vjustify' (垂直两端对齐)
'vdistributed' (垂直分散对齐)

# 可以分别设置,或通过 set_align 一次性设置
align_center_vcenter = workbook.add_format() # 创建格式对象
align_center_vcenter.set_align('center') # 设置水平居中
align_center_vcenter.set_align('vcenter') # 设置垂直居中
worksheet.set_row(12, 30) # 设置第13行 (索引12) 的高度为30,以便观察垂直对齐
worksheet.write('A13', '水平垂直居中', align_center_vcenter) # 应用格式

# 也可以在创建时设置
align_right_top = workbook.add_format({
              'align': 'right', 'valign': 'top'}) # 创建右对齐、顶端对齐格式
worksheet.write('B13', '右上对齐', align_right_top) # 应用格式

set_text_wrap(): 设置自动换行。

wrap_format = workbook.add_format({
              'text_wrap': True, 'valign': 'top'}) # 创建自动换行、顶端对齐格式
worksheet.set_column('C:C', 15) # 设置C列宽度为15
long_text = "这是一段非常非常长的文本,需要自动换行才能完整显示。" # 定义长文本
worksheet.write('C13', long_text, wrap_format) # 写入长文本并应用自动换行格式

set_rotation(angle): 设置文本旋转角度。angle 可以是 -90 到 90 之间的整数。特殊值 270 表示垂直文本(自上而下)。

rotate_format = workbook.add_format({
              'rotation': 45, 'align': 'center', 'valign': 'vcenter'}) # 创建旋转45度格式
worksheet.write('D13', '旋转45度', rotate_format) # 应用格式

vertical_text_format = workbook.add_format({
              'rotation': 270, 'align': 'center', 'valign': 'vcenter'}) # 创建垂直文本格式
worksheet.write('E13', '垂直文本', vertical_text_format) # 应用格式

set_indent(level): 设置文本缩进级别。
set_shrink(): 设置缩小字体以适应单元格。

3.2.4 填充 (Fill) 和图案 (Pattern)

set_pattern(pattern_index): 设置图案样式。pattern_index 从 0 到 18,0 表示无图案,1 表示纯色填充。

set_bg_color(color_string): 设置图案的背景色 (当 pattern > 1 时使用)。

set_fg_color(color_string): 设置图案的前景色 (当 pattern > 0 时使用)。对于纯色填充 (pattern=1),fg_color 就是填充色。

# 纯色填充 (背景色)
solid_fill_blue = workbook.add_format({
              'fg_color': '#ADD8E6'}) # 浅蓝色固体填充 (fg_color 用于 solid fill)
# solid_fill_blue.set_pattern(1) # Pattern 1 is solid fill by default if fg_color is set.
worksheet.write('A14', '浅蓝背景', solid_fill_blue) # 应用格式

# 另一种设置纯色填充的方式
solid_fill_yellow = workbook.add_format() # 创建格式对象
solid_fill_yellow.set_pattern(1)  # 设置为纯色填充模式 (1 代表 solid fill)
solid_fill_yellow.set_fg_color('yellow') # 设置前景色 (填充色) 为黄色
worksheet.write('B14', '黄色背景', solid_fill_yellow) # 应用格式

# 图案填充 (例如:灰色细网点)
pattern_fill_format = workbook.add_format() # 创建格式对象
pattern_fill_format.set_pattern(6)      # 设置图案样式为细网点 (6: thin_diag_crosshatch)
pattern_fill_format.set_fg_color('gray')  # 设置图案前景色为灰色
pattern_fill_format.set_bg_color('white') # 设置图案背景色为白色 (可选,默认为无)
worksheet.write('C14', '网点图案', pattern_fill_format) # 应用格式

xlsxwriter 文档中有完整的图案索引列表。

3.2.5 边框 (Border)

set_border(style): 设置单元格所有四个边框的样式。
set_top(style), set_bottom(style), set_left(style), set_right(style): 分别设置上、下、左、右边框的样式。
set_border_color(color_string): 设置所有四个边框的颜色。
set_top_color(color), set_bottom_color(color), set_left_color(color), set_right_color(color): 分别设置各边框颜色。
set_diag_type(diag_type): 设置对角线边框类型 (1: 左上到右下, 2: 左下到右上, 3: 两者都有)。
set_diag_border(style): 设置对角线边框样式。
set_diag_color(color): 设置对角线边框颜色。

边框样式 style 的值 (整数):

0: 无边框

1: 细实线 (Thin)

2: 中等实线 (Medium)

3: 虚线 (Dashed)

4: 点线 (Dotted)

5: 粗实线 (Thick)

6: 双线 (Double)

7: 发丝线 (Hair)

8: 中等虚线 (Medium dashed)

9: 细点划线 (Dash-dot)

10: 中等点划线 (Medium dash-dot)

11: 细双点划线 (Dash-dot-dot)

12: 中等双点划线 (Medium dash-dot-dot)

13: 倾斜中等点划线 (Slanted medium dash-dot)

# 全部细黑边框
all_thin_border = workbook.add_format({
              'border': 1, 'border_color': 'black'}) # 设置所有边框为细黑线
worksheet.write('A15', '四边细黑框', all_thin_border) # 应用格式

# 自定义上下边框
custom_border_format = workbook.add_format() # 创建格式对象
custom_border_format.set_top(5) # 设置上边框为粗实线
custom_border_format.set_top_color('red') # 设置上边框颜色为红色
custom_border_format.set_bottom(6) # 设置下边框为双线
custom_border_format.set_bottom_color('blue') # 设置下边框颜色为蓝色
custom_border_format.set_left(1) # 设置左边框为细实线
custom_border_format.set_left_color('green') # 设置左边框颜色为绿色
custom_border_format.set_right(2) # 设置右边框为中等实_Hasync_lines线
custom_border_format.set_right_color('purple') # 设置右边框颜色为紫色
worksheet.write('B15', '自定义边框', custom_border_format) # 应用格式

# 对角线边框
diag_border_format = workbook.add_format() # 创建格式对象
diag_border_format.set_diag_type(3) # 设置对角线类型为两条 (左上到右下,左下到右上)
diag_border_format.set_diag_border(1) # 设置对角线边框样式为细实线
diag_border_format.set_diag_color('orange') # 设置对角线边框颜色为橙色
worksheet.write('C15', 'X', diag_border_format) # 应用格式 (通常用于标记单元格)
3.2.6 保护 (Protection)

set_locked(is_locked): 设置单元格是否锁定。默认为 True (锁定)。单元格锁定只有在工作表被保护时才生效。

set_hidden(is_hidden): 设置公式是否隐藏。默认为 False (不隐藏)。公式隐藏也只有在工作表被保护时才生效。

unlocked_format = workbook.add_format({
              'locked': False}) # 创建解锁格式
hidden_formula_format = workbook.add_format({
              'hidden': True, 'locked': True}) # 创建隐藏公式并锁定格式

worksheet.write('A16', '可编辑内容', unlocked_format) # 此单元格在工作表保护后仍可编辑
worksheet.write_formula('B16', '=A16*2', hidden_formula_format) # 此单元格公式在保护后不可见,且单元格不可编辑

# 保护工作表 (见后续章节)
# worksheet.protect()
3.3 Format 对象的属性字典

除了使用 set_*() 方法,还可以在创建 Format 对象时通过一个字典来传递所有属性:

header_format_dict = workbook.add_format({
             # 使用字典定义一个复杂的表头格式
    'bold': True,                       # 粗体
    'font_name': 'Arial',               # 字体 Arial
    'font_size': 12,                    # 字号 12
    'font_color': 'white',              # 字体颜色 白色
    'fg_color': '#4F81BD',              # 背景填充色 (深蓝)
    'pattern': 1,                       # 纯色填充
    'align': 'center',                  # 水平居中
    'valign': 'vcenter',                # 垂直居中
    'border': 1,                        # 细边框
    'border_color': '#BFBFBF'           # 边框颜色 (浅灰)
})

worksheet.write('A18', '字典定义的表头', header_format_dict) # 应用通过字典创建的格式

这种方式代码更简洁,特别是当需要设置很多属性时。属性名称与 set_*() 方法名(去掉 set_ 并转为小写下划线)或其文档中定义的键名对应。

3.4 默认格式

工作簿有一个默认的单元格格式。可以通过 workbook.set_default_date_format() 来设置默认的日期格式字符串,这样在调用 write_datetime() 时如果未提供 cell_format,就会使用这个默认日期格式。

workbook.set_default_date_format('dd/mm/yy') # 设置工作簿的默认日期格式为 dd/mm/yy
worksheet.write_datetime('A20', datetime.date(2025, 5, 10)) # 写入日期,将使用上面设置的默认日期格式

对于其他类型的默认格式(如全局字体),xlsxwriter 没有直接的API,通常需要为每个单元格或区域显式应用格式。Excel 的 “Normal” 样式是其内部定义的。

3.5 格式的合并与复用

Format 对象一旦创建并设置好属性后,就是不可变的。如果你需要一个基于现有格式稍作修改的新格式,你需要创建一个新的 Format 对象,并从头设置其所有属性,或者使用 Format.set_<em>property</em>() 方法来构建它。xlsxwriter 不支持像CSS那样的样式继承或覆盖。

xlsxwriter 会自动优化格式。如果多个单元格应用了完全相同的格式属性组合,它们在内部会共享同一个 Format 对象在 .xlsx 文件中的定义,这有助于减小最终文件的大小。因此,不必担心创建多个内容相同的 Format 对象实例会导致文件膨胀,只要它们的属性集完全一样。

format1 = workbook.add_format({
            'bold': True, 'font_color': 'red'}) # 创建格式1: 粗体红字
format2 = workbook.add_format({
            'bold': True, 'font_color': 'red'}) # 创建格式2: 粗体红字 (属性与format1相同)
# format1 和 format2 在xlsxwriter内部会被视为同一个格式定义

worksheet.write(20, 0, "Text1", format1) # 在A21应用格式1
worksheet.write(20, 1, "Text2", format2) # 在B21应用格式2 (实际上会复用format1的定义)

# 如果需要一个略有不同的格式
format3 = workbook.add_format({
            'bold': True, 'font_color': 'red', 'italic': True}) # 格式3: 粗体红字斜体
worksheet.write(20, 2, "Text3", format3) # 在C21应用格式3 (这是一个新的格式定义)
第四章:操作行和列

xlsxwriter 允许对工作表中的行和列进行多种操作,包括设置高度/宽度、隐藏、应用默认格式、分组(大纲)等。这些操作都是通过 Worksheet 对象的方法来完成的。

4.1 设置列宽 (set_column())

worksheet.set_column(first_col, last_col, width=None, cell_format=None, options=None)

此方法用于设置一列或多列的宽度以及可选的默认格式。

first_col: 要设置的第一列的索引(从0开始,A列为0)。
last_col: 要设置的最后一列的索引。如果只设置单列,first_collast_col 相同。
width: 列的宽度,单位是字符宽度。Excel 的默认列宽通常是 8.43 个字符(对于默认字体 Calibri 11pt)。xlsxwriter 中的宽度单位与 Excel 相同。如果设置为 None 或省略,则宽度保持不变(但仍可应用格式)。如果设置为0,列将被隐藏。
cell_format: 可选的 Format 对象。此格式将应用于指定列范围内的所有单元格,除非这些单元格被后续的单元格特定格式覆盖。
options: 一个可选的字典,包含以下键:

'hidden': 布尔值,如果为 True,则隐藏列(等同于 width=0)。
'level': 整数,设置列的大纲级别(用于列分组)。
'collapsed': 布尔值,如果大纲级别被设置,并且此项为 True,则该列组默认折叠。

代码示例:设置列宽和默认列格式

# ... (假设 workbook 和 worksheet 已创建) ...
# worksheet = workbook.add_worksheet("行和列操作")

# 1. 设置单列的宽度
worksheet.set_column(0, 0, 20) # 设置 A 列 (索引0) 的宽度为 20 个字符
worksheet.write('A1', 'A列宽度为20') # 在A1写入内容以观察效果

# 2. 设置多列的宽度
worksheet.set_column(1, 3, 12) # 设置 B, C, D 列 (索引1到3) 的宽度为 12 个字符
worksheet.write('B1', 'B列') # 写入B1
worksheet.write('C1', 'C列') # 写入C1
worksheet.write('D1', 'D列') # 写入D1

# 3. 设置列宽并应用默认格式
currency_format = workbook.add_format({
            'num_format': '$#,##0.00'}) # 创建货币格式
worksheet.set_column('E:E', 15, currency_format) # 设置 E 列宽度为15,并应用货币格式为默认格式
worksheet.write_number('E1', 1234.56) # 在E1写入数字,将自动应用货币格式
worksheet.write_number('E2', 7890.12) # 在E2写入数字,也将应用货币格式
worksheet.write_string('E3', '非数字', currency_format) # 对字符串应用货币格式通常无显示效果,但格式已关联

# 4. 隐藏列
worksheet.set_column('F:F', None, None, {
            'hidden': True}) # 隐藏 F 列 (通过options参数)
# 或者 worksheet.set_column('F:F', 0) # 也可以通过设置宽度为0来隐藏
worksheet.write('F1', '此列已隐藏') # 写入F1 (内容存在但列不可见)
worksheet.write('G1', 'G列可见') # 写入G1以对比

# 5. 使用列名字符串设置范围
worksheet.set_column('H:J', 10) # 设置 H, I, J 列的宽度为 10

# 注意:多次调用 set_column() 在重叠的列上,后面的设置会覆盖前面的。
# 例如,先设置 A:E 为宽度10,再设置 C:C 为宽度20,则C列最终宽度为20。

使用 set_column() 时,如果 width 参数为 None,则该列的宽度不会改变,但 cell_format (如果提供) 仍然会作为该列的默认格式应用。

4.2 设置行高 (set_row())

worksheet.set_row(row, height=None, cell_format=None, options=None)

此方法用于设置特定行的高度以及可选的默认格式。

row: 要设置的行的索引(从0开始,第1行为0)。
height: 行的高度,单位是磅 (points)。Excel 的默认行高通常是 15 磅。如果设置为 None 或省略,则高度保持不变(但仍可应用格式)。如果设置为0,行将被隐藏。
cell_format: 可选的 Format 对象。此格式将应用于该行的所有单元格,除非被单元格特定格式覆盖。
options: 一个可选的字典,包含以下键:

'hidden': 布尔值,如果为 True,则隐藏行(等同于 height=0)。
'level': 整数,设置行的大纲级别(用于行分组)。
'collapsed': 布尔值,如果大纲级别被设置,并且此项为 True,则该行组默认折叠。
'height_rule': (较少使用) 控制行高如何应用,通常不需要设置。

代码示例:设置行高和默认行格式

# ... (假设 workbook, worksheet, currency_format 已创建) ...

# 1. 设置单行的高度
worksheet.set_row(4, 30) # 设置第5行 (索引4) 的高度为 30 磅
worksheet.write(4, 0, '第5行高度为30磅') # 在 A5 (索引4,0) 写入内容

# 2. 设置行高并应用默认格式
highlight_format = workbook.add_format({
            'bg_color': '#FFFFCC', 'bold': True}) # 创建高亮格式 (浅黄背景,粗体)
worksheet.set_row(5, 25, highlight_format) # 设置第6行 (索引5) 高度为25磅,并应用高亮格式为默认格式
worksheet.write(5, 0, "默认高亮") # 此单元格将应用 highlight_format
worksheet.write(5, 1, 123)        # 此单元格也将应用 highlight_format
worksheet.write(5, 2, "特定格式", currency_format) # 此单元格有特定格式,会覆盖行的默认格式

# 3. 隐藏行
worksheet.set_row(6, None, None, {
            'hidden': True}) # 隐藏第7行 (索引6)
# 或者 worksheet.set_row(6, 0)
worksheet.write(6, 0, '此行已隐藏') # 写入内容到隐藏行
worksheet.write(7, 0, '第8行可见') # 写入到下一行以对比

# 4. 设置默认行高 (会影响之后添加的没有显式设置高度的行)
# worksheet.set_default_row(height=20, hide_unused_rows=False)
# `set_default_row()` 会设置工作表中所有未使用(即没有数据或格式化)的行的高度。
# `hide_unused_rows=True` 会隐藏所有默认行高的行,这通常用于创建看起来更紧凑的表格。

# 示例:设置默认行高并隐藏未使用的行
# 注意:这个操作会影响整个工作表后续的默认行高和显示
worksheet.set_default_row(18) # 设置之后所有未显式设置高度的行的默认高度为18磅
worksheet.write(8,0, "此行使用新的默认高度") # 第9行 (索引8)

# 如果想隐藏所有超出已使用范围的默认行:
# worksheet.set_default_row(hide_unused_rows=True)
# 这通常在所有数据写入完毕后调用。

set_row() 应用的默认格式优先级低于单元格通过 write() 方法直接指定的格式。

4.3 默认行属性 (set_default_row())

worksheet.set_default_row(height=None, hide_unused_rows=False)

height: 设置工作表中所有“未使用”行的默认高度。默认是15磅。
hide_unused_rows: 如果设为 True,则所有高度由 height 参数(或Excel默认值)决定的未使用行将被隐藏。这可以使包含少量数据的工作表看起来更整洁。

这个方法通常在工作表内容基本确定后调用,用于调整整体外观。

4.4 插入图片到单元格 (insert_image())

worksheet.insert_image(row, col, filename, options=None)worksheet.insert_image(cell, filename, options=None)

用于在工作表中插入图片。图片会浮动在单元格之上,但其左上角会与指定的单元格对齐。

row, colcell: 图片左上角对齐的单元格。
filename: 图片文件的路径 (例如 'logo.png', 'images/my_pic.jpg')。支持 PNG, JPEG, GIF, BMP, WMF, EMF 等格式。推荐使用 PNG。
options: 一个可选的字典,用于控制图片的位置、缩放、URL等。常用选项包括:

'x_offset', 'y_offset': 图片相对于单元格左上角的像素偏移量。
'x_scale', 'y_scale': 图片的水平和垂直缩放比例 (例如 0.5 表示50%)。
'url': 为图片添加超链接。
'tip': 图片的工具提示文本。
'image_data': 一个 io.BytesIO 对象,包含图片的二进制数据,而不是从文件路径加载。这对于从内存中的图片数据插入很有用。
'object_position': 控制图片如何随单元格移动和调整大小 (高级选项,1: 随单元格移动和调整大小, 2: 随单元格移动但不调整大小 (默认), 3: 不随单元格移动和调整大小)。
'description': 图片的描述文字(用于辅助功能)。

代码示例:插入图片

# ... (假设 workbook 和 worksheet 已创建) ...

# 准备一个示例图片文件 (例如,在脚本同目录下创建一个 'logo.png')
# 为了运行此示例,你需要确保有一个名为 'python_logo.png' 的图片在脚本可以访问到的地方
# 或者替换为你的图片路径。
# 你可以从 https://www.python.org/static/community_logos/python-logo.png 下载一个Python logo
image_path = 'python_logo.png' # 图片文件路径

try:
    # 1. 简单插入图片到 B10 单元格
    worksheet.insert_image('B10', image_path) # 将图片插入到 B10 单元格对齐
    worksheet.write('A10', 'Python Logo:') # 在图片旁边添加标签

    # 2. 插入图片并进行缩放和偏移
    options_scaled = {
            
        'x_scale': 0.5, # 水平缩放为50%
        'y_scale': 0.5, # 垂直缩放为50%
        'x_offset': 10, # 向右偏移10像素
        'y_offset': 5   # 向下偏移5像素
    }
    worksheet.insert_image('B15', image_path, options_scaled) # 在 B15 插入缩放并偏移的图片
    worksheet.write('A15', '缩放Logo:') # 添加标签

    # 3. 插入图片并添加超链接和提示
    options_with_url = {
            
        'url': 'https://www.python.org', # 为图片设置超链接
        'tip': '访问 Python 官方网站'     # 设置鼠标悬停提示
    }
    worksheet.insert_image(19, 1, image_path, options_with_url) # 在第20行B列 (B20) 插入带链接的图片
    worksheet.write(19, 0, '链接Logo:') # 在 A20 添加标签

    # 4. 从内存数据插入图片 (如果图片已在BytesIO对象中)
    import io # 导入 io 模块
    # 假设我们已经通过某种方式获取了图片的二进制数据
    # 例如,通过 requests 下载的图片 content
    # image_bytes = requests.get("URL_TO_IMAGE").content
    # image_data_io = io.BytesIO(image_bytes)
    # worksheet.insert_image('B25', 'dummy_name_for_excel.png', {'image_data': image_data_io})
    # 注意:即使从内存插入,通常也需要提供一个文件名字符串,Excel内部会用到。
    # 这里我们跳过实际的内存加载,只演示结构。

except FileNotFoundError: # 文件未找到异常处理
    worksheet.write('B10', f"错误: 图片 '{
              image_path}' 未找到。请确保图片存在。") # 如果图片文件不存在,则写入错误消息
    print(f"警告: 图片文件 '{
              image_path}' 未找到,部分图片插入示例可能无法正常工作。") # 打印警告信息


# 设置包含图片的行高和列宽,以便图片能完整显示
worksheet.set_row(9, 80)  # 第10行 (索引9) 高度设为80 (假设logo高度)
worksheet.set_row(14, 50) # 第15行 (索引14) 高度设为50 (假设缩放后logo高度)
worksheet.set_row(19, 80) # 第20行 (索引19) 高度设为80
worksheet.set_column('B:B', 15) # B列宽度设为15 (假设logo宽度)

图片是按其原始像素尺寸插入的,除非通过 x_scaley_scale 进行缩放。你需要根据图片大小调整单元格或行列尺寸,或者缩放图片以适应布局。

4.5 合并单元格 (merge_range())

worksheet.merge_range(first_row, first_col, last_row, last_col, data, cell_format=None)worksheet.merge_range(range_string, data, cell_format=None)

用于合并一个矩形区域的单元格,并将数据和格式写入到合并后的左上角单元格。

first_row, first_col, last_row, last_col: 定义要合并的单元格范围的左上角和右下角(从0开始的索引)。
range_string: 或者使用单元格范围字符串,如 'A1:C3'
data: 要写入到合并单元格的数据。
cell_format: 可选的 Format 对象,应用到合并后的单元格。

代码示例:合并单元格

# ... (假设 workbook 和 worksheet 已创建) ...

# 1. 合并 B22:D23 范围并写入文本,应用居中格式
merge_format = workbook.add_format({
             # 创建居中对齐格式
    'align': 'center',
    'valign': 'vcenter',
    'border': 1, # 添加边框以看清合并区域
    'fg_color': '#F0F8FF' # 爱丽丝蓝背景
})
worksheet.merge_range('B22:D23', '这是一个合并的单元格区域', merge_format) # 合并 B22:D23,写入文本并应用格式

# 2. 合并单元格并写入数字
worksheet.merge_range(24, 1, 24, 3, 12345, currency_format) # 合并第25行 (索引24) 的 B,C,D 列 (B25:D25),写入数字并应用货币格式

# 3. 仅合并单元格,不写入初始数据 (写入 None 或空字符串)
empty_merge_format = workbook.add_format({
            'border': 1, 'fg_color': '#E0E0E0'}) # 浅灰色背景和边框
worksheet.merge_range('F22:G24', None, empty_merge_format) # 合并 F22:G24,不写入数据,但应用格式

# 注意事项:
# - 只能合并矩形区域。
# - 合并区域内的其他单元格(除了左上角)在概念上就不存在了,不能再单独写入或引用。
# - 如果尝试写入已合并区域内的非左上角单元格,`xlsxwriter` 可能会忽略写入或产生不可预期的行为。
# - 合并单元格的格式由传递给 `merge_range` 的 `cell_format` 决定。
# - 如果合并区域内的单元格之前有数据,合并后只有左上角单元格的数据(即传递给 `merge_range` 的 `data` 参数)会保留。

合并单元格常用于创建标题、表头或布局复杂的表格。

4.6 大纲和分组 (Outlining and Grouping)

xlsxwriter 支持创建行和列的分组(大纲),允许用户在 Excel 中展开和折叠这些组。这是通过在 set_row()set_column()options 字典中设置 level 属性来实现的。

level: 大纲级别,从1开始。级别越高,嵌套越深。级别为0表示不属于任何组。
hidden: 如果某个级别要隐藏其下的所有行/列,则该级别的 set_row/column 调用可以设置 hidden: True
collapsed: 如果为 True,则该级别的分组在文件打开时默认是折叠的。

代码示例:创建行分组和列分组

# ... (假设 workbook 和 worksheet 已创建) ...
# worksheet_outline = workbook.add_worksheet("大纲和分组") # 为此示例创建一个新工作表

# 准备一些层级数据
data_outline = [
    ["区域", "月份", "产品A销量", "产品B销量"],
    ["华东", "一月", 100, 150],
    ["华东", "二月", 120, 160],
    ["华东小计", "", "=SUM(C2:C3)", "=SUM(D2:D3)"], # 级别1的小计行
    ["华北", "一月", 80, 130],
    ["华北", "二月", 90, 140],
    ["华北小计", "", "=SUM(C5:C6)", "=SUM(D5:D6)"], # 级别1的小计行
    ["总计", "", "=C4+C7", "=D4+D7"]               # 级别0的总计行
]

# 写入数据
for r_idx, row_data in enumerate(data_outline): # 遍历数据
    worksheet.write_row(r_idx + 28, 0, row_data) # 从第29行 (索引28) 开始写入数据 (避免与之前内容重叠)

# 设置行大纲级别
# 假设数据在第29行到第36行 (索引28到35)
# 华东数据行 (一月, 二月) - 级别 2
worksheet.set_row(29, options={
            'level': 2, 'hidden': False}) # 第30行 (索引29),华东一月
worksheet.set_row(30, options={
            'level': 2, 'hidden': False}) # 第31行 (索引30),华东二月
# 华东小计行 - 级别 1 (父级)
worksheet.set_row(31, options={
            'level': 1, 'hidden': False, 'collapsed': False}) # 第32行 (索引31),华东小计

# 华北数据行 - 级别 2
worksheet.set_row(32, options={
            'level': 2, 'hidden': False}) # 第33行 (索引32),华北一月
worksheet.set_row(33, options={
            'level': 2, 'hidden': False}) # 第34行 (索引33),华北二月
# 华北小计行 - 级别 1
worksheet.set_row(34, options={
            'level': 1, 'hidden': False, 'collapsed': True}) # 第35行 (索引34),华北小计,默认折叠

# 总计行 - 级别 0 (不属于任何组,或顶级)
worksheet.set_row(35, options={
            'level': 0}) # 第36行 (索引35),总计

# 设置列大纲级别 (例如,将产品A和产品B销量分为一组)
# 产品A销量 (C列,索引2) 和 产品B销量 (D列,索引3) - 级别 1
worksheet.set_column(2, 2, options={
            'level': 1, 'hidden': False, 'collapsed': True}) # C列,产品A销量,级别1,默认折叠
worksheet.set_column(3, 3, options={
            'level': 1, 'hidden': False, 'collapsed': True}) # D列,产品B销量,级别1,默认折叠

# (可选)设置大纲显示选项
worksheet.outline_settings(visible=True, symbols_below=True, symbols_right=True, auto_style=False)
# visible: 是否显示大纲符号 (默认为True,如果设置了级别)
# symbols_below: 行大纲符号是否显示在组的下方 (True) 或上方 (False, 默认)。Excel默认是在下方。
# symbols_right: 列大纲符号是否显示在组的右方 (True) 或左方 (False, 默认)。Excel默认是在右方。
# auto_style: Excel是否自动为大纲级别应用样式 (通常不需要xlsxwriter来做)。

创建大纲后,Excel 用户界面左侧(行)和顶部(列)会出现 +- 符号,用于展开和折叠分组。

4.7 冻结窗格 (freeze_panes())

worksheet.freeze_panes(row, col, top_row=None, left_col=None)worksheet.freeze_panes(cell, top_row=None, left_col=None)

用于冻结工作表的一部分行和/或列,使其在滚动时保持可见。

row, col (或 cell): 指定冻结的分界点。所有在此单元格上方的行和左侧的列将被冻结。

若要冻结第一行:freeze_panes(1, 0)freeze_panes('A2')
若要冻结A列:freeze_panes(0, 1)freeze_panes('B1')
若要冻结第一行和A列:freeze_panes(1, 1)freeze_panes('B2')

top_row, left_col: (已废弃,但为了兼容性可能仍存在) 用于更复杂的“拆分窗格”场景,通常直接使用 row, col 参数即可满足冻结需求。

代码示例:冻结表头行和标识列

# ... (假设 workbook 和 worksheet 已创建,并且有一些数据) ...
# worksheet_freeze = workbook.add_worksheet("冻结窗格") # 创建新工作表

# 写入一些示例数据,以便滚动
for r in range(40): # 写入40行数据
    for c in range(10): # 写入10列数据
        worksheet.write(r, c, f'R{
              r+1}C{
              c+1}') # 写入单元格标识 "RxCy"

# 1. 冻结第一行 (表头行)
# worksheet.freeze_panes(1, 0) # 冻结第1行 (索引0的下一行即第2行开始滚动)

# 2. 冻结 A 列 (标识列)
# worksheet.freeze_panes(0, 1) # 冻结A列 (索引0的右一列即B列开始滚动)

# 3. 冻结第一行和 A 列
worksheet.freeze_panes(1, 1) # 冻结点在 B2 单元格,使其上方的第1行和左侧的A列被冻结

# 注意:一个工作表只能有一个冻结窗格设置。后续调用会覆盖之前的设置。
4.8 拆分窗格 (split_panes())

worksheet.split_panes(y, x, top_row, left_col)

用于将工作表拆分为多个可独立滚动的窗格。这与冻结窗格不同,拆分窗格允许所有窗格都滚动。

y: 垂直拆分位置(以屏幕像素为单位,但 xlsxwriter 通常将其解释为行高单位的近似值)。
x: 水平拆分位置(以屏幕像素为单位,xlsxwriter 通常将其解释为列宽单位的近似值)。
top_row: 拆分后,左上角窗格中可见的最顶行号(从0开始)。
left_col: 拆分后,左上角窗格中可见的最左列号(从0开始)。

拆分窗格在 xlsxwriter 中的使用不如冻结窗格常见,其参数解释也可能依赖于 Excel 的默认行为。

# ... (worksheet_freeze 包含数据) ...
# 示例:在第10行和第3列之后拆分窗格,左上角窗格显示工作表的开头
# y_split = 15 * 10 # 假设每行高15磅,在第10行后拆分 (大约150磅)
# x_split = 8.43 * 3 * 5.5 # 假设每列宽8.43字符,在第3列后拆分 (像素转换复杂,这里用近似)
# worksheet.split_panes(y_split, x_split, 0, 0) # 在大约第10行和第3列处拆分
# `xlsxwriter` 文档建议 y 和 x 是行高和列宽的倍数。
# 例如,拆分在第5行(索引4)和C列(索引2)之后:
# worksheet.split_panes(row_to_split_after=4, col_to_split_after=2) # 这种接口在xlsxwriter中可能不存在
# 更常见的做法是指定行号和列号作为拆分点

# `xlsxwriter` 的 `split_panes` 参数是 y, x, top_row, left_col
# y: 垂直分割点 (行高单位)。如果想在第5行之后分割,y = 5 * default_row_height。
# x: 水平分割点 (列宽单位)。
# 假设默认行高15,默认列宽8.43
# 拆分在第5行之后,第3列之后:
y_split_pos = 5 * 15 # 5行的高度
x_split_pos = 3 * 8.43 * 6 # 3列的宽度 (乘以一个因子转为近似像素或内部单位) - 这个转换比较模糊
# worksheet.split_panes(y_split_pos, x_split_pos, 0, 0) # 这种方式效果可能不精确

# 更可靠的拆分窗格通常是在Excel中设置,因为像素到单位的转换和具体行为不易精确控制。
# `xlsxwriter` 主要用于冻结窗格。如果需要拆分,可以尝试,但效果可能需要调整。
# 如果只想创建拆分视图,通常是设置 `freeze_panes` 的 `top_row` 和 `left_col` 参数,
# 而 `row` 和 `col` 参数为0。但这也更像是冻结的变种。
# e.g., worksheet.freeze_panes(0, 0, top_row=5, left_col=3) # 视图从第6行D列开始,但没有冻结的行/列

# 专注于 `freeze_panes` 通常更实用。

由于 split_panes 的像素/单位转换的复杂性和 Excel 行为的多样性,freeze_panes 是更常用且效果更可预测的功能。

第五章:数据验证 (Data Validation)

数据验证是 Excel 的一项功能,用于限制用户可以在单元格中输入的数据类型或值。它可以防止输入错误,确保数据的准确性和一致性。xlsxwriter 允许你在创建工作表时定义这些验证规则。

5.1 data_validation() 方法

worksheet.data_validation(first_row, first_col, last_row, last_col, options)worksheet.data_validation(cell_range, options)

此方法用于向一个或多个单元格添加数据验证规则。

first_row, first_col, last_row, last_colcell_range: 定义应用数据验证的单元格范围。
options: 一个包含验证参数的字典。关键参数包括:

'validate': 验证类型。这是最重要的参数,决定了验证规则的性质。可选值包括:

'any': 任何值 (通常用于设置输入消息或错误提示,而不实际限制输入)。
'integer': 整数。
'decimal': 十进制数。
'list': 列表中的值 (下拉列表)。
'date': 日期。
'time': 时间。
'length': 文本长度。
'custom': 自定义公式。

'criteria': 验证标准。其含义取决于 'validate' 的类型。例如:

对于 'integer', 'decimal', 'date', 'time', 'length''criteria' 可以是:

'between', 'not between'
'equal to', 'not equal to'
'greater than', 'less than'
'greater than or equal to', 'less than or equal to'

对于 'list''criteria' 通常不直接使用,而是通过 'source' 提供列表。
对于 'custom''criteria' 通常不直接使用,而是通过 'value' (或 'formula') 提供公式。

'value': 对于 'integer', 'decimal', 'date', 'time', 'length',这是与 'criteria' 配合使用的单个值或公式引用。对于 'custom',这是验证公式。对于 'list',如果列表项直接在选项中提供而不是引用单元格区域,则此参数可能用 'source' 代替。
'minimum': 对于 'between''not between' 标准,这是下限值或公式引用。
'maximum': 对于 'between''not between' 标准,这是上限值或公式引用。
'source': 对于 'list' 验证类型,这是关键参数。它可以是:

一个包含下拉列表项的 Python 列表 (例如 ['Open', 'High', 'Closed'])。
一个单元格区域的字符串引用 (例如 '$A$1:$A$5'),该区域包含列表项。

'ignore_blank': 布尔值 (默认为 True)。如果为 True,则空单元格被视为有效。
'dropdown': 布尔值 (默认为 True)。对于 'list' 验证,如果为 True,则显示下拉箭头。
'show_input': 布尔值 (默认为 True)。如果为 True,则在选择单元格时显示输入消息。
'input_title': 字符串,输入消息的标题 (如果 'show_input'True)。
'input_message': 字符串,输入消息的内容。
'show_error': 布尔值 (默认为 True)。如果为 True,则在输入无效数据时显示错误警告。
'error_title': 字符串,错误警告的标题 (如果 'show_error'True)。
'error_message': 字符串,错误警告的内容。
'error_type': 字符串,错误警告的类型。可以是:

'stop' (默认): 阻止输入无效数据。
'warning': 警告用户数据无效,但允许输入。
'information': 提示用户数据无效,但允许输入。

5.2 验证整数 (Integer)

限制单元格只能输入整数,并可以指定范围。

# ... (假设 workbook 和 worksheet 已创建) ...
# worksheet_validation = workbook.add_worksheet("数据验证") # 创建新工作表用于数据验证示例

# 1. 验证单元格只能输入 1 到 10 之间的整数
worksheet.data_validation('B2', {
             # 对 B2 单元格应用数据验证
    'validate': 'integer',          # 验证类型:整数
    'criteria': 'between',          # 标准:介于两者之间
    'minimum': 1,                   # 最小值:1
    'maximum': 10,                  # 最大值:10
    'input_title': '输入整数:',      # 输入提示标题
    'input_message': '请输入一个介于 1 和 10 之间的整数。', # 输入提示内容
    'error_title': '输入错误!',      # 错误提示标题
    'error_message': '您输入的值不在 1 到 10 的范围内。', # 错误提示内容
    'error_type': 'stop'            # 错误类型:停止 (禁止无效输入)
})
worksheet.write_string('A2', '1-10整数:') # 在 A2 写入标签 "1-10整数:"

# 2. 验证单元格只能输入大于 100 的整数
worksheet.data_validation('B3', {
             # 对 B3 单元格应用数据验证
    'validate': 'integer',          # 验证类型:整数
    'criteria': 'greater than',     # 标准:大于
    'value': 100,                   # 值:100 (与'criteria'配合使用)
    'input_message': '请输入一个大于100的整数。', # 输入提示内容 (标题可选)
    'error_message': '必须输入大于100的整数。', # 错误提示内容
    'error_type': 'warning'         # 错误类型:警告 (允许输入但提示)
})
worksheet.write_string('A3', '>100整数:') # 在 A3 写入标签 ">100整数:"
5.3 验证小数 (Decimal)

与整数验证类似,但允许输入带小数的数字。

# ... (worksheet_validation 已创建) ...

# 验证单元格只能输入 0.0 到 1.0 之间的小数 (例如百分比)
worksheet.data_validation('B5', {
             # 对 B5 单元格应用数据验证
    'validate': 'decimal',          # 验证类型:小数
    'criteria': 'between',          # 标准:介于两者之间
    'minimum': 0.0,                 # 最小值:0.0
    'maximum': 1.0,                 # 最大值:1.0
    'input_title': '输入百分比 (0-1):', # 输入提示标题
    'input_message': '请输入一个介于 0.0 和 1.0 之间的小数。', # 输入提示内容
    'error_title': '格式无效',       # 错误提示标题
    'error_message': '百分比值必须在 0.0 和 1.0 之间。' # 错误提示内容
})
worksheet.write_string('A5', '0-1小数:') # 在 A5 写入标签 "0-1小数:"
5.4 验证列表 (List) – 创建下拉列表

这是非常常用的功能,可以在单元格中创建一个下拉列表供用户选择。

# ... (worksheet_validation 已创建) ...

# 1. 使用 Python 列表作为下拉列表的源
status_options = ['待处理', '进行中', '已完成', '已取消'] # 定义下拉列表的选项
worksheet.data_validation('B7', {
             # 对 B7 单元格应用数据验证
    'validate': 'list',             # 验证类型:列表
    'source': status_options,       # 源:直接使用 Python 列表
    'input_message': '请从列表中选择一个状态。', # 输入提示内容
    'error_message': '请选择列表中的有效状态。', # 错误提示内容
    'show_input': True,             # 显示输入提示 (默认也是True)
    'dropdown': True                # 显示下拉箭头 (默认也是True)
})
worksheet.write_string('A7', '状态(列表源):') # 在 A7 写入标签 "状态(列表源):"

# 2. 使用工作表中的单元格区域作为下拉列表的源
# 首先,在工作表的某个地方写入列表项
source_list_header = ['可选城市'] # 定义源列表的表头
cities = ['北京', '上海', '广州', '深圳', '杭州'] # 定义城市列表
worksheet.write_row('E1', source_list_header) # 在 E1 写入表头 "可选城市"
for i, city in enumerate(cities): # 遍历城市列表
    worksheet.write(i + 1, 4, city) # 将城市名写入 E 列 (从 E2 开始)

# 定义源区域的字符串引用 (例如 E2:E6)
city_source_range = f'$E$2:$E${
              len(cities) + 1}' # 构建源区域引用字符串 "$E$2:$E$6"

worksheet.data_validation('B8', {
             # 对 B8 单元格应用数据验证
    'validate': 'list',             # 验证类型:列表
    'source': city_source_range,    # 源:引用工作表中的单元格区域
    'input_message': '请选择一个城市。', # 输入提示内容
})
worksheet.write_string('A8', '城市(区域源):') # 在 A8 写入标签 "城市(区域源):"

# 3. 也可以不显示下拉箭头 (但仍然会进行列表验证)
worksheet.data_validation('B9', {
             # 对 B9 单元格应用数据验证
    'validate': 'list',
    'source': ['是', '否'],
    'dropdown': False, # 不显示下拉箭头
    'input_message': '请输入 "是" 或 "否"'
})
worksheet.write_string('A9', '是/否(无下拉):') # 在 A9 写入标签 "是/否(无下拉):"

注意:当使用单元格区域作为 source 时,Excel 对该区域的长度有限制(通常是255个字符的总长度,对于下拉列表中的所有项,如果它们不是直接来自单元格引用的话;或者如果来自单元格引用,则对单元格数量有限制)。对于非常长的列表,可能需要考虑其他方法或在Excel中通过命名区域来管理。xlsxwriter 在处理直接列表源时,如果项太多,生成的XML可能会很大。

5.5 验证日期 (Date)

限制单元格只能输入有效的日期,并可以指定日期范围。

import datetime # 导入 datetime 模块
# ... (worksheet_validation 已创建) ...

# 1. 验证日期必须在 2023-01-01 之后
start_date_obj = datetime.date(2023, 1, 1) # 定义开始日期对象
# xlsxwriter 在处理日期验证时,通常期望日期以Excel序列号或ISO 8601字符串 'YYYY-MM-DD' 形式提供给 'value', 'minimum', 'maximum'
start_date_excel_val = (start_date_obj - datetime.date(1899, 12, 30)).days # 转换为Excel序列号 (近似)
# 或者更简单地使用ISO格式字符串,xlsxwriter会处理
start_date_iso = start_date_obj.isoformat() # "2023-01-01"

worksheet.data_validation('B11', {
             # 对 B11 单元格应用数据验证
    'validate': 'date',             # 验证类型:日期
    'criteria': 'greater than',     # 标准:大于
    'value': start_date_iso,        # 值:开始日期 (ISO格式)
    # 或者 'value': start_date_obj, # xlsxwriter 也可能接受 datetime 对象
    'input_title': '输入日期:',
    'input_message': '请输入 2023-01-01 之后的日期。 (格式 YYYY-MM-DD)',
    'error_message': '日期必须晚于 2023-01-01。'
})
worksheet.write_string('A11', '日期(晚于):') # 在 A11 写入标签 "日期(晚于):"
# 最好也为该单元格设置日期数字格式
date_display_format = workbook.add_format({
            'num_format': 'yyyy-mm-dd'}) # 创建日期显示格式
worksheet.set_column('B:B', 15, date_display_format) # 设置 B 列宽度并应用默认日期格式

# 2. 验证日期在指定范围内
min_date_obj = datetime.date(2024, 1, 1) # 定义最小日期
max_date_obj = datetime.date(2024, 12, 31) # 定义最大日期

worksheet.data_validation('B12', {
             # 对 B12 单元格应用数据验证
    'validate': 'date',
    'criteria': 'between',
    'minimum': min_date_obj, # xlsxwriter 通常可以直接接受 datetime 对象
    'maximum': max_date_obj,
    'input_message': '请输入 2024 年的日期。'
})
worksheet.write_string('A12', '日期(2024年):') # 在 A12 写入标签 "日期(2024年):"

Excel 对日期的内部存储是序列号。xlsxwriter 会处理 Python datetime 对象到 Excel 序列号的转换。在 'value', 'minimum', 'maximum' 中提供 datetime.datedatetime.datetime 对象通常是可行的。

5.6 验证时间 (Time)

与日期验证类似,但用于时间值。

import datetime # 导入 datetime 模块
# ... (worksheet_validation 已创建) ...

# 验证时间必须在 09:00 AM 到 05:00 PM 之间
min_time_obj = datetime.time(9, 0, 0) # 定义最小时间 09:00:00
max_time_obj = datetime.time(17, 0, 0) # 定义最大时间 17:00:00

worksheet.data_validation('B14', {
             # 对 B14 单元格应用数据验证
    'validate': 'time',             # 验证类型:时间
    'criteria': 'between',          # 标准:介于两者之间
    'minimum': min_time_obj,        # 最小值:datetime.time 对象
    'maximum': max_time_obj,        # 最大值:datetime.time 对象
    'input_title': '输入工作时间:',
    'input_message': '请输入 09:00 AM 到 05:00 PM 之间的时间。 (格式 HH:MM)',
    'error_message': '时间必须在工作时间内。'
})
worksheet.write_string('A14', '时间(工作时段):') # 在 A14 写入标签 "时间(工作时段):"
# 为该单元格设置时间数字格式
time_display_format = workbook.add_format({
            'num_format': 'hh:mm AM/PM'}) # 创建时间显示格式
worksheet.set_column('B:B', 18, time_display_format) # 更新B列宽度并应用默认时间格式 (之前的日期格式会被覆盖,注意范围)
# 更好的做法是为不同验证的单元格单独设置格式,或在写入时指定
worksheet.write_blank('B14', None, time_display_format) # 给B14应用时间格式
5.7 验证文本长度 (Length)

限制单元格中输入文本的字符数。

# ... (worksheet_validation 已创建) ...

# 验证文本长度必须等于5个字符 (例如邮政编码)
worksheet.data_validation('B16', {
             # 对 B16 单元格应用数据验证
    'validate': 'length',           # 验证类型:文本长度
    'criteria': 'equal to',         # 标准:等于
    'value': 5,                     # 值:长度为5
    'input_message': '请输入5位字符的编码。',
    'error_message': '编码长度必须为5位。'
})
worksheet.write_string('A16', '文本长度(5位):') # 在 A16 写入标签 "文本长度(5位):"

# 验证文本长度在 3 到 10 个字符之间
worksheet.data_validation('B17', {
             # 对 B17 单元格应用数据验证
    'validate': 'length',
    'criteria': 'between',
    'minimum': 3,
    'maximum': 10,
    'input_message': '请输入3到10个字符的用户名。'
})
worksheet.write_string('A17', '用户名(3-10位):') # 在 A17 写入标签 "用户名(3-10位):"
5.8 自定义验证 (Custom)

允许使用 Excel 公式作为验证标准。如果公式计算结果为 TRUE (或非零数字),则输入有效;否则无效。

# ... (worksheet_validation 已创建) ...

# 验证 B19 单元格的值必须大于 B20 单元格的值
# 公式是相对于应用验证的第一个单元格编写的。
# 如果验证应用于单个单元格 B19,则公式可以直接引用 B19。
worksheet.data_validation('B19', {
             # 对 B19 单元格应用数据验证
    'validate': 'custom',           # 验证类型:自定义
    'value': '=B19>B20',            # 验证公式:B19 的值大于 B20 的值
    'input_title': '自定义验证',
    'input_message': '此单元格 (B19) 的值必须大于下方单元格 (B20) 的值。',
    'error_message': 'B19 必须大于 B20!'
})
worksheet.write_string('A19', '自定义(B19>B20):') # 在 A19 写入标签 "自定义(B19>B20):"
worksheet.write_string('A20', '参考值 (B20):') # 在 A20 写入标签 "参考值 (B20):"
worksheet.write_number('B20', 50) # 在 B20 写入一个参考数字 50

# 验证单元格输入必须是唯一的 (在该列中)
# 例如,验证 D 列从 D2 开始的单元格输入是唯一的
# 公式 (对于D2单元格): =COUNTIF(D:D, D2)<=1
# 注意:如果范围很大,COUNTIF(D:D,...) 可能会慢。最好指定一个实际范围,如 COUNTIF($D$2:$D$100, D2)<=1
unique_formula = '=COUNTIF(D$2:D$100,D2)<=1' # 定义唯一性验证公式 (假设数据在D2:D100)
worksheet.data_validation('D2:D10', {
             # 对 D2:D10 范围应用唯一性验证
    'validate': 'custom',
    'value': unique_formula,
    'error_title': '输入重复',
    'error_message': '此列中已存在相同的值,请输入唯一值。',
    'error_type': 'stop'
})
worksheet.write_string('C2', '唯一ID列:') # 在 C2 写入标签 "唯一ID列:"
worksheet.set_column('D:D', 15) # 设置D列宽度

自定义公式提供了极大的灵活性,可以实现各种复杂的验证逻辑。公式中的单元格引用遵循 Excel 的相对和绝对引用规则。

5.9 输入消息和错误警告的控制

如前面的示例所示,可以通过以下参数自定义用户交互:

'show_input', 'input_title', 'input_message':控制输入单元格时的提示信息。
'show_error', 'error_title', 'error_message', 'error_type':控制输入无效数据时的错误处理行为和消息。

'show_input''show_error' 设置为 False 可以禁用相应的消息框。

5.10 ignore_blank 参数

默认情况下 ('ignore_blank': True),数据验证规则不会对空单元格进行检查。如果用户没有在单元格中输入任何内容,则视为有效。如果需要强制用户输入(即空单元格无效),则应将 'ignore_blank' 设置为 False

# ... (worksheet_validation 已创建) ...
worksheet.data_validation('B22', {
             # 对 B22 单元格应用数据验证
    'validate': 'any', # 验证类型可以是 'any' 如果只是想强制输入
    'criteria': 'not equal to', # 结合 criteria 使其有意义
    'value': '""', # 通常与一个不可能的值比较,或者依赖 ignore_blank
    'ignore_blank': False, # 空值将被视为无效
    'input_message': '此字段为必填项。',
    'error_message': '此字段不能为空,请输入一个值。'
})
worksheet.write_string('A22', '必填字段:') # 在 A22 写入标签 "必填字段:"

ignore_blankFalse 时,如果用户试图将单元格留空,将会触发错误警告(除非验证规则本身允许空字符串且 validate 类型是文本相关并匹配了空字符串)。

数据验证是确保 Excel 数据质量的重要手段。xlsxwriter 提供了全面的 API 来实现 Excel 中几乎所有的数据验证功能。


第六章:条件格式 (Conditional Formatting)

条件格式允许根据单元格的值或公式的结果自动更改单元格的外观(如背景色、字体颜色、图标、数据条等)。这使得用户能够快速识别数据中的模式、趋势、异常值或重要信息。

6.1 conditional_format() 方法

worksheet.conditional_format(first_row, first_col, last_row, last_col, options)worksheet.conditional_format(cell_range, options)

此方法用于向一个或多个单元格添加条件格式规则。

first_row, first_col, last_row, last_colcell_range: 定义应用条件格式的单元格范围。

options: 一个包含条件格式参数的字典。关键参数包括:

'type': 条件格式的类型。这是最重要的参数。常用类型包括:

'cell': 基于单元格值的规则。
'formula': 基于公式的规则。
'2_color_scale', '3_color_scale': 双色或三色色阶。
'data_bar': 数据条。
'icon_set': 图标集。
'text': 包含特定文本、不包含、开头为、结尾为。
'date': 发生日期 (今天、昨天、上周等)。
'blanks', 'no_blanks': 空白或非空白单元格。
'errors', 'no_errors': 包含错误或不包含错误的单元格。
'duplicate', 'unique': 重复值或唯一值。
'top', 'bottom': 前/后 N 个项目或 N%。
'average': 高于或低于平均值。

'criteria': 条件标准。其含义取决于 'type'。例如:

对于 'cell' 类型:'greater than', 'less than', 'between', 'equal to' 等。
对于 'text' 类型:'containing', 'notContaining', 'beginsWith', 'endsWith'
对于 'date' 类型:'yesterday', 'today', 'tomorrow', 'last7Days', 'thisWeek' 等。
对于 'average' 类型:'above', 'below', 'equalOrAbove', 'equalOrBelow'

'value': 与 'criteria' 配合使用的值或公式。
'minimum', 'maximum': 用于 'between' 标准的上下限。
'format': 一个 Format 对象,定义了当条件满足时应用的格式。这是最核心的格式化参数。 对于色阶、数据条、图标集,格式是其自身定义的一部分,而不是通过这个 'format' 参数。
'multi_range': (高级) 如果条件格式应用于多个不连续的范围,可以将这些范围的字符串列表(例如 'A1:A5 B10:B15')传递给此参数,此时 conditional_format 的第一个范围参数应为该多范围字符串。
'stop_if_true': 布尔值。如果为 True,并且此条件格式规则被触发,则 Excel 不会评估应用于同一单元格的后续(优先级较低的)条件格式规则。

特定类型的附加选项:

色阶 ('2_color_scale', '3_color_scale'):

'min_type', 'mid_type' (仅3色), 'max_type': 端点/中点类型 ('num', 'percent', 'percentile', 'formula', 'min', 'max')。
'min_value', 'mid_value', 'max_value': 对应类型的值。
'min_color', 'mid_color', 'max_color': 端点/中点颜色 (HTML颜色字符串)。

数据条 ('data_bar'):

'bar_color': 数据条的颜色。
'bar_only': 布尔值,如果为 True,则只显示数据条,不显示单元格值。
'bar_direction': 'leftToRight''rightToLeft'
'bar_axis_position': 'none', 'middle' (数据条在单元格中间,文本覆盖)。
'min_type', 'max_type', 'min_value', 'max_value' (类似色阶)。
可以有负值数据条的颜色设置,如 'negative_bar_color', 'negative_bar_border_color'

图标集 ('icon_set'):

'icon_style': 图标集的名称 (例如 '3ArrowsGray', '4Rating', '5TrafficLights')。xlsxwriter 文档中有完整列表。
'icons': 一个列表,描述每个图标及其阈值。每个元素是一个字典,例如 {'criteria': '>=', 'type': 'number', 'value': 0, 'icon': 'green_up_arrow'} (icon的名称可能不直接用,通常由icon_style和阈值决定)。更常见的是直接设置阈值:
'icon_criteria': (可能已弃用或内部使用)
'values': 一个列表,包含图标集的阈值。
'types': 一个列表,对应 'values' 中每个阈值的类型 ('number', 'percent', 'percentile', 'formula')。
'reverse_icons': 布尔值,是否反转图标顺序。
'icons_only': 布尔值,如果为 True,则只显示图标,不显示单元格值。

6.2 基于单元格值的条件格式 ('type': 'cell')

这是最常见的条件格式类型,根据单元格自身的值来应用格式。

# ... (假设 workbook, worksheet 已创建) ...
# worksheet_cf = workbook.add_worksheet("条件格式") # 创建新工作表用于条件格式示例

# 准备一些分数数据
scores_data = [
    ["学生", "分数"],
    ["Alice", 92],
    ["Bob", 78],
    ["Charlie", 65],
    ["David", 88],
    ["Eve", 55],
    ["Frank", 95]
]
for r_idx, row_data in enumerate(scores_data): # 遍历数据
    worksheet.write_row(r_idx, 0, row_data) # 从 A1 开始写入

# 定义格式
format_high_score = workbook.add_format({
            'bg_color': '#C6EFCE', 'font_color': '#006100'}) # 浅绿背景,深绿字体
format_mid_score = workbook.add_format({
            'bg_color': '#FFEB9C', 'font_color': '#9C6500'}) # 浅黄背景,棕色字体
format_low_score = workbook.add_format({
            'bg_color': '#FFC7CE', 'font_color': '#9C0006'}) # 浅红背景,深红字体

score_range = 'B2:B7' # 定义分数数据范围

# 1. 高亮显示大于等于 90 的分数 (优秀)
worksheet.conditional_format(score_range, {
             # 对分数范围应用条件格式
    'type': 'cell',                     # 类型:基于单元格值
    'criteria': '>=',                   # 标准:大于等于
    'value': 90,                        # 值:90
    'format': format_high_score         # 应用的格式:优秀分数格式
})

# 2. 高亮显示介于 70 和 89 之间的分数 (良好)
# 注意:条件格式规则是按顺序评估的。如果一个单元格满足多个规则,
# 除非设置了 'stop_if_true',否则所有匹配的格式可能会叠加(通常是最后一个匹配的优先)。
# 为了避免重叠,最好让条件互斥。
worksheet.conditional_format(score_range, {
             # 对分数范围应用条件格式
    'type': 'cell',
    'criteria': 'between',              # 标准:介于两者之间
    'minimum': 70,                      # 最小值:70
    'maximum': 89,                      # 最大值:89 (Excel中between通常是包含边界)
    'format': format_mid_score          # 应用的格式:中等分数格式
})

# 3. 高亮显示小于 70 的分数 (需改进)
worksheet.conditional_format(score_range, {
             # 对分数范围应用条件格式
    'type': 'cell',
    'criteria': '<',                    # 标准:小于
    'value': 70,                        # 值:70
    'format': format_low_score          # 应用的格式:低分格式
})
6.3 基于公式的条件格式 ('type': 'formula')

允许使用 Excel 公式来决定是否应用格式。如果公式对当前单元格计算结果为 TRUE(或非零数字),则应用格式。

# ... (worksheet_cf 和 scores_data 已写入) ...

# 示例:高亮显示分数高于平均分的学生整行
# 首先计算平均分 (可以在一个辅助单元格,或者直接在公式中使用AVERAGE)
# 假设我们想高亮 A 列到 B 列的整行

# 定义高亮整行的格式
format_above_avg_row = workbook.add_format({
            'bg_color': '#DAEEF3'}) # 浅青色背景

# 公式是相对于应用范围的左上角单元格编写的。
# 假设应用范围是 'A2:B7'。对于A2单元格,公式需要检查 B2 是否大于 B2:B7 的平均值。
# 在条件格式公式中,对于整行高亮,通常固定比较列,而行号相对。
# 公式:`$B2 > AVERAGE($B$2:$B$7)`
# 当应用于A2时,它看B2;当应用于A3时,它看B3,以此类推。
formula_above_avg = f'${
              scores_data[0][1].upper()}2>AVERAGE(${
              scores_data[0][1].upper()}$2:${
              scores_data[0][1].upper()}${
              len(scores_data)})'
# 上述公式构建有点复杂,可以直接写死为 '$B2>AVERAGE($B$2:$B$7)' 如果列和范围已知
formula_above_avg_simple = '$B2>AVERAGE($B$2:$B$7)' # 更简洁的公式

worksheet.conditional_format('A2:B7', {
             # 对 A2:B7 范围应用条件格式
    'type': 'formula',                  # 类型:基于公式
    'criteria': formula_above_avg_simple, # 条件公式
    'format': format_above_avg_row      # 应用的格式
})

# 示例:如果A列是文本 "Eve",则高亮B列对应的分数
format_eve_score = workbook.add_format({
            'font_color': 'purple', 'bold': True}) # 紫色粗体
formula_eve = '$A2="Eve"' # 公式检查A列是否为 "Eve" (行号相对)

worksheet.conditional_format('B2:B7', {
             # 仅对B列分数应用
    'type': 'formula',
    'criteria': formula_eve,
    'format': format_eve_score
})
6.4 色阶 ('2_color_scale', '3_color_scale')

使用颜色渐变来可视化单元格区域内值的分布。

# ... (worksheet_cf 和 scores_data 已写入) ...
# score_range = 'B2:B7'

# 1. 应用双色色阶 (例如,从低分的红色到高分的绿色)
worksheet.conditional_format(score_range, {
             # 对分数范围应用双色色阶
    'type': '2_color_scale',            # 类型:双色色阶
    'min_type': 'min',                  # 最小值类型:区域中的最小值
    'max_type': 'max',                  # 最大值类型:区域中的最大值
    'min_color': '#F8696B',             # 最小颜色:红色 (Excel默认低值颜色)
    'max_color': '#63BE7B'              # 最大颜色:绿色 (Excel默认高值颜色)
})

# 2. 应用三色色阶 (例如,红-黄-绿)
# 为了不与上面的双色冲突,可以将此应用到新范围或先清除之前的规则
# 假设我们有一列新的数据 C2:C7
worksheet.write_column('C1', ["新数据", 10, 50, 30, 80, 60, 95]) # 在C列写入新数据
new_data_range = 'C2:C7' # 定义新数据范围

worksheet.conditional_format(new_data_range, {
             # 对新数据范围应用三色色阶
    'type': '3_color_scale',            # 类型:三色色阶
    'min_type': 'num',                  # 最小值类型:具体数字
    'min_value': 0,                     # 最小值:0
    'min_color': '#F8696B',             # 最小颜色:红色
    'mid_type': 'percentile',           # 中点类型:百分位数
    'mid_value': 50,                    # 中点值:第50百分位数 (中位数)
    'mid_color': '#FFEB84',             # 中点颜色:黄色 (Excel默认中间值颜色)
    'max_type': 'num',                  # 最大值类型:具体数字
    'max_value': 100,                   # 最大值:100
    'max_color': '#63BE7B'              # 最大颜色:绿色
})
6.5 数据条 ('data_bar')

在单元格内绘制与单元格值成比例的条形。

# ... (worksheet_cf 和 scores_data 已写入) ...
# score_range = 'B2:B7'

# 应用蓝色实体数据条
worksheet.conditional_format(score_range, {
             # 对分数范围应用数据条
    'type': 'data_bar',                 # 类型:数据条
    'bar_color': '#638EC6',             # 数据条颜色:蓝色 (Excel默认)
    'bar_only': False,                  # 是否只显示数据条 (False表示同时显示值)
    # 默认情况下,数据条的范围是基于区域中的最小值和最大值
    # 可以通过 'min_type', 'max_type', 'min_value', 'max_value' 自定义范围
    # 例如,使数据条基于0到100的固定范围:
    # 'min_type': 'num', 'min_value': 0,
    # 'max_type': 'num', 'max_value': 100,
})

# 应用渐变数据条,并只显示条 (不显示数字)
gradient_bar_data = [10,25,50,75,90] # 准备一些数据
worksheet.write_column('D1', ["渐变条", *gradient_bar_data]) # 在D列写入数据
gradient_range = 'D2:D6' # 定义渐变条数据范围

worksheet.conditional_format(gradient_range, {
             # 对渐变条数据范围应用条件格式
    'type': 'data_bar',
    'bar_color': '#77C077', # 绿色
    'data_bar_2010': True, # 使用Excel 2010+ 样式的数据条 (通常包括渐变、边框等)
    'bar_solid': False,    # False 表示渐变填充 (如果 data_bar_2010 为 True,这个可能被覆盖或协同工作)
                           # 对于xlsxwriter,更直接的方式是选择一个本身就是渐变的bar_color或依赖data_bar_2010
    'bar_only': True,      # 只显示数据条,不显示数字
    'min_type': 'num', 'min_value': 0, # 数据条从0开始
    'max_type': 'num', 'max_value': 100 # 数据条到100结束
})

'data_bar_2010': True 会启用 Excel 2010 引入的更现代的数据条外观(通常有渐变填充和细边框)。

6.6 图标集 ('icon_set')

使用小图标(如箭头、交通灯)来基于单元格的值对其进行分类和可视化。

# ... (worksheet_cf 和 scores_data 已写入) ...
# score_range = 'B2:B7'

# 1. 应用3箭头图标集 (灰色)
# 规则:>=90 向上箭头, >=70 向右箭头, <70 向下箭头
worksheet.conditional_format(score_range, {
             # 对分数范围应用图标集
    'type': 'icon_set',                 # 类型:图标集
    'icon_style': '3ArrowsGray',        # 图标样式:灰色三箭头
    # 'values' 和 'types' 用于定义阈值
    # 对于N个图标的样式,通常需要 N-1 个阈值来定义N个区间
    # 顺序很重要,通常是定义“较好”图标的下限
    'values': [70, 90],                 # 阈值:70 和 90
    'types': ['number', 'number'],      # 阈值类型:都是数字
    # 解释:
    #   - 值 < values[0] (即 <70)  -> 第一个图标 (向下箭头)
    #   - values[0] <= 值 < values[1] (即 70 <= 值 < 90) -> 第二个图标 (向右箭头)
    #   - 值 >= values[1] (即 >=90) -> 第三个图标 (向上箭头)
    'icons_only': False,                # 是否只显示图标 (False表示同时显示值)
    'reverse_icons': False              # 是否反转图标顺序
})

# 2. 应用5评级星图标集,只显示图标
ratings_data = [1, 3, 5, 2, 4, 3] # 准备评级数据 (1到5星)
worksheet.write_column('E1', ["评级", *ratings_data]) # 在E列写入数据
rating_range = 'E2:E7' # 定义评级数据范围

worksheet.conditional_format(rating_range, {
             # 对评级数据范围应用条件格式
    'type': 'icon_set',
    'icon_style': '5Rating',            # 图标样式:5评级星
    # 对于5图标集,通常需要4个阈值
    # Excel的默认行为通常是基于百分比,这里我们用数字
    # 假设1星(<20%), 2星(>=20% <40%), 3星(>=40% <60%), 4星(>=60% <80%), 5星(>=80%)
    # 对于数字阈值,假设评级是1-5
    'values': [2, 3, 4, 5],           # 阈值: 当值>=2显示1/4填充星, >=3显示半星, >=4显示3/4星, >=5显示全星 (近似逻辑)
                                      # xlsxwriter/Excel的图标集阈值解释有时需要试验
                                      # 更常见的可能是按百分比: [20, 40, 60, 80] 和 types: ['percent', ...]
    'types': ['number', 'number', 'number', 'number'], # 类型都是数字
    'icons_only': True                 # 只显示图标
})

icon_style 的可用值可以在 xlsxwriter 文档中找到 (搜索 “Conditional Format Icon Sets”)。阈值的设置 (valuestypes) 对于图标集至关重要,需要仔细匹配所选 icon_style 的预期行为。

6.7 其他条件格式类型

xlsxwriter 还支持其他一些 Excel 内置的条件格式类型:

'text':

'criteria': 'containing', 'notContaining', 'beginsWith', 'endsWith'
'value': 要匹配的文本字符串。
'format': 应用的 Format 对象。

name_range = 'A2:A7' # 学生姓名范围
format_contains_li = workbook.add_format({
              'bg_color': 'cyan'}) # 青色背景
worksheet.conditional_format(name_range, {
               # 对姓名范围应用条件格式
    'type': 'text',                     # 类型:文本
    'criteria': 'containing',           # 标准:包含
    'value': 'li',                      # 值:"li" (例如 Alice, Charlie 中的 "li")
    'format': format_contains_li        # 应用的格式
})

'date':

'criteria': 'yesterday', 'today', 'tomorrow', 'last7Days', 'thisMonth', 'lastMonth', 'nextMonth', 'thisWeek', 'lastWeek', 'nextWeek'
'format': 应用的 Format 对象。

# 假设 F 列包含日期数据
worksheet.write_column('F1', ["日期", datetime.date(2023,11,10), datetime.date.today(), datetime.date(2023,11,1), datetime.date.today() - datetime.timedelta(days=3)])
date_range_cf = 'F2:F5' # 定义日期范围
format_today = workbook.add_format({
              'font_color': 'white', 'bg_color': 'green'}) # 白色字体,绿色背景

worksheet.conditional_format(date_range_cf, {
               # 对日期范围应用条件格式
    'type': 'date',                     # 类型:日期
    'criteria': 'today',                # 标准:今天
    'format': format_today              # 应用的格式
})

'blanks' / 'no_blanks':

'format': 应用的 Format 对象。

# 假设 G 列有一些数据和一些空单元格
worksheet.write_column('G1', ["检查空值", 10, None, 30, None, 50]) # G列数据
blank_range_cf = 'G2:G6' # 定义检查范围
format_blank = workbook.add_format({
              'bg_color': '#D3D3D3'}) # 浅灰色背景

worksheet.conditional_format(blank_range_cf, {
               # 对范围应用条件格式
    'type': 'blanks',                   # 类型:空白单元格
    'format': format_blank              # 应用的格式
})

'errors' / 'no_errors':

'format': 应用的 Format 对象。

# 假设 H 列有一些数据和一些公式错误 (例如 #DIV/0!)
worksheet.write('H1', "检查错误") # 写入表头
worksheet.write_number('H2', 10) # 写入数字
worksheet.write_formula('H3', '=H2/0') # 写入一个会导致错误的公式 (除以0)
worksheet.write_number('H4', 20) # 写入数字
error_range_cf = 'H2:H4' # 定义检查范围
format_error = workbook.add_format({
              'bg_color': 'pink', 'font_color': 'darkred'}) # 粉色背景,深红字体

worksheet.conditional_format(error_range_cf, {
               # 对范围应用条件格式
    'type': 'errors',                   # 类型:包含错误的单元格
    'format': format_error              # 应用的格式
})

'duplicate' / 'unique':

'format': 应用的 Format 对象。

# 假设 I 列有一些ID,我们想高亮重复的ID
worksheet.write_column('I1', ["ID (查重)", "ID001", "ID002", "ID001", "ID003", "ID002", "ID004"]) # I列数据
duplicate_range_cf = 'I2:I7' # 定义查重范围
format_duplicate = workbook.add_format({
              'font': {
              'color': '#9C0006', 'italic': True}, 'fill': {
              'fg_color': '#FFC7CE'}}) # 深红斜体,浅红填充

worksheet.conditional_format(duplicate_range_cf, {
               # 对范围应用条件格式
    'type': 'duplicate',                # 类型:重复值
    'format': format_duplicate          # 应用的格式
})

# 高亮唯一值 (与重复值相反)
# format_unique = workbook.add_format({'bg_color': 'lightgreen'})
# worksheet.conditional_format(duplicate_range_cf, {
              
# 'type': 'unique',
# 'format': format_unique
# })

'top' / 'bottom':

'criteria': 'top''bottom'
'value': N 的值 (要高亮的项目数)。
'percent': 布尔值,如果为 True,则 'value' 表示百分比而不是项目数。
'format': 应用的 Format 对象。

# 使用之前的分数数据 score_range = 'B2:B7'
format_top_2 = workbook.add_format({
              'bold': True, 'font_color': 'orange'}) # 橙色粗体

worksheet.conditional_format(score_range, {
               # 对分数范围应用条件格式
    'type': 'top',                      # 类型:前 N 个
    'value': 2,                         # 值:前 2 个
    # 'percent': False, (默认就是项目数)
    'format': format_top_2              # 应用的格式
})

'average':

'criteria': 'above', 'below', 'equalOrAbove', 'equalOrBelow', '1stdDevAbove', '1stdDevBelow', '2stdDevAbove', '2stdDevBelow', '3stdDevAbove', '3stdDevBelow'
'format': 应用的 Format 对象。

# 使用之前的分数数据 score_range = 'B2:B7'
format_above_avg_direct = workbook.add_format({
              'bg_color': '#B4C6E7'}) # 浅蓝色背景

worksheet.conditional_format(score_range, {
               # 对分数范围应用条件格式
    'type': 'average',                  # 类型:平均值
    'criteria': 'above',                # 标准:高于平均值
    'format': format_above_avg_direct   # 应用的格式
})
6.8 多区域条件格式 ('multi_range')

如果需要将同一个条件格式规则应用到多个不连续的单元格区域,可以使用 'multi_range' 选项。

# 假设我们想将 format_low_score 应用到 B2:B7 和 D2:D6 (之前的渐变条数据)
multi_range_str = f'{
              score_range} {
              gradient_range}' # 构建多区域字符串 "B2:B7 D2:D6"
# 或者使用列表: multi_range_list = [score_range, gradient_range]
# xlsxwriter 的 multi_range 通常期望一个空格分隔的字符串

worksheet.conditional_format(multi_range_str, {
             # 第一个参数是多区域字符串
    'type': 'cell',
    'criteria': '<',
    'value': 60, # 假设对两个区域都应用 <60 的规则
    'format': format_low_score, # 应用低分格式
    # 'multi_range': multi_range_str # 这个参数在这里是可选的,因为第一个参数已经是多区域了
                                  # 如果第一个参数是单个范围,而你想扩展到多范围,则用此参数
})

当第一个参数已经是多区域字符串时,'multi_range' 选项通常不需要再次指定。如果第一个参数是单个范围,而你想指定这是一个多区域规则的一部分,则使用 'multi_range'。通常直接将多区域字符串作为第一个参数更直观。

6.9 stop_if_true

当多个条件格式规则应用于同一个单元格时,Excel 会按顺序评估它们。如果一个规则的 'stop_if_true' 设置为 True,并且该规则的条件得到满足,那么后续(优先级较低的)规则将不会再对此单元格进行评估。

# ... (假设 format_high_score 和 format_mid_score 已定义) ...
# score_range = 'B2:B7'

# 规则1: 分数 >= 90,高亮,并停止后续规则
worksheet.conditional_format(score_range, {
            
    'type': 'cell',
    'criteria': '>=',
    'value': 90,
    'format': format_high_score,
    'stop_if_true': True # 如果满足此条件,则停止处理后续规则
})

# 规则2: 分数 >= 70 (如果上面的规则没有stop, 90分以上也会匹配这个)
worksheet.conditional_format(score_range, {
            
    'type': 'cell',
    'criteria': '>=',
    'value': 70,
    'format': format_mid_score
    # 如果没有 stop_if_true, 一个95分的单元格会先应用 format_high_score,
    # 然后再被 format_mid_score 覆盖 (如果 format_mid_score 的格式属性不同且优先)。
    # 有了 stop_if_true, 95分单元格应用 high_score 后就不会再尝试应用 mid_score。
})

stop_if_true 对于管理复杂条件格式规则的优先级和避免不期望的格式覆盖非常有用。

数据验证和条件格式是 xlsxwriter 中两个非常强大的工具,它们能够显著提升生成Excel文件的交互性、数据质量和可读性。通过灵活运用这些功能,你可以创建出高度专业和用户友好的电子表格。

© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容