How can I get the RGB value of a given cell in a xlsx file using python?
Question:
Given a row and a column (plus sheet name) I need a way to extract the rgb value for a cell, as reported within excel, from a python script.
I’ve been using openpyxl. The following do not work consistently:
cell.fill.fgColor.rgb
cell.fill.bgColor.rgb
The following give the wrong value:
openpyxl.styles.colors.COLOR_INDEX[cell.fill.fgColor.index]
openpyxl.styles.colors.COLOR_INDEX[cell.fill.fgColor.index]
So I’m looking for another way to do it. Possible solutions need not be limited to the openpyxl library, as I’m willing to use another one.
Answers:
Consider win32com
library if using Python for Windows as it can access the Excel Object Library and use any of its methods and properties such as Workbooks.Open
, Interior.Color
, Workbook.Close
.
Using this interesting link for RGB value extraction, you can translate VBA to Python. Specifically, VBA’s integer division operator, the backslash,
, translates to Python’s double forward slash, //
and the modulo operator in VBA mod
becomes Python’s %
Below outputs the RGB of a yellow-colored cell. Both cell reference types are included. Entire routine is wrapped in a try/except/finally
to close background processes and release resources with or without a runtime error.
import win32com.client as win32
def getRGB(xlCell):
C = xlCell.Interior.Color
R = C % 256
G = C // 256 % 256
B = C // 65536 % 256
return "R={}, G={}, B={}".format(R, G, B)
try:
xlApp = win32.gencache.EnsureDispatch('Excel.Application')
wb = xlApp.Workbooks.Open('C:\Path\To\Workbook.xlsx')
ws = wb.Worksheets('RESULTS')
print(getRGB(ws.Range("A2"))) # A1 Style Reference
# R=255, G=255, B=0 (yellow-colored cell)
print(getRGB(ws.Cells(2,1))) # R1C1 Style Reference
# R=255, G=255, B=0 (yellow-colored cell)
wb.Close(False)
xlApp.Visible = False
except Exception as e:
print(e)
finally:
xlApp.Quit
ws = None
wb = None
xlApp = None
Aside, do note VBA is NOT part of MS Excel but an external component (by default connected to the software). It is just another language to connect to Excel’s object library as any programming language demonstrated here with Python can make a COM interface to this library.
The solution by @Parfait is excellent. But I improved getRGB()
, I think shifting will be better than redundant N divisions:
def getRGB(xlCell):
C = int(xlCell.Interior.Color)
R = C & 255
G = C >> 8 & 255
B = C >> 16 & 255
return "R={}, G={}, B={}".format(R, G, B)
So this isn’t an answer but it will be useful to folks who want a quick fix.
Using Microsoft Excel 2007 (but I believe most versions), if you go to Format Cells, choose Fill tab, and then select a color for Background color, the ten basic colors at the bottom always work for me.
However I’ve had only intermittent success with the gradient colors above those.
I mention this is a quick fix because if for your program, you want a simple way to bookmark cells for some function rather than the cell contents, you can still do this if you stick with the ten basic colors.
I found it easier doing that, rather than importing another library just to handle the extra colors I don’t need anyway.
Given a row and a column (plus sheet name) I need a way to extract the rgb value for a cell, as reported within excel, from a python script.
I’ve been using openpyxl. The following do not work consistently:
cell.fill.fgColor.rgb
cell.fill.bgColor.rgb
The following give the wrong value:
openpyxl.styles.colors.COLOR_INDEX[cell.fill.fgColor.index]
openpyxl.styles.colors.COLOR_INDEX[cell.fill.fgColor.index]
So I’m looking for another way to do it. Possible solutions need not be limited to the openpyxl library, as I’m willing to use another one.
Consider win32com
library if using Python for Windows as it can access the Excel Object Library and use any of its methods and properties such as Workbooks.Open
, Interior.Color
, Workbook.Close
.
Using this interesting link for RGB value extraction, you can translate VBA to Python. Specifically, VBA’s integer division operator, the backslash, , translates to Python’s double forward slash,
//
and the modulo operator in VBA mod
becomes Python’s %
Below outputs the RGB of a yellow-colored cell. Both cell reference types are included. Entire routine is wrapped in a try/except/finally
to close background processes and release resources with or without a runtime error.
import win32com.client as win32
def getRGB(xlCell):
C = xlCell.Interior.Color
R = C % 256
G = C // 256 % 256
B = C // 65536 % 256
return "R={}, G={}, B={}".format(R, G, B)
try:
xlApp = win32.gencache.EnsureDispatch('Excel.Application')
wb = xlApp.Workbooks.Open('C:\Path\To\Workbook.xlsx')
ws = wb.Worksheets('RESULTS')
print(getRGB(ws.Range("A2"))) # A1 Style Reference
# R=255, G=255, B=0 (yellow-colored cell)
print(getRGB(ws.Cells(2,1))) # R1C1 Style Reference
# R=255, G=255, B=0 (yellow-colored cell)
wb.Close(False)
xlApp.Visible = False
except Exception as e:
print(e)
finally:
xlApp.Quit
ws = None
wb = None
xlApp = None
Aside, do note VBA is NOT part of MS Excel but an external component (by default connected to the software). It is just another language to connect to Excel’s object library as any programming language demonstrated here with Python can make a COM interface to this library.
The solution by @Parfait is excellent. But I improved getRGB()
, I think shifting will be better than redundant N divisions:
def getRGB(xlCell):
C = int(xlCell.Interior.Color)
R = C & 255
G = C >> 8 & 255
B = C >> 16 & 255
return "R={}, G={}, B={}".format(R, G, B)
So this isn’t an answer but it will be useful to folks who want a quick fix.
Using Microsoft Excel 2007 (but I believe most versions), if you go to Format Cells, choose Fill tab, and then select a color for Background color, the ten basic colors at the bottom always work for me.
However I’ve had only intermittent success with the gradient colors above those.
I mention this is a quick fix because if for your program, you want a simple way to bookmark cells for some function rather than the cell contents, you can still do this if you stick with the ten basic colors.
I found it easier doing that, rather than importing another library just to handle the extra colors I don’t need anyway.