Python – Automatically adjust width of an excel file's columns
Question:
Newbie – I have a Python script that adjusts the width of different columns of an excel file, according to the values specified:
import openpyxl
from string import ascii_uppercase
newFile = "D:Excel Filesabc.xlsx"
wb = openpyxl.load_workbook(filename = newFile)
worksheet = wb.active
for column in ascii_uppercase:
if (column=='A'):
worksheet.column_dimensions[column].width = 30
elif (column=='B'):
worksheet.column_dimensions[column].width = 40
elif (column=='G'):
worksheet.column_dimensions[column].width = 45
else:
worksheet.column_dimensions[column].width = 15
wb.save(newFile)
Is there any way through which we can adjust the width of every column to its most optimum value, without explicitly specifying it for different columns (means, without using this “if-elif-elif-……-elif-else” structure)?
Thanks!
Answers:
for col in worksheet.columns:
max_length = 0
column = col[0].column_letter # Get the column name
for cell in col:
try: # Necessary to avoid error on empty cells
if len(str(cell.value)) > max_length:
max_length = len(str(cell.value))
except:
pass
adjusted_width = (max_length + 2) * 1.2
worksheet.column_dimensions[column].width = adjusted_width
This could probably be made neater but it does the job. You will want to play around with the adjusted_width value according to what is good for the font you are using when viewing it. If you use a monotype you can get it exact but its not a one-to-one correlation so you will still need to adjust it a bit.
If you want to get fancy and exact without monotype you could sort letters by width and assign each width a float value which you then add up. This would require a third loop parsing each character in the cell value and summing up the result for each column and probably a dictionary sorting characters by width, perhaps overkill but cool if you do it.
Edit: Actually there seems to be a better way of measuring visual size of text: link personally I would prefer the matplotlib technique.
Hope I could be of help, my very first stackoverflow answer =)
I have a problem with merged_cells and autosize not work correctly, if you have the same problem, you can solve adding the next lines inside code of oldsea
for col in worksheet.columns:
max_length = 0
column = col[0].column # Get the column name
for cell in col:
if cell.coordinate in worksheet.merged_cells: # not check merge_cells
continue
try: # Necessary to avoid error on empty cells
if len(str(cell.value)) > max_length:
max_length = len(cell.value)
except:
pass
adjusted_width = (max_length + 2) * 1.2
worksheet.column_dimensions[column].width = adjusted_width
Updated version as of openpyxl 3.0.0 (using .columns fails with TypeError: expected <class 'str'>
:
for column_cells in ws.columns:
length = max(len(str(cell.value)) for cell in column_cells)
ws.column_dimensions[column_cells[0].column_letter].width = length
def auto_format_cell_width(ws):
for letter in range(1,ws.max_column):
maximum_value = 0
for cell in ws[get_column_letter(letter)]:
val_to_check = len(str(cell.value))
if val_to_check > maximum_value:
maximum_value = val_to_check
ws.column_dimensions[get_column_letter(letter)].width = maximum_value + 1
Based on the comment above and add this post openpyxl – adjust column width size. I succeeded, but the answer should be:
from openpyxl.utils import get_column_letter
for col in ws.columns:
max_length = 0
column = get_column_letter(col[0].column) # Get the column name
# Since Openpyxl 2.6, the column name is ".column_letter" as .column became the column number (1-based)
for cell in col:
try: # Necessary to avoid error on empty cells
if len(str(cell.value)) > max_length:
max_length = len(cell.value)
except:
pass
adjusted_width = (max_length + 2) * 1.2
ws.column_dimensions[column].width = adjusted_width
i’m using openpyxl = "^3.0.5"
With the latest openpyxl you can use this:
from openpyxl.utils import get_column_letter
for idx, col in enumerate(worksheet.columns, 1):
worksheet.column_dimensions[get_column_letter(idx)].auto_size = True
Just insert the below line of code in your file. That’s it (install the mentioned libraries if you don’t have)
# Imorting the necessary modules
try:
from openpyxl.cell import get_column_letter
except ImportError:
from openpyxl.utils import get_column_letter
from openpyxl.utils import column_index_from_string
from openpyxl import load_workbook
import openpyxl
from openpyxl import Workbook
for column_cells in sheet.columns:
new_column_length = max(len(str(cell.value)) for cell in column_cells)
new_column_letter = (get_column_letter(column_cells[0].column))
if new_column_length > 0:
sheet.column_dimensions[new_column_letter].width = new_column_length*1.23
for column_cells in sheet.columns:
new_column_length = max(len(str(cell.value)) for cell in column_cells)
new_column_letter = (get_column_letter(column_cells[0].column))
if new_column_length > 0:
sheet.column_dimensions[new_column_letter].width = new_column_length*1.23
sheet.column_dimensions[new_column_letter].width = new_column_length*1.23
The above line of code fits the adjust the width of the column to best fit
Try this, it works for me:
from openpyxl.utils import get_column_letter
for columns in worksheet.columns:
col = get_column_letter(columns[0].column)
worksheet.column_dimensions[col].auto_size = True
pywin32 is a better package to work with Excel on Python in my opinion because it mirrors Excel VBA. The Range.AutoFit method takes care of this issue. Example below:
import win32com.client as win32
xlApp = win32.Dispatch('Excel.Application')
wb = xlApp.Workbooks.Open(***file path to excel file goes here***)
ws = wb.Worksheets[***name of worksheet trying adjust column width***]
ws.Columns.AutoFit()
Note: Worksheet.Columns property represents a Range object. Autofit is a method that belongs to the Range object.
Newbie – I have a Python script that adjusts the width of different columns of an excel file, according to the values specified:
import openpyxl
from string import ascii_uppercase
newFile = "D:Excel Filesabc.xlsx"
wb = openpyxl.load_workbook(filename = newFile)
worksheet = wb.active
for column in ascii_uppercase:
if (column=='A'):
worksheet.column_dimensions[column].width = 30
elif (column=='B'):
worksheet.column_dimensions[column].width = 40
elif (column=='G'):
worksheet.column_dimensions[column].width = 45
else:
worksheet.column_dimensions[column].width = 15
wb.save(newFile)
Is there any way through which we can adjust the width of every column to its most optimum value, without explicitly specifying it for different columns (means, without using this “if-elif-elif-……-elif-else” structure)?
Thanks!
for col in worksheet.columns:
max_length = 0
column = col[0].column_letter # Get the column name
for cell in col:
try: # Necessary to avoid error on empty cells
if len(str(cell.value)) > max_length:
max_length = len(str(cell.value))
except:
pass
adjusted_width = (max_length + 2) * 1.2
worksheet.column_dimensions[column].width = adjusted_width
This could probably be made neater but it does the job. You will want to play around with the adjusted_width value according to what is good for the font you are using when viewing it. If you use a monotype you can get it exact but its not a one-to-one correlation so you will still need to adjust it a bit.
If you want to get fancy and exact without monotype you could sort letters by width and assign each width a float value which you then add up. This would require a third loop parsing each character in the cell value and summing up the result for each column and probably a dictionary sorting characters by width, perhaps overkill but cool if you do it.
Edit: Actually there seems to be a better way of measuring visual size of text: link personally I would prefer the matplotlib technique.
Hope I could be of help, my very first stackoverflow answer =)
I have a problem with merged_cells and autosize not work correctly, if you have the same problem, you can solve adding the next lines inside code of oldsea
for col in worksheet.columns:
max_length = 0
column = col[0].column # Get the column name
for cell in col:
if cell.coordinate in worksheet.merged_cells: # not check merge_cells
continue
try: # Necessary to avoid error on empty cells
if len(str(cell.value)) > max_length:
max_length = len(cell.value)
except:
pass
adjusted_width = (max_length + 2) * 1.2
worksheet.column_dimensions[column].width = adjusted_width
Updated version as of openpyxl 3.0.0 (using .columns fails with TypeError: expected <class 'str'>
:
for column_cells in ws.columns:
length = max(len(str(cell.value)) for cell in column_cells)
ws.column_dimensions[column_cells[0].column_letter].width = length
def auto_format_cell_width(ws):
for letter in range(1,ws.max_column):
maximum_value = 0
for cell in ws[get_column_letter(letter)]:
val_to_check = len(str(cell.value))
if val_to_check > maximum_value:
maximum_value = val_to_check
ws.column_dimensions[get_column_letter(letter)].width = maximum_value + 1
Based on the comment above and add this post openpyxl – adjust column width size. I succeeded, but the answer should be:
from openpyxl.utils import get_column_letter
for col in ws.columns:
max_length = 0
column = get_column_letter(col[0].column) # Get the column name
# Since Openpyxl 2.6, the column name is ".column_letter" as .column became the column number (1-based)
for cell in col:
try: # Necessary to avoid error on empty cells
if len(str(cell.value)) > max_length:
max_length = len(cell.value)
except:
pass
adjusted_width = (max_length + 2) * 1.2
ws.column_dimensions[column].width = adjusted_width
i’m using openpyxl = "^3.0.5"
With the latest openpyxl you can use this:
from openpyxl.utils import get_column_letter
for idx, col in enumerate(worksheet.columns, 1):
worksheet.column_dimensions[get_column_letter(idx)].auto_size = True
Just insert the below line of code in your file. That’s it (install the mentioned libraries if you don’t have)
# Imorting the necessary modules
try:
from openpyxl.cell import get_column_letter
except ImportError:
from openpyxl.utils import get_column_letter
from openpyxl.utils import column_index_from_string
from openpyxl import load_workbook
import openpyxl
from openpyxl import Workbook
for column_cells in sheet.columns:
new_column_length = max(len(str(cell.value)) for cell in column_cells)
new_column_letter = (get_column_letter(column_cells[0].column))
if new_column_length > 0:
sheet.column_dimensions[new_column_letter].width = new_column_length*1.23
for column_cells in sheet.columns:
new_column_length = max(len(str(cell.value)) for cell in column_cells)
new_column_letter = (get_column_letter(column_cells[0].column))
if new_column_length > 0:
sheet.column_dimensions[new_column_letter].width = new_column_length*1.23
sheet.column_dimensions[new_column_letter].width = new_column_length*1.23
The above line of code fits the adjust the width of the column to best fit
Try this, it works for me:
from openpyxl.utils import get_column_letter
for columns in worksheet.columns:
col = get_column_letter(columns[0].column)
worksheet.column_dimensions[col].auto_size = True
pywin32 is a better package to work with Excel on Python in my opinion because it mirrors Excel VBA. The Range.AutoFit method takes care of this issue. Example below:
import win32com.client as win32
xlApp = win32.Dispatch('Excel.Application')
wb = xlApp.Workbooks.Open(***file path to excel file goes here***)
ws = wb.Worksheets[***name of worksheet trying adjust column width***]
ws.Columns.AutoFit()
Note: Worksheet.Columns property represents a Range object. Autofit is a method that belongs to the Range object.