Python pandas openpyxl excel合并单元格,设置边框,背景色

Python pandas openpyxl excel合并单元格,设置边框,背景色

当涉及到比较复杂的设置背景色时,需要根据一些结果去对另一些单元格进行设置时,在行列上只能设置一种颜色,否则会被覆盖;
比如对 F列的 1,3,5设置红色,对F列的2,4,7设置绿色;
对G列的1,4,6设置红色,对G列的2,3,5设置黄色;

则只能先对表格,F、G列的红色背景单元格,设置公共的红色,然后保存到本地文件,用openpyxl读取在对其余的单元格分别设置颜色;

df_c = df_b.style.map(
        lambda x: 'background-color: red;', subset=pd.IndexSlice[[1, 3, 5], ['F']])
df_d = df_c.map(
        lambda x: 'background-color: red;', subset=pd.IndexSlice[[1, 4, 6], ['G']])

# openpyxl 遍历单元格对F列的2,4,7设置绿色;对G列的2,3,5设置黄色;

1. 效果图

pandas设置单元格背景色,字体颜色,边框
在这里插入图片描述

openpyxl合并单元格,设置丰富的字体
在这里插入图片描述

2. 源码

# excel数字与列名互转
import os

import numpy as np
import openpyxl
import pandas as pd
from openpyxl.styles import Side, Border, Font


# 列名转数字
def column_to_num(s: str) -> int:
    assert (isinstance(s, str))
    for i in s:
        if not 64 < ord(i) < 91:
            raise ValueError('Excel Column ValueError')
    return sum([(ord(n) - 64) * 26 ** i for i, n in enumerate(list(s)[::-1])])


# 数字转列名
def num_to_column(n: int) -> str:
    assert (isinstance(n, int) and n > 0)
    num = [chr(i) for i in range(65, 91)]
    ret = []
    while n > 0:
        n, m = divmod(n - 1, len(num))
        ret.append(num[m])
    return ''.join(ret[::-1])


def read_and_merge(file=None):
    np.random.seed(24)
    print([x[0] for x in np.random.randn(10, 1).tolist()])
    data = {'name': ['Lucy'] * 10,
            'title': ['美丽的花朵'] * 6 + ['面向未来'] * 4,
            '爱好': ['篮球', '足球', '羽毛球', '乒乓球', '网球', '游泳', '瑜伽', '阅读', '骑行', '爬山'],
            'Date': pd.to_datetime(['2017-05-31 20:53:00', '2017-05-11 20:53:00', '2017-05-08 20:53:00',
                                    '2017-06-06 20:53:00', '2017-06-06 20:53:00'] * 2),
            'A': np.linspace(1, 10, 10).tolist(),
            'B': [x[0] for x in np.random.randn(10, 1).tolist()],
            'C': [x[0] for x in np.random.randn(10, 1).tolist()],
            'D': [x[0] for x in np.random.randn(10, 1).tolist()],
            'E': [x[0] for x in np.random.randn(10, 1).tolist()],
            'F': [x[0] for x in np.random.randn(10, 1).tolist()],
            'G': [x[0] for x in np.random.randn(10, 1).tolist()],
            'H': [x[0] for x in np.random.randn(10, 1).tolist()]
            }
    df_b = pd.DataFrame(data)
    print(df_b)

    # 定义一个函数来设置样式,将文本居中对齐和上下居中对齐
    def set_cell_style(value):
        style = 'text-align: center; vertical-align: middle; border: solid 1px black; '
        return style

    def set_cell_color(val):
        if val < 4:
            color = 'green'
        elif val < 8:
            color = 'yellow'
        else:
            color = 'red'
        return 'background-color: %s' % color

    def color_negative_red(val):
        """
        Takes a scalar and returns a string with
        the css property `'color: red'` for negative
        strings, black otherwise.
        """
        # print('---val:', val)
        # color_list = []
        # for val in vals:
        #     color = 'color: %s' % ('red' if val < 0 else 'black')
        #     color_list.append(color)
        # return color_list
        return 'color: %s' % ('red' if val < 0 else 'black')

    # 使用Styler对象来应用样式,同时设置文本的居中对齐和上下居中对齐
    df_c = df_b.style.map(lambda x: set_cell_style(x)).map(lambda x: set_cell_color(x), subset=['A']).map(
        lambda x: color_negative_red(x), subset=pd.IndexSlice[[1, 3, 5, 7, 9], ['B', 'C', 'D', 'G']])

    # 保存到新文件
    df_c.to_excel('temp.xlsx', index=False, engine='openpyxl')

    # 合并单元格
    wb = openpyxl.load_workbook('temp.xlsx')
    ws = wb.active
    # 第一列连续相同值的合并单元格
    # 获取第一列数据
    type_list = []
    i = 2
    while True:
        r = ws.cell(i, 1).value
        if r:
            type_list.append(r)
        else:
            break
        i += 1

    # 判断合并单元格的始末位置
    s = 0
    e = 0
    flag = type_list[0]
    for i in range(len(type_list)):
        if type_list[i] != flag:
            flag = type_list[i]
            e = i - 1
            if e >= s:
                ws.merge_cells("A" + str(s + 2) + ":A" + str(e + 2))
                s = e + 1
        if i == len(type_list) - 1:
            e = i
            ws.merge_cells("A" + str(s + 2) + ":A" + str(e + 2))

    ### 合并列
    num_rows = ws.max_row

    combine_columns = {
        ('F', 'G')
    }

    for i in range(num_rows):
        for columns in combine_columns:
            start, end = columns
            ws.merge_cells(start + str(i + 1) + ":" + end + str(i + 1))

    # 定义不同列的字体配置
    font_columns = [
        (['A', 'B', 'C'], Font(name='Times New Roman', size=9, bold=True)),
        (['D', 'E'], Font(name='Times New Roman', size=12)),
        (['F', 'G'], Font(name='宋体', size=12)),
    ]

    # 设置列的字体样式
    for labels, font in font_columns:
        for label in labels:
            for cell in ws[label]:
                cell.font = font
                # XX结尾的数据改成红色
                if cell.value and str(cell.value).endswith("XX"):
                    cell.value = cell.value[:-2]
                    cell.font = Font(name='Times New Roman', size=12, bold=True, color="FF0000", )
    # 创建一个边框样式
    border_style = Border(
        left=Side(border_style='thin', color='000000'),
        right=Side(border_style='thin', color='000000'),
        top=Side(border_style='thin', color='000000'),
        bottom=Side(border_style='thin', color='000000')
    )

    # 遍历工作表中的所有单元格并应用边框样式
    for row in ws.iter_rows():
        for cell in row:
            cell.border = border_style
    wb.save('output_excel_file.xlsx')

    try:
        os.remove('temp.xlsx')
    except FileNotFoundError:
        pass
    except Exception as e:
        pass
    return 'output_excel_file.xlsx'


if __name__ == '__main__':
    for i in range(1, 100):
        column_name = num_to_column(i)
        print(i, column_name, column_to_num(column_name))

    read_and_merge()

参考

<think>好的,用户的问题是关于如何使用Python处理包含合并单元Excel文件,特别是用pandasopenpyxl来解决。首先,我需要回忆一下相关的库和它们的文档。记得pandas主要用于数据处理,而openpyxl可以处理Excel文件的式,包括合并单元。 用户提到了pandasopenpyxl,可能还需要用到这两个库的组合。因为pandas读取合并单元时,默认只会填充第一个单元格的值,其他合并区域是空的,这会导致数据处理的问题。所以用户可能需要先读取合并单元的信息,然后填充这些空值。 接下来,我应该考虑如何用openpyxl来检测合并单元格区域。openpyxl的worksheet.merged_cells属性可以提供合并范围的信息。然后遍历这些合并区域,记录每个区域的起始行和列,以及合并后的值。之后,用pandas读取整个工作表的数据,但这时候合并区域的其他单元格是NaN,需要用前面记录的值来填充这些NaN。 另外,用户可能还需要处理如何将处理后的数据保存回Excel,并保持合并单元式。这时候可能需要使用openpyxl合并单元功能,先处理数据,再应用合并。同时,用户可能还需要设置边框背景色,这部分可能需要参考引用中的内容,使用openpyxl的样式设置。 还需要注意,当用户读取合并单元时,pandas默认的处理方式,以及如何正确获取合并后的值。例如,合并单元A1到C3,只有A1有值,其他都是空的。所以需要在读取数据后,根据合并区域的信息,将空值替换为A1的值。 可能还需要考虑性能问题,如果Excel文件很大,处理合并单元可能会比较慢。但用户的问题中没有提到性能,所以暂时先不考虑优化,先解决基本功能。 总结步骤应该是:1. 使用openpyxl读取合并区域的信息。2. 使用pandas读取数据。3. 根据合并区域信息填充NaN值。4. 保存处理后的数据,可能需要重新应用合并单元式,如果需要的话。 然后,用户可能需要生成相关问题,比如如何设置边框背景色,或者如何将处理后的数据保存回Excel并保持合并式。根据引用中的内容,引用1和2提到了合并单元和样式设置,所以相关问题可以围绕这些展开。</think>### 解答:Python处理合并单元Excel文件 #### 1. **读取合并单元的数据** 使用`openpyxl`获取合并单元的坐标范围,再结合`pandas`填充空值: ```python from openpyxl import load_workbook import pandas as pd # 读取Excel文件 wb = load_workbook("test.xlsx") ws = wb.active # 获取所有合并单元的坐标范围 merged_ranges = [str(merge) for merge in ws.merged_cells.ranges] # 用pandas读取数据(此时合并区域仅首有值,其余为NaN) df = pd.read_excel("test.xlsx", sheet_name="Sheet1", header=0) # 填充合并区域的空值 for range_str in merged_ranges: min_col, min_row, max_col, max_row = ws.merged_cells[range_str].bounds value = ws.cell(row=min_row, column=min_col).value for row in range(min_row, max_row + 1): for col in range(min_col, max_col + 1): df.iloc[row-1, col-1] = value # pandas行/列索引从0开始 ``` #### 2. **保存数据并保留合并式** 若需将处理后的数据导出为带合并单元Excel文件: ```python from openpyxl.styles import Border, Side, PatternFill # 创建新工作簿并写入数据 wb_new = openpyxl.Workbook() ws_new = wb_new.active # 将DataFrame数据写入工作表 for row in df.itertuples(index=False): ws_new.append(row) # 重新合并单元设置样式 for range_str in merged_ranges: ws_new.merge_cells(range_str) # 设置边框(示例) border = Border(left=Side(style='thin'), right=Side(style='thin'), top=Side(style='thin'), bottom=Side(style='thin')) for row in ws_new[range_str]: for cell in row: cell.border = border # 设置背景色(示例) fill = PatternFill(start_color="FFFF00", fill_type="solid") ws_new[range_str.split(':')[0]].fill = fill wb_new.save("processed.xlsx") ``` #### 3. **关键说明** - **合并单元读取**:`openpyxl`通过`merged_cells.ranges`获取所有合并区域,遍历后提取其左上角的值填充至整个区域[^3]。 - **样式保留**:合并单元边框背景色需通过`openpyxl.styles`重新设置,直接保存`DataFrame`无法保留原式[^1][^2]。 - **性能优化**:若数据量大,建议直接操作`openpyxl`而非结合`pandas`,以避免内存开销。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序媛一枚~

您的鼓励是我创作的最大动力。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值