在 openpyxl 中为 Excel 中列的数值分配颜色的问题

问题描述 投票:0回答:1

我有这个 df:

             NOMBRE ESTACION DEPARTAMENTO  ... APNoviembre APDiciembre
0                   ARAMANGO     AMAZONAS  ...  -15.463042    3.254973
1                BAGUA CHICA     AMAZONAS  ...   -8.193005    7.855943
2                CHACHAPOYAS     AMAZONAS  ...  -11.803714   -9.552846
3                   CHIRIACO     AMAZONAS  ...         NaN         NaN
4                  EL PINTOR     AMAZONAS  ...     8.99654    10.01199
..                       ...          ...  ...         ...         ...
529                      ITE        TACNA  ...       500.0        25.0
530                 VILACOTA        TACNA  ...  -14.666667    2.389078
531                  LA CRUZ       TUMBES  ...  -26.666667      78.125
532  LAS PALMERAS DE UCAYALI      UCAYALI  ...    8.700102      6.0981
533            SAN ALEJANDRO      UCAYALI  ...  -23.723229   -24.59382

[534 rows x 20 columns]

我只想对确定范围内的数值(从9到最后一列的列)进行着色并将其导出到excel。所以我做了这个代码:

#Export the df to excel
with pd.ExcelWriter("path/to/file/df.xlsx") as writer:   
    df.to_excel(writer,'ANOM', index=False)


import openpyxl
from openpyxl.styles import PatternFill
import pandas as pd
wb = openpyxl.load_workbook("path/to/file/df.xlsx")
ws = wb.active #Name of the working sheet


fill_cell1 = PatternFill(patternType='solid',
                           fgColor='C2523C')
fill_cell2 = PatternFill(patternType='solid',
                           fgColor='E8951A')
fill_cell3 = PatternFill(patternType='solid',
                           fgColor='FAEA05')
fill_cell4 = PatternFill(patternType='solid',
                           fgColor='FFFFFF')
fill_cell5 = PatternFill(patternType='solid',
                           fgColor='B8F500')
fill_cell6 = PatternFill(patternType='solid',
                           fgColor='400000')
fill_cell7 = PatternFill(patternType='solid',
                           fgColor='19B04D')

fill_cell8 = PatternFill(patternType='solid',
                           fgColor='198759')
fill_cell9 = PatternFill(patternType='solid',
                           fgColor='089EAD')
fill_cell10 = PatternFill(patternType='solid',
                           fgColor='2B61A8')
fill_cell11 = PatternFill(patternType='solid',
                           fgColor='0B2C7A')
fill_cell12 = PatternFill(patternType='solid',
                           fgColor='000000')

for row in ws.rows:
    for i in range(8,8+int((ws.max_column-8)/2)):
        if row[i].value > 800:
            row[i].fill = fill_cell11
            row[int(i+(ws.max_column-8)/2)].fill = fill_cell11
        elif 400 <= row[i].value <= 800:
            row[i].fill = fill_cell10
            row[int(i+(ws.max_column-8)/2)].fill = fill_cell10
        elif 200 <= row[i].value < 400:
            row[i].fill = fill_cell9
            row[int(i+(ws.max_column-8)/2)].fill = fill_cell9
        elif 100 <= row[i].value < 200:
            row[i].fill = fill_cell8
            row[int(i+(ws.max_column-8)/2)].fill = fill_cell8
        elif 60 <= row[i].value < 100:
            row[i].fill = fill_cell7
            row[int(i+(ws.max_column-8)/2)].fill = fill_cell7
        elif 30 <= row[i].value < 60:
            row[i].fill = fill_cell6
            row[int(i+(ws.max_column-8)/2)].fill = fill_cell6
        elif 15 <= row[i].value < 30:
            row[i].fill = fill_cell5
            row[int(i+(ws.max_column-8)/2)].fill = fill_cell5
        elif -15 <= row[i].value < 15:
            row[i].fill = fill_cell4
            row[int(i+(ws.max_column-8)/2)].fill = fill_cell4
        elif -30 <= row[i].value < -15:
            row[i].fill = fill_cell3
            row[int(i+(ws.max_column-8)/2)].fill = fill_cell3
        elif -60 <= row[i].value < -30:
            row[i].fill = fill_cell2
            row[int(i+(ws.max_column-8)/2)].fill = fill_cell2
        elif -100 <= row[i].value < -60:
            row[i].fill = fill_cell1
            row[int(i+(ws.max_column-8)/2)].fill = fill_cell1
        elif row[i].value == "NaN" or row[i].value == "" or row[i].value == None:
            row[i].fill = fill_cell12
            row[int(i+(ws.max_column-8)/2)].fill = fill_cell12

wb.save("path/to/file/df_colored.xlsx")

但是我得到了这个错误:

TypeError: '>' not supported between instances of 'str' and 'int'

我知道错误是因为 openpyxl 将

row[i].value
作为字符串标题,而不是数值,但我不明白为什么。我将
range(8,8+int((ws.max_column-8)/2))
中的8替换为9、10甚至11,它只适用于19,但我没有得到带有颜色的excel文件。有人可以帮助我很好地理解 ws 中的行并为此提供一些解决方案。 提前致谢。

python openpyxl
1个回答
1
投票

是的,您正在尝试将字符串(列标题中的文本)与给出错误的 int(第一个检查值 800)进行比较。 为什么不使用 iter_rows 并跳过第一行,这样就不用担心标题了?
但是,您还需要其他字符串值“NaN”、“”和空单元格,因此仅跳过标题并不能避免此错误。因此,如果不为字符串应用单元格颜色,则可以检查单元格值是浮点数还是整数,如果是,则检查填充颜色的范围。

注意: 使用单元格类型检查意味着将

min_row
设置为 2 是不必要的,因为标头无论如何都会被两个标准检查拒绝,但它仍然可以节省循环行。

还要注意检查单元格是 None 不要使用 '==' 语法应该是;

cell.value is None

为了减少行数,我将单元格填充颜色操作更改为使用字典和函数,而不是设置多个 PatternFill 行。

...
wb = openpyxl.load_workbook("path/to/file/df.xlsx")
ws = wb.active  # Name of the working sheet

def add_colour(cell, colour):
    ### fill cell based on the colour key
    cell.fill = PatternFill(patternType='solid', fgColor=colour)


### Create colour dictionary
colour_dict = {1: 'C2523C', 2: 'E8951A', 3: 'FAEA05', 4: 'FFFFFF',
               5:'B8F500', 6: '400000', 7: '19B04D', 8: '198759',
               9: '089EAD', 10: '2B61A8', 11: '0B2C7A', 12: '000000'}

### loop rows in columns skipping row 1
for row in ws.iter_rows(min_col=9, max_col=8+int((ws.max_column-8)/2), min_row=2):
    for cell in row:
        c_value = cell.value
        ### Check if the cell value is integer or float
        ### If so check the value range and set fill colour 
        if isinstance(c_value, (int, float)):
            if c_value > 800:
                add_colour(cell, colour_dict[11])
            elif 400 <= c_value <= 800:
                add_colour(cell, colour_dict[10])
            elif 200 <= c_value < 400:
                add_colour(cell, colour_dict[9])
            elif 100 <= c_value < 200:
                add_colour(cell, colour_dict[8])
            elif 60 <= c_value < 100:
                add_colour(cell, colour_dict[7])
            elif 30 <= c_value < 60:
                add_colour(cell, colour_dict[6])
            elif 15 <= c_value < 30:
                add_colour(cell, colour_dict[5])
            elif -15 <= c_value < 15:
                add_colour(cell, colour_dict[4])
            elif -30 <= c_value < -15:
                add_colour(cell, colour_dict[3])
            elif -60 <= c_value < -30:
                add_colour(cell, colour_dict[2])
            elif -100 <= c_value < -60:
                add_colour(cell, colour_dict[1])

        ### This elif is on the same level as the int float test
        ### If cell value is not int or float check the following strings or empty cell 
        elif c_value == "NaN" or c_value == "" or c_value is None:
            add_colour(cell, colour_dict[12])

wb.save("path/to/file/df_colored.xlsx")
© www.soinside.com 2019 - 2024. All rights reserved.