adjust column width size using openpyxl - python

I'm facing trouble in adjusting column width of the below excel file. I'm using this code.
from openpyxl.utils import get_column_letter
ws.delete_cols(1) #remove col 'A' which has pandas index no.
for column in ws.iter_cols():
name = get_column_letter(column[0].column)
new_col_length = max(len(str(cell.value)) for cell in column)
#ws.column_dimensions[name].bestFit = True #I tried this but the result is same
ws.column_dimensions[name].width = new_col_length
excel sheet:
the output im getting.:

Something like this should manage the deletion of column A using Openpyxl
from openpyxl import load_workbook
from openpyxl.utils import get_column_letter
path = 'col_width.xlsx'
wb = load_workbook(path)
ws = wb['Sheet1']
remerge_cells_list = []
# Remove existing merged cells, and
# Add the calculated new cell coords to remerge_cells_list to re-add after
# the deletion of column A.
for unmerge in range(len(ws.merged_cells.ranges)):
current_merge = ws.merged_cells.ranges[0]
new_min_col = get_column_letter(current_merge.min_col-1)
new_max_col = get_column_letter(current_merge.max_col-1)
remerge_cells_list.append(new_min_col + str(current_merge.min_row) + ':'
+ new_max_col + str(current_merge.max_row))
print("Removing merge: " + current_merge.coord)
ws.unmerge_cells(current_merge.coord)
print("\nDeleting column A\n")
ws.delete_cols(1) #remove col 'A' which has pandas index no.
# Set the column width dimenions
for column in ws.iter_cols():
name = get_column_letter(column[0].column)
new_col_length = max(len(str(cell.value)) for cell in column)
# ws.column_dimensions[name].bestFit = True #I tried this but the result is same
ws.column_dimensions[name].width = new_col_length+2 # Added a extra bit for padding
# Re-merge the cells from the remerge_cells_list
# Don't think it matters if this is done before or after resizing the columns
for merge in remerge_cells_list:
print("Add adjusted cell merge: " + merge)
ws.merge_cells(merge)
wb.save('col_width_out.xlsx')

After many hours of research finally, I found it.
NOTE : In the below code, sheet is the worksheet name. Usually in the documentation, we can see it as ws. Please don't forget to change the worksheet name.
# 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
UPDATE : This code doesn't work for all, but don't hesitate to try it..

Related

Python/Openpyxl: Merge empty row cells delimited by string

I am trying to create a script using python and openpyxl to open up a given excel sheet and merge all cells in a given row together until the script finds a cell containing a string. The row placement is always the same, but the number of columns and the column placement of the strings is not so it needs to be dynamic. Once a new string is found, I want to continue to merge cells until the column that is right before the grand total. There are also cases where the cell doesn't need to be merged, because there is no empty cell in the data set to merge it with.
I found this answer here, which is doing a similar procedure except it is merging rows instead of columns. I was able to refactor part of this to create a list of the cells that have strings in my workbook, but am struggling on next steps. Any thoughts?
import openpyxl
from openpyxl.utils import get_column_letter
from openpyxl import Workbook
wb1 = openpyxl.load_workbook('stackoverflow question.xlsx')
ws1 = wb1.worksheets['ws1']
columns_with_strings = []
merge_row = '3' #the data to merge will always be in this row
for col in range (2, ws1.max_column-1):
for row in merge_row:
if ws1[get_column_letter(col) + merge_row].value != None:
columns_with_strings.append(str(get_column_letter(col) + merge_row)
The above code yields this list which includes the correct cells that contain strings and need to be checked for merging:
['C3', 'F3', 'J3']
This is how the workbook looks now:
This is how I am trying to get it to look in the end:
To complete your code, you can use worksheet.merge_cells with worhseet.cell.alignment:
from openpyxl import load_workbook
from openpyxl.styles import Alignment
wb = load_workbook("tmp/stackoverflow question.xlsx")
ws = wb["Sheet1"]
merge_row = 3
#here, we get the columns idx for every non null cell in row 3
#and after that, we make a text alignment (center) in the last cell
idx_col_strings = [cell.column for cell in ws[merge_row] if cell.value]
ws.cell(3, idx_col_strings[-1]).alignment = Alignment(horizontal="center")
#here, we loop through each range until the last non null cell in row 3
#then, we make a merge as much as the number of transitions (non null => null)
#and finally, we make a text alignement (center) for each cell/merge
for i in range(len(idx_col_strings)-1):
start_col, end_col = idx_col_strings[i], idx_col_strings[i+1]-1
ws.merge_cells(start_row=merge_row, start_column=start_col,
end_row=merge_row, end_column=end_col)
ws.cell(merge_row, start_col).alignment = Alignment(horizontal="center")
wb.save("tmp/stackoverflow answer.xlsx")
BEFORE :
AFTER :
To start, if you aren't familiar with openpyxl's merge and unmerge functions, I recommend your read about them in the documentation (https://openpyxl.readthedocs.io/en/stable/usage.html#merge-unmerge-cells) to get a sense of how this works.
Here is base code that should provide the functionality you are wanting, but some values may need tweaked for your device or spreadsheet.
import openpyxl # Necessary imports.
from openpyxl.utils import get_column_letter
from openpyxl.utils.cell import coordinate_from_string
from openpyxl.utils.cell import column_index_from_string
from openpyxl import Workbook
wb1 = openpyxl.load_workbook('stackoverflow question.xlsx') # Start of your code.
ws1 = wb1.worksheets[0]
columns_with_strings = []
merge_row = '3' #the data to merge will always be in this row
for col in range (2, ws1.max_column):
for row in merge_row:
if ws1[get_column_letter(col) + merge_row].value != None:
columns_with_strings.append(str(get_column_letter(col) + merge_row)) # End of your code.
prior_string = columns_with_strings[0] # Set the "prior_string" to be the first detected string.
for cell in columns_with_strings:
coords = coordinate_from_string(cell) # Split "prior_string" into the letter and number components.
if column_index_from_string(coords[0]) >1:
prior = str(get_column_letter(column_index_from_string(coords[0])-1)) + str(coords[1]) # Get the cell that is left of the cell "prior_string"
if prior > prior_string:
ws1.merge_cells(f'{prior_string}:{prior}') # Merge the cells.
prior_string=cell # Set the current string to be the prior string.
ws1.merge_cells(f'{cell}:{get_column_letter(ws1.max_column)+str(coords[1])}') # Merge the last string to the end (the last column).
wb1.save("stackoverflow question.xlsx") # Save the file changes.
I hope this helps to point you in the right direction!
Based on #timeless' answer I've cleaned the code up a bit to make better use of Python's tools and the openpyxl API
from openpyxl import Workbook
wb = Workbook()
ws = wb.active
ws.append([])
ws.append([])
ws.append([None, None, "Group A", None, None, "Group B", None, None, None, "Group C"])
# get column indices for header cells
headings = [cell.column for cell in next(ws.iter_rows(min_row=3, max_row=3)) if cell.value]
from openpyxl.styles import Alignment, PatternFill, NamedStyle
fill = PatternFill(patternType="solid", fgColor="DDDDDD")
alignment = Alignment(horizontal="center")
header_style = NamedStyle(alignment=alignment, fill=fill, name="Header")
wb.named_styles.append(header_style)
from itertools import zip_longest
# create ranges for merged cells from the list of header cells: the boundary of the first range, is the index of the start of the next minus 1. Use zip_longest for the final value
for start_column, end_column in zip_longest(headings, headings[1:], fillvalue=headings[-1]+1):
ws.cell(3, start_column).style = header_style
ws.merge_cells(start_row=3, end_row=3, start_column=start_column, end_column=end_column-1)
wb.save("merged.xlsx")
Using the API wherever possible generally leads to more manageable and generic code.

How to read specif cell with pandas library?

I want to read from excel sheet a specific cell: h6. So I try it like this:
import pandas as pd
excel_file = './docs/fruit.xlsx'
df = pd.read_excel(excel_file,'Overzicht')
sheet = df.active
x1 = sheet['H6'].value
print(x1)
But then I get this error:
File "C:\Python310\lib\site-packages\pandas\core\generic.py", line 5575, in __getattr__
return object.__getattribute__(self, name)
AttributeError: 'DataFrame' object has no attribute 'active'
So my questiion is: How to read specif cell from sheet from excelsheet?
Thank you
Oke, I tried with openpyxl:
import openpyxl
path = "./docs/fruit.xlsx"
wb_obj = openpyxl.load_workbook(path)
sheet_obj = wb_obj.active
cell_obj = sheet_obj.cell(row = 6, column = 9)
print(cell_obj.value)
But then the formula is printed. Like this:
=(H6*1000)/F6/G6
and not the value: 93
You can do this using openpyxl directly or pandas (which internally uses openpyxl behind the scene)...
Using Openpyxl
You will need to use data_only=True when you open the file. Also, make sure you know the row and column number. To read the data in H6, row would be 6 and 8 would be H
import openpyxl
path = "./docs/Schoolfruit.xlsx"
wb_obj = openpyxl.load_workbook(path, data_only=True)
sheet_obj = wb_obj.active ## Or use sheet_obj = wb_obj['Sheet1'] if you know sheet name
val = sheet_obj.cell(row = 6, column = 8).value
print(val)
Using Pandas
The other option is to use pandas read_excel() which will read the whole sheet into a dataframe. You can use iloc() or at() to read the specific cell. Note that this is probably the less optimal solution if you need to read just one cell...
Another point to note here is that, once you have read the data into a dataframe, the row 1 will be considered as the header and the first row would now be 0. So the row number would be 4 instead of 6. Similarly, the first column would now be 0 and not 1, which would change the position to [4,7]
import pandas as pd
path = "./docs/Schoolfruit.xlsx"
df = pd.read_excel(path, 'Sheet1')
print(df.iloc[4,7])
I found a solution and hope, it works for you.
import pandas as pd
excel_file = './docs/Schoolfruit.xlsx'
df = pd.read_excel(excel_file, sheet_name='active' ,header=None, skiprows=1)
print(df[7][4])
7: Hth column
4: 6th row (skipped first row and index is began from 0)

how to assign a list value to column in excel file?

I have a list value and want to assign it into a column in a excel file. The values I want to change are in sheet 6.
my poor code looks something like this the best I could do is try to first change the AF6:AF22 to a fixed value 5 with hope that I could change it to list.
But is there a simple way to change AF6:AF22 values to a list?
something simple ws['AF6:AF22'] = l?
from openpyxl import Workbook
import pandas as pd
from openpyxl import load_workbook
l = list(range(5))
FilePath = 'excel_file.xlsx'
wb = load_workbook(FilePath)
ws = wb.worksheets
sheet_number = 6
for sheet_number in ws.iter_cols('AF6:AF22'):
for cell in sheet_number:
cell.value = 5
Option 1
Hi - I am adding a faster way here. This is probably better as it avoids the for loop and updating cells one at a time.
from openpyxl import Workbook
import pandas as pd
from openpyxl import load_workbook
l = list(range(17)) #The list - You can replace l with whatever you need
with pd.ExcelWriter('excel_file.xlsx', mode='a', engine = 'openpyxl') as writer:
pd.DataFrame(l).to_excel(writer, sheet_name='Sheet6', startrow = 5, startcol= 31, index=False, header=None)
Option 2
You can use the below code to do what you need. Added comments, so you get an understanding of my logic...
from openpyxl import Workbook
import pandas as pd
from openpyxl import load_workbook
l = list(range(17)) #The list - You can replace l with whatever you need
FilePath = 'excel_file.xlsx'
wb = load_workbook(FilePath)
ws = wb.worksheets[5] #Worksheet 5 is the 6th sheet as numbering starts from zero
for i in range(6,23): # Column numbers 6 through 22
ws.cell(row=i, column=32).value = l[i-6] #Write to cell in AF = column 32
wb.save("excel_file.xlsx")

How to split merged Excel cells with Python?

I am trying to split only the merged cells in Excel file (with multiple sheets) that are like:
Please note that there are partially/fully empty rows. These rows are not merged.
Using openpyxl, I found the merged cell ranges in each sheet with this code:
wb2 = load_workbook('Example.xlsx')
sheets = wb2.sheetnames ##['Sheet1', 'Sheet2']
for i,sheet in enumerate(sheets):
ws = wb2[sheets[i]]
print(ws.merged_cell_ranges)
The print output:
['B3:B9', 'B13:B14', 'A3:A9', 'A13:A14', 'B20:B22', 'A20:A22']
['B5:B9', 'A12:A14', 'B12:B14', 'A17:A18', 'B17:B18', 'A27:A28', 'B27:B28', 'A20:A22', 'B20:B22', 'A3:A4', 'B3:B4', 'A5:A9']
Since I found the merged cell ranges, I need to split the ranges and fill in the corresponding rows like this:
How can I split like this using openpyxl? I am new to using this module. Any feedback is greatly appreciated!
You need to use the unmerge function. Example:
ws.unmerge_cells(start_row=2,start_column=1,end_row=2,end_column=4)
when you use unmerge_cells function, sheet.merged_cells.ranges will be modified, so don't use sheet.merged_cells.ranges in for loop.
from openpyxl.workbook import Workbook
from openpyxl import load_workbook
from openpyxl.utils.cell import range_boundaries
wb = load_workbook(filename = 'tmp.xlsx')
for st_name in wb.sheetnames:
st = wb[st_name]
mcr_coord_list = [mcr.coord for mcr in st.merged_cells.ranges]
for mcr in mcr_coord_list:
min_col, min_row, max_col, max_row = range_boundaries(mcr)
top_left_cell_value = st.cell(row=min_row, column=min_col).value
st.unmerge_cells(mcr)
for row in st.iter_rows(min_col=min_col, min_row=min_row, max_col=max_col, max_row=max_row):
for cell in row:
cell.value = top_left_cell_value
wb.save('merged_tmp.xlsx')

openpyxl - adjust column width size

I have following script which is converting a CSV file to an XLSX file, but my column size is very narrow. Each time I have to drag them with mouse to read data. Does anybody know how to set column width in openpyxl?
Here is the code I am using.
#!/usr/bin/python2.6
import csv
from openpyxl import Workbook
from openpyxl.cell import get_column_letter
f = open('users_info_cvs.txt', "rU")
csv.register_dialect('colons', delimiter=':')
reader = csv.reader(f, dialect='colons')
wb = Workbook()
dest_filename = r"account_info.xlsx"
ws = wb.worksheets[0]
ws.title = "Users Account Information"
for row_index, row in enumerate(reader):
for column_index, cell in enumerate(row):
column_letter = get_column_letter((column_index + 1))
ws.cell('%s%s'%(column_letter, (row_index + 1))).value = cell
wb.save(filename = dest_filename)
You could estimate (or use a mono width font) to achieve this. Let's assume data is a nested array like
[['a1','a2'],['b1','b2']]
We can get the max characters in each column. Then set the width to that. Width is exactly the width of a monospace font (if not changing other styles at least). Even if you use a variable width font it is a decent estimation. This will not work with formulas.
from openpyxl.utils import get_column_letter
column_widths = []
for row in data:
for i, cell in enumerate(row):
if len(column_widths) > i:
if len(cell) > column_widths[i]:
column_widths[i] = len(cell)
else:
column_widths += [len(cell)]
for i, column_width in enumerate(column_widths,1): # ,1 to start at 1
worksheet.column_dimensions[get_column_letter(i)].width = column_width
A bit of a hack but your reports will be more readable.
My variation of Bufke's answer. Avoids a bit of branching with the array and ignores empty cells / columns.
Now fixed for non-string cell values.
ws = your current worksheet
dims = {}
for row in ws.rows:
for cell in row:
if cell.value:
dims[cell.column] = max((dims.get(cell.column, 0), len(str(cell.value))))
for col, value in dims.items():
ws.column_dimensions[col].width = value
As of openpyxl version 3.0.3 you need to use
dims[cell.column_letter] = max((dims.get(cell.column_letter, 0), len(str(cell.value))))
as the openpyxl library will raise a TypeError if you pass column_dimensions a number instead of a column letter, everything else can stay the same.
Even more pythonic way to set the width of all columns that works at least in openpyxl version 2.4.0:
for column_cells in worksheet.columns:
length = max(len(as_text(cell.value)) for cell in column_cells)
worksheet.column_dimensions[column_cells[0].column].width = length
The as_text function should be something that converts the value to a proper length string, like for Python 3:
def as_text(value):
if value is None:
return ""
return str(value)
With openpyxl 3.0.3 the best way to modify the columns is with the DimensionHolder object, which is a dictionary that maps each column to a ColumnDimension object.
ColumnDimension can get parameters as bestFit, auto_size (which is an alias of bestFit) and width.
Personally, auto_size doesn't work as expected and I had to use width and figured out that the best width for the column is len(cell_value) * 1.23.
To get the value of each cell it's necessary to iterate over each one, but I personally didn't use it because in my project I just had to write worksheets, so I got the longest string in each column directly on my data.
The example below just shows how to modify the column dimensions:
import openpyxl
from openpyxl.worksheet.dimensions import ColumnDimension, DimensionHolder
from openpyxl.utils import get_column_letter
wb = openpyxl.load_workbook("Example.xslx")
ws = wb["Sheet1"]
dim_holder = DimensionHolder(worksheet=ws)
for col in range(ws.min_column, ws.max_column + 1):
dim_holder[get_column_letter(col)] = ColumnDimension(ws, min=col, max=col, width=20)
ws.column_dimensions = dim_holder
I have a problem with merged_cells and autosize not work correctly, if you have the same problem, you can solve with the next code:
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
A slight improvement of the above accepted answer, that I think is more pythonic (asking for forgiveness is better than asking for permission)
column_widths = []
for row in workSheet.iter_rows():
for i, cell in enumerate(row):
try:
column_widths[i] = max(column_widths[i], len(str(cell.value)))
except IndexError:
column_widths.append(len(str(cell.value)))
for i, column_width in enumerate(column_widths):
workSheet.column_dimensions[get_column_letter(i + 1)].width = column_width
We can convert numbers to their ASCII values and give it to column_dimension parameter
import openpyxl as xl
work_book = xl.load_workbook('file_location')
sheet = work_book['Sheet1']
column_number = 2
column = str(chr(64 + column_number))
sheet.column_dimensions[column].width = 20
work_book.save('file_location')
Here is a more general, simplified solution for users new to the topic (Not specified for the question).
If you want to change the width or the height of cells in openpyxl (Version 3.0.9), you can do it simply by assigning the attributes of the cells with row_dimensions or column_dimensions.
import openpyxl
wb = openpyxl.Workbook()
sheet = wb["Sheet"]
sheet["A1"] = "Tall row"
sheet["B2"] = "Wide column"
# Change height of row A1
sheet.row_dimensions[1].height = 100
# Change width of column B
sheet.column_dimensions["B"].width = 50
wb.save("StackOverflow.xlsx")
This is my version referring #Virako 's code snippet
def adjust_column_width_from_col(ws, min_row, min_col, max_col):
column_widths = []
for i, col in \
enumerate(
ws.iter_cols(min_col=min_col, max_col=max_col, min_row=min_row)
):
for cell in col:
value = cell.value
if value is not None:
if isinstance(value, str) is False:
value = str(value)
try:
column_widths[i] = max(column_widths[i], len(value))
except IndexError:
column_widths.append(len(value))
for i, width in enumerate(column_widths):
col_name = get_column_letter(min_col + i)
value = column_widths[i] + 2
ws.column_dimensions[col_name].width = value
And how to use is as follows,
adjust_column_width_from_col(ws, 1,1, ws.max_column)
All the above answers are generating an issue which is that col[0].column is returning number while worksheet.column_dimensions[column] accepts only character such as 'A', 'B', 'C' in place of column. I've modified #Virako's code and it is working fine now.
import re
import openpyxl
..
for col in _ws.columns:
max_lenght = 0
print(col[0])
col_name = re.findall('\w\d', str(col[0]))
col_name = col_name[0]
col_name = re.findall('\w', str(col_name))[0]
print(col_name)
for cell in col:
try:
if len(str(cell.value)) > max_lenght:
max_lenght = len(cell.value)
except:
pass
adjusted_width = (max_lenght+2)
_ws.column_dimensions[col_name].width = adjusted_width
This is a dirty fix. But openpyxl actually supports auto_fit. But there is no method to access the property.
import openpyxl
from openpyxl.utils import get_column_letter
wb = openpyxl.load_workbook("Example.xslx")
ws = wb["Sheet1"]
for i in range(1, ws.max_column+1):
ws.column_dimensions[get_column_letter(i)].bestFit = True
ws.column_dimensions[get_column_letter(i)].auto_size = True
Another approach without storing any state could be like this:
from itertools import chain
# Using `ws` as the Worksheet
for cell in chain.from_iterable(ws.iter_cols()):
if cell.value:
ws.column_dimensions[cell.column_letter].width = max(
ws.column_dimensions[cell.column_letter].width,
len(f"{cell.value}"),
)
I had to change #User3759685 above answer to this when the openpxyl updated. I was getting an error. Well #phihag reported this in the comments as well
for column_cells in ws.columns:
new_column_length = max(len(as_text(cell.value)) for cell in column_cells)
new_column_letter = (openpyxl.utils.get_column_letter(column_cells[0].column))
if new_column_length > 0:
ws.column_dimensions[new_column_letter].width = new_column_length + 1
Compiling and applying multiple suggestions above, and extending merged cells detection to the horizontally merged cells only, I could offer this code:
def adjust_width(ws):
"""
Adjust width of the columns
#param ws: worksheet
#return: None
"""
def is_merged_horizontally(cell):
"""
Checks if cell is merged horizontally with an another cell
#param cell: cell to check
#return: True if cell is merged horizontally with an another cell, else False
"""
cell_coor = cell.coordinate
if cell_coor not in ws.merged_cells:
return False
for rng in ws.merged_cells.ranges:
if cell_coor in rng and len(list(rng.cols)) > 1:
return True
return False
for col_number, col in enumerate(ws.columns, start=1):
col_letter = get_column_letter(col_number)
max_length = max(
len(str(cell.value or "")) for cell in col if not is_merged_horizontally(cell)
)
adjusted_width = (max_length + 2) * 0.95
ws.column_dimensions[col_letter].width = adjusted_width
After update from openpyxl2.5.2a to latest 2.6.4 (final version for python 2.x support), I got same issue in configuring the width of a column.
Basically I always calculate the width for a column (dims is a dict maintaining each column width):
dims[cell.column] = max((dims.get(cell.column, 0), len(str(cell.value))))
Afterwards I am modifying the scale to something shortly bigger than original size, but now you have to give the "Letter" value of a column and not anymore a int value (col below is the value and is translated to the right letter):
worksheet.column_dimensions[get_column_letter(col)].width = value +1
This will fix the visible error and assigning the right width to your column ;)
Hope this help.
I made a function that is very fast with large Excel files because it uses pandas.read_excel
import pandas as pd
from openpyxl import load_workbook
from openpyxl.utils import get_column_letter
def auto_adjust_column_width(file_path, sheet_name=0):
column_widths = []
df = pd.read_excel(file_path, sheet_name=sheet_name, header=None)
for col in df.columns:
max_length = int(df[col].astype(str).str.len().max() * 1.2)
column_widths.append(max_length)
wb = load_workbook(file_path)
if isinstance(sheet_name, int):
sheet_name = wb.sheetnames[sheet_name]
worksheet = wb[sheet_name]
for i, column_width in enumerate(column_widths):
column = get_column_letter(i+1)
worksheet.column_dimensions[column].width = column_width
wb.save(file_path)
When this came up for me, I just did everything I wanted to do with openpyxl, saved the workbook, and opened it again with pywin32. Pywin32 has autofit built in without having to make a bunch of rules/conditions.
Edit: I should note that pywin32 only works with Windows.
from win32com.client import Dispatch
excel = Dispatch('Excel.Application')
wb = excel.Workbooks.Open("excelFile.xlsx")
excel.Worksheets(1).Activate()
excel.ActiveSheet.Columns.AutoFit()
wb.Save()
wb.Close()
excel.Quit()
I did add a rule, however, because I had one text column that had some long values I didn't need to show. I limited any column to 75 characters.
excel = Dispatch('Excel.Application')
wb = excel.Workbooks.Open("excelFile.xlsx")
excel.Worksheets(1).Activate()
excel.ActiveSheet.Columns.AutoFit()
for col in excel.ActiveSheet.Columns:
if col.ColumnWidth > 75:
col.ColumnWidth = 75
wb.Save()
wb.Close()
excel.Quit()
Just insert the below line of code in your file
# 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
Here is an answer for Python 3.8 and OpenPyXL 3.0.0.
I tried to avoid using the get_column_letter function but failed.
This solution uses the newly introduced assignment expressions aka "walrus operator":
import openpyxl
from openpyxl.utils import get_column_letter
workbook = openpyxl.load_workbook("myxlfile.xlsx")
worksheet = workbook["Sheet1"]
MIN_WIDTH = 10
for i, column_cells in enumerate(worksheet.columns, start=1):
width = (
length
if (length := max(len(str(cell_value) if (cell_value := cell.value) is not None else "")
for cell in column_cells)) >= MIN_WIDTH
else MIN_WIDTH
)
worksheet.column_dimensions[get_column_letter(i)].width = width
Since in openpyxl 2.6.1, it requires the column letter, not the column number, when setting the width.
for column in sheet.columns:
length = max(len(str(cell.value)) for cell in column)
length = length if length <= 16 else 16
sheet.column_dimensions[column[0].column_letter].width = length

Categories