Setting styles in Openpyxl - python

I need advice on setting styles in Openpyxl.
I see that the NumberFormat of a cell can be set, but I also require setting of font colors and attributes (bold etc). There is a style.py class but it seems I can't set the style attribute of a cell, and I don't really want to start tinkering with the openpyxl source code.
Has anyone found a solution to this?

As of openpyxl version 1.5.7, I have successfully applied the following worksheet style options...
from openpyxl.reader.excel import load_workbook
from openpyxl.workbook import Workbook
from openpyxl.styles import Color, Fill
from openpyxl.cell import Cell
# Load the workbook...
book = load_workbook('foo.xlsx')
# define ws here, in this case I pick the first worksheet in the workbook...
# NOTE: openpyxl has other ways to select a specific worksheet (i.e. by name
# via book.get_sheet_by_name('someWorksheetName'))
ws = book.worksheets[0]
## ws is a openpypxl worksheet object
_cell = ws.cell('C1')
# Font properties
_cell.style.font.color.index = Color.GREEN
_cell.style.font.name = 'Arial'
_cell.style.font.size = 8
_cell.style.font.bold = True
_cell.style.alignment.wrap_text = True
# Cell background color
_cell.style.fill.fill_type = Fill.FILL_SOLID
_cell.style.fill.start_color.index = Color.DARKRED
# You should only modify column dimensions after you have written a cell in
# the column. Perfect world: write column dimensions once per column
#
ws.column_dimensions["C"].width = 60.0
FYI, you can find the names of the colors in openpyxl/style.py... I sometimes I patch in extra colors from the X11 color names
class Color(HashableObject):
"""Named colors for use in styles."""
BLACK = 'FF000000'
WHITE = 'FFFFFFFF'
RED = 'FFFF0000'
DARKRED = 'FF800000'
BLUE = 'FF0000FF'
DARKBLUE = 'FF000080'
GREEN = 'FF00FF00'
DARKGREEN = 'FF008000'
YELLOW = 'FFFFFF00'
DARKYELLOW = 'FF808000'

For openpyxl version 2.4.1 and above use below code to set font color:
from openpyxl.styles import Font
from openpyxl.styles.colors import Color
ws1['A1'].font = Font(color = "FF0000")
hex codes for various colors can be found at:
http://dmcritchie.mvps.org/excel/colors.htm

As of openpyxl 2.0, styles are immutable.
If you have a cell, you can (e.g.) set bold text by:
cell.style = cell.style.copy(font=cell.style.font.copy(bold=True))
Yes, this is annoying.

As of openpyxl 2.0, setting cell styles is done by creating new style objects and by assigning them to properties of a cell.
There are several style objects: Font, PatternFill, Border, and Alignment. See the doc.
To change a style property of a cell, first you either have to copy the existing style object from the cell and change the value of the property or you have to create a new style object with the desired settings. Then, assign the new style object to the cell.
Example of setting the font to bold and italic of cell A1:
from openpyxl import Workbook
from openpyxl.styles import Font
# Create workbook
wb = Workbook()
# Select active sheet
ws = wb.active()
# Select cell A1
cell = ws['A1']
# Make the text of the cell bold and italic
cell.font = cell.font.copy(bold=True, italic=True)

This seems like a feature that has changed a few times. I am using openpyxl 2.5.0, and I was able to set the strike-through option this way:
new_font = copy(cell.font)
new_font.strike = True
cell.font = new_font
It seems like earlier versions (1.9 to 2.4?) had a copy method on the font that is now deprecated and raises a warning:
cell.font = cell.font.copy(strike=True)
Versions up to 1.8 had mutable fonts, so you could just do this:
cell.font.strike=True
That now raises an error.

New 2021 Updated Way of Changing FONT in OpenPyXl:
sheet.cell.font = Font(size=23, underline='single', color='FFBB00', bold=True, italic=True)
Full Code:
import openpyxl # Connect the library
from openpyxl import Workbook
from openpyxl.styles import PatternFill # Connect cell styles
from openpyxl.workbook import Workbook
from openpyxl.styles import Font, Fill # Connect styles for text
from openpyxl.styles import colors # Connect colors for text and cells
wb = openpyxl.Workbook() # Create book
work_sheet = wb.create_sheet(title='Testsheet') # Created a sheet with a name and made it active
work_sheet['A1'] = 'Test text'
work_sheet_a1 = work_sheet['A5'] # Created a variable that contains cell A1 with the existing text
work_sheet_a1.font = Font(size=23, underline='single', color='FFBB00', bold=True,
italic=True) # We apply the following parameters to the text: size - 23, underline, color = FFBB00 (text color is specified in RGB), bold, oblique. If we do not need a bold font, we use the construction: bold = False. We act similarly if we do not need an oblique font: italic = False.
# Important:
# if necessary, the possibility of using standard colors is included in the styles, but the code in this case will look different:
work_sheet_a1.font = Font(size=23, underline='single', color=colors.RED, bold=True,
italic=True) # what color = colors.RED — color prescribed in styles
work_sheet_a1.fill = PatternFill(fill_type='solid', start_color='ff8327',
end_color='ff8327') # This code allows you to do design color cells

Like openpyxl doc said:
This is an open source project, maintained by volunteers in their spare time. This may well mean that particular features or functions that you would like are missing.
I checked openpyxl source code, found that:
Till openpyxl 1.8.x, styles are mutable. Their attribute can be assigned directly like this:
from openpyxl.workbook import Workbook
from openpyxl.style import Color
wb = Workbook()
ws = wb.active
ws['A1'].style.font.color.index = Color.RED
However from of openpyxl 1.9, styles are immutable.
Styles are shared between objects and once they have been assigned they cannot be changed. This stops unwanted side-effects such as changing the style for lots of cells when instead of only one.
To create a new style object, you can assign it directly, or copy one from an existing cell's style with new attributes, answer to the question as an example(forgive my Chinese English):
from openpyxl.styles import colors
from openpyxl.styles import Font, Color
from openpyxl import Workbook
wb = Workbook()
ws = wb.active
a1 = ws['A1']
d4 = ws['D4']
# create a new style with required attributes
ft_red = Font(color=colors.RED)
a1.font = ft_red
# you can also do it with function copy
ft_red_bold = ft_red.copy(bold=True)
# you can copy from a cell's style with required attributes
ft_red_sigle_underline = a1.font.copy(underline="single")
d4.font = ft_red_bold
# apply style to column E
col_e = ws.column_dimensions['E']
col_e.font = ft_red_sigle_underline
A cell' style contains these attributes: font, fill, border, alignment, protection and number_format. Check openpyxl.styles.
They are similar and should be created as an object, except number_format, its value is string type.
Some pre-defined number formats are available, number formats can also be defined in string type. Check openpyxl.styles.numbers.
from openpyxl.styles import numbers
# use pre-defined values
ws.cell['T49'].number_format = numbers.FORMAT_GENERAL
ws.cell(row=2, column=4).number_format = numbers.FORMAT_DATE_XLSX15
# use strings
ws.cell['T57'].number_format = 'General'
ws.cell(row=3, column=5).number_format = 'd-mmm-yy'
ws.cell['E5'].number_format = '0.00'
ws.cell['E50'].number_format = '0.00%'
ws.cell['E100'].number_format = '_ * #,##0_ ;_ * -#,##0_ ;_ * "-"??_ ;_ #_ '

As of openpyxl-1.7.0 you can do this too:
cell.style.fill.start_color.index = "FF124191"
I've got a couple of helper functions which set a style on a given cell - things like headers, footers etc.

You can define a common style then you can apply the same to any cell or range.
Define Style:
Apply on a cell.

This worked for me (font colour + bold font):
from openpyxl.styles import colors
from openpyxl.styles import Font, Color
from openpyxl import Workbook
wb = Workbook()
ws = wb['SheetName']
ws.cell(row_number,column_number).font = Font(color = "0000FF",bold = True)

Related

Align cell content in excel using python

I am struggling to set the alignment for data in excel using python
My python function loads data from excel into a pandas dataframe, calculates some new columns, then adds these columns to the original sheet. This all works well, but I now want to tidy up the result.
I can set italics / bold etc using
sheet['E1:J24'].font.bold = True
sheet['E1:J24'].font.italic = True
But I cannot set the alignment properly. I have tried the following, and several other suggestions I found online, but none of them seems to work.
sheet['E1:J24'].alignment = Alignment(horizontal="center")
Any help would be appreciated.
Update to question,
With further on-line searching I came upon this line of code which successfully adjusts the alignment.
sheet.range(f'$E1:J24').api.HorizontalAlignment = -4152
I think the problem is that I connected to the worksheet using xlwings and then tried to use openpyxl to format it. Jupyter didn't give an error because I had imported 'Alignment' from openpyxl
Note, for alignments use setting as follows
center = -4108
right = -4152
Left = -4131
Not sure where the numbers come from
Use 'VerticalAlignment' and/or 'HorizontalAlignment'.
Import VAlign, HAlign from the Xlwings constants to use the name or just use the Excel code. I have copied these into the comments for your information.
import xlwings as xw
from xlwings.constants import VAlign, HAlign
### Xlwings constants
"""
VAlign Class
xlVAlignBottom = -4107
xlVAlignCenter = -4108
xlVAlignDistributed = -4117
xlVAlignJustify = -4130
xlVAlignTop = -4160
HAlign Class
xlHAlignCenter = -4108
xlHAlignCenterAcrossSelection = 7
xlHAlignDistributed = -4117
xlHAlignFill = 5
xlHAlignGeneral = 1
xlHAlignJustify = -4130
xlHAlignLeft = -4131
xlHAlignRight = -4152
"""
path = "foo.xlsx"
with xw.App() as app:
wb = xw.Book(path)
ws = wb.sheets[0]
# Align text vertically
ws.range(1, 1).api.VerticalAlignment = -4160
ws.range(1, 2).api.VerticalAlignment = VAlign.xlVAlignCenter
ws.range(1, 3).api.VerticalAlignment = VAlign.xlVAlignBottom
# Align text horizontally
ws.range(2, 1).api.HorizontalAlignment = HAlign.xlHAlignLeft
ws.range(2, 2).api.HorizontalAlignment = HAlign.xlHAlignCenter
ws.range(2, 3).api.HorizontalAlignment = -4152
wb.save(path)
wb.close()

Python openpyxl.formatting.rule and Excel formula with variable as value

I don’t know if somebody have already used the openpyxl.formatting.rule and Excel formula containing a variable as value
I cannot find a solution to put a variable as value in an Excel formula
When I set the real value, the formula is well taken into account and the result is the expected one
When I set a variable (as an argument of the function), the formula doesn’t recognize the value which is a string and my Excel file isn’t updated as expected.
import openpyxl
from openpyxl.utils import get_column_letter
from openpyxl.worksheet.dimensions import ColumnDimension, DimensionHolder
from openpyxl.styles import Color, Fill, Font, PatternFill
from openpyxl.cell import Cell
from openpyxl.styles.differential import DifferentialStyle
from openpyxl.formatting.rule import Rule
...
def add_title_in_sheet(worksheet, title, ref_build,size_value):
…
# for lines containing values for reference build
reference_fill = PatternFill(bgColor="00FFFF")
dxf = DifferentialStyle(fill=reference_fill)
rule2 = Rule( type="expression", dxf=dxf)
**rule2.formula = ['ISNUMBER(SEARCH("2021 R2_B20210527", $C5))'] # Work well**
**rule2.formula = ['ISNUMBER(SEARCH(ref_build, $C5))'] # Cannot work**
worksheet.conditional_formatting.add('A5:G200', rule2)
In main python program:
wb = writer.book
add_title_in_sheet( wb['Measures'], "List of measures","2021 R2_B20210527", 14 )
Note: I’ve tried many writing but all not worked
rule2.formula = ['ISNUMBER(SEARCH(ref_build, $C5))']
ou
rule2.formula = ['ISNUMBER(SEARCH("ref_build”, $C5))']
ou
rule2.formula = ['ISNUMBER(SEARCH({ref_build}, $C5))']
ou
rule2.formula = ['ISNUMBER(SEARCH(‘ref_build’, $C5))']
ou
rule2.formula = ['ISNUMBER(SEARCH(“{ref_build}”, $C5))']
Who has a solution?
Why I don't put directly the value? It is because it is retrieved in an Excel cell before.
Note: this function is used in a python program using panda, dataframe, read_excel with openpyxl engine.
Thanks a for your help,

Using xlsxwriter to colour an individual cell

I want to use xlsxwriter to set properties like background color, font color, font type, font size etc. for one single cell only.
I am finding methods like .set_rows() and .set_columns(). Is there any way to access only 1 particular cell.
Thanks in advance
You can use xlswriter library in order to format individual formats like in the following example
import xlsxwriter
# Create a new Excel file and add a worksheet.
wb = xlsxwriter.Workbook('mydocument.xlsx')
ws = wb.add_worksheet()
# Widen the first two columns
ws.set_column('A:B', 20)
# Write a non-formatted text
ws.write('A1', 'fox jumped')
# Define a format and add some attributes in order to highlight the related cells
frm1 = wb.add_format({'bold': True})
frm1.set_font_color('#FF0000')
frm1.set_bg_color('#808080')
ws.write('A2', 'over the lazy dog', frm1)
# Define a format and add attributes at once
frm2 = wb.add_format({'italic': True,'border': 1,'bg_color': '#FFC7CE','font_color': '#9C0006'})
ws.write('B1','over the lazy dog',frm2)
wb.close()

Fill cells with colors using openpyxl?

I am currently using openpyxl v2.2.2 for Python 2.7 and i wanted to set colors to cells. I have used the following imports
import openpyxl,
from openpyxl import Workbook
from openpyxl.styles import Color, PatternFill, Font, Border
from openpyxl.styles import colors
from openpyxl.cell import Cell
and the following is the code I tried using:
wb = openpyxl.Workbook()
ws = wb.active
redFill = PatternFill(start_color='FFFF0000',
end_color='FFFF0000',
fill_type='solid')
ws['A1'].style = redFill
but I get the following error:
Traceback (most recent call last)
self.font = value.font.copy()
AttributeError: 'PatternFill' object has no attribute 'font'
Any idea on how to set cell A1 (or any other cells) with colors using openpyxl?
I believe the issue is that you're trying to assign a fill object to a style.
ws['A1'].fill = redFill should work fine.
The API for styles changed once again. What worked for me was
my_red = openpyxl.styles.colors.Color(rgb='00FF0000')
my_fill = openpyxl.styles.fills.PatternFill(patternType='solid', fgColor=my_red)
cell.fill = my_fill
Color is an alpha RGB hex color. You can pass it in as 'rrggbb' with a default alpha of 00 or specify the alpha with 'aarrggbb'. A bunch of colors are defined as constants in openpyxl.styles.colors if you need to grab one quickly.
This worked for me. They changed things and most of the help you see on the internet is for older versions of the openpyxl library from what I am seeing.
# Change background color
xls_cell.style = Style(fill=PatternFill(patternType='solid',
fill_type='solid',
fgColor=Color('C4C4C4')))
in python 3.x
wb = openpyxl.Workbook()
ws = wb.active
redFill = PatternFill(start_color='FFFF0000',
end_color='FFFF0000',
fill_type='solid')
ws['A1'].fill = redFill
that working but i dont know in python 2.x i hope working
just put ws['A1'].fill=redFill
from openpyxl import Workbook, load_workbook
from openpyxl.styles import PatternFill
_file_name = "Test.xlsx"
_sheet_name = "Test_Sheet"
def new_workbook(_file_name, _sheet_name):
wb = Workbook() # Workbook Object
ws = wb.active # Gets the active worksheet
ws.title = _sheet_name # Name the active worksheet
# Writing the header columns
ws['A1'] = 'Name'
ws['B1'] = 'Class'
ws['C1'] = 'Section'
ws['D1'] = 'Marks'
ws['E1'] = 'Age'
col_range = ws.max_column # get max columns in the worksheet
# formatting the header columns, filling red color
for col in range(1, col_range + 1):
cell_header = ws.cell(1, col)
cell_header.fill = PatternFill(start_color='FF0000', end_color='FF0000', fill_type="solid") #used hex code for red color
wb.save(_file_name) # save the workbook
wb.close() # close the workbook
if __name__ == '__main__':
new_workbook(_file_name, _sheet_name)
Result -
What I would do for Excel is this:
from openpyxl import Workbook, load_workbook
from openpyxl.styles import PatternFill
wb = load_workbook("test.xlsx")
ws = wb.active
ws["A1"].fill = PatternFill("solid", start_color="FFA500")
You can replace "A1" with another cell and start_color has to be a hex color.
To fill a range of rows/columns, do this
for cell in ws['A1:A100']:
cell[0].fill = redFill
To fill all rows of a column
for cell in ws['A1:{}'.format(ws.max_row)]:
cell[0].fill = redFill
Use a nested for loop to fill a two dimensional range.
Python 3.9
import openpyxl as op
fill_gen = op.styles.PatternFill(fill_type='solid',
start_color='FFFFFF',
end_color='FFFFFF')
for row in ws["A1:BB50"]:
for cell in row:
cell.fill = fill_gen

Horizontal text alignment in openpyxl

I'm trying to change the text alignment to the center of 2 merged cells. I've found some answers that didn't work for my case:
currentCell = ws.cell('A1')
currentCell.style.alignment.horizontal = 'center' #TypeError: cannot set horizontal attribute
#or
currentCell.style.alignment.vertical = Alignment.HORIZONTAL_CENTER #AttributeError: type object 'Alignment' has no attribute 'HORIZONTAL_CENTER'
both didn't work, is there any other way to do it?
yes, there is a way to do this with openpyxl:
from openpyxl.styles import Alignment
currentCell = ws.cell('A1') #or currentCell = ws['A1']
currentCell.alignment = Alignment(horizontal='center')
hope this will help you
This is what finally worked for me with the latest version from PIP (2.2.5)
# center all cells
for col in w_sheet.columns:
for cell in col:
# openpyxl styles aren't mutable,
# so you have to create a copy of the style, modify the copy, then set it back
alignment_obj = cell.alignment.copy(horizontal='center', vertical='center')
cell.alignment = alignment_obj
Update:
As of openpyxl version 2.4.0 (~2016) the .copy() method is deprecated for StyleProxy objects.
Try changing the last two lines to:
from copy import copy
alignment_obj = copy(cell.alignment)
alignment_obj.horizontal = 'center'
alignment_obj.vertical = 'center'
cell.alignment = alignment_obj
None of the other solutions worked for me, since my solution requires openpyxl, and at least in 2.1.5 cell.alignment can't be set directly.
from openpyxl.styles import Style, Alignment
cell = ws.cell('A1')
cell.style = cell.style.copy(alignment=Alignment(horizontal='center'))
The above copies the current style and replaces the alignment.
You can also create a whole new style - with any values not specified taking the default values from https://openpyxl.readthedocs.org/en/latest/styles.html
cell.style = Style(alignment=Alignment(horizontal='center'),font=Font(bold=True))
# or - a tidier way
vals = {'alignment':Alignment(horizontal='center'),
'font':Font(bold=True),
}
new_style = Style(**vals)
cell.style = new_style
its my first time posting anything here.
So i found a way to align text using openpyxl, Alignment
i=3
while i < 253:
cellc = ws.cell(row=i, column= 3)
cellc.alignment = Alignment(horizontal="right")
i+=1
I set i to be the start point then the len of my column
I found the following code to be a pretty simple way to format every cell in your worksheet:
tot_rows = ws.max_row #get max row number
tot_cols = ws.max_column #get max column number
cols = range(1,tot_cols) #turns previous variables into iterables
rows = range(1,tot_rows)
for c in cols:
for r in rows:
ws.cell(row=r, column=c).alignment = Alignment(horizontal='center', vertical='center')
You can achieve this by using Python XlsxWriter library.
import xlsxwriter
workbook = xlsxwriter.Workbook('example.xlsx')
worksheet = workbook.add_worksheet()
cell_format = workbook.add_format({'align': 'center'})
worksheet.merge_range('A1:B1', "")
worksheet.write_rich_string('A1','Example', cell_format)
workbook.close()
Here i have merged cells A1, B1 and added a cell format parameter which includes the align parameter assigned as center.

Categories