Reputation: 11
I'm using openpyxl 2.5.6 and py 3.7.0. My goal is to read an Excel workbook and print both the contents and the formatting of each cell into a CSV. For instance, if a cell is blue with text "Data" then I would prepend a tag of "[blu]" to the cell value, printing to the CSV as "[blu]Data" and do this likewise with a cell that's bolded and for other fill colors, etc.
I can do this perfectly fine for cells with static formatting, but not with conditional formatting. My issue is that I don't know how to tell if a conditional formatting rule is applied. I found the conditional_formatting._cf_rules
dict, but I'm only seeing attributes like formula, priority, dxfId, and the dxf rules itself. I want to believe that the data of whether a cf rule is applied or not might stored somewhere, but I cannot find where it might be.
My code thus far looks something like this.
from openpyxl import load_workbook
wb = load_workbook('Workbook_Name.xlsx', data_only = True)
ws = wb['Worksheet1']
# Code that shows me each cf rule's formula, fill type, priority, etc
cellrangeslist = list(ws.conditional_formatting._cf_rules)
for cellrange in cellrangeslist:
print('{:30s}{:^10s}{:30s}'.format('----------------------------',str(cellrange.sqref),'----------------------------'))
for i in cellrange.cfRule:
print('{:10s}{:8s}{:40s}{:10s}{:10s}'.format(str(i.dxf.fill.bgColor.index), str(i.dxf.fill.bgColor.type), str(i.formula), str(i.stopIfTrue), str(i.priority)))
# This is where I want to be able to identify which cf rule is applied to a given cell
#
#
#
# Code that interprets cell styling into appropriate tags, e.g.
for r in ws.iter_rows(min_row = ws.min_row, max_row = ws.max_row, min_col = ws.min_column, max_col = ws.max_column):
for cell in r:
if cell.font.b == True:
cell.value = "[bold]"+cell.value
# Code to write each cell as a string literal to a CSV file
#
#
#
My Excel file looks like this,
And my cf rules look like this,
The console output I receive from the above code is
---------------------------- C1 ----------------------------
FF92D050 rgb ['$A1-$B1>0'] None 2
FFFF0000 rgb ['$A1-$B1<0'] None 1
The output shows the rules are properly there, but I'm wanting to know if there's a way to tell which of these rules, if any, are actually applied to the cell.
I have a growing suspicion that it's something calculated on runtime of Excel, so my alternative is to write an Excel formula interpreter, but I'm really hoping to avoid that by just about any means as I'm not sure I have the skill to do it.
Upvotes: 1
Views: 1447
Reputation: 6574
If you don't find a better option, following on from my comment this is an example of what you could do with Xlwings.
For the example output shown, A1 is a higher number than B1 so cell C1 is green.
A1 = 1236
B1 = 1235
If the A1 is changed back to 1234, C1 colour returns to red and if the same code is run after the workbook is saved the 'Colour applied to conditional format cell:' will be for 'Conditional Format 1' i.e. red
import xlwings as xw
from xlwings.constants import RgbColor
def colour_lookup(cfc):
cell_colour = (key for key, value in colour_dict.items() if value == cfc)
for key in cell_colour:
return key
colour_dict = { key: getattr(RgbColor, key) for key in dir(RgbColor) if not key.startswith('_') }
wb = xw.Book('test.xlsx')
ws = wb.sheets('Sheet1')
cf = ws['C1'].api.FormatConditions
print("Number of conditional formatting rules: " + str(cf._inner.Count))
print("Colour applied to conditional format cell:\n\tEnumerated: " +
str(cf._inner.Parent.DisplayFormat.Interior.Color))
print("\tRGBColor: " + colour_lookup(cf._inner.Parent.DisplayFormat.Interior.Color))
print("------------------------------------------------")
for idx, cf_detail in enumerate(cf, start=1):
print("Conditional Format " + str(idx))
print(cf_detail._inner.Formula1)
print(cf_detail._inner.Interior.Color)
print("\tRGBColor: " + colour_lookup(cf_detail._inner.Interior.Color))
print("")
Output
Number of conditional formatting rules: 2
Colour applied to conditional format cell:
Enumerated: 32768.0
RGBColor: rgbGreen
------------------------------------------------
Conditional Format 1
=$A1-$B1<0
255.0
RGBColor: rgbRed
Conditional Format 2
=$A1-$B1>0
32768.0
RGBColor: rgbGreen
Upvotes: 0