199

I am being asked to generate some Excel reports. I am currently using pandas quite heavily for my data, so naturally I would like to use the pandas.ExcelWriter method to generate these reports. However the fixed column widths are a problem.

The code I have so far is simple enough. Say I have a dataframe called df:

writer = pd.ExcelWriter(excel_file_path, engine='openpyxl')
df.to_excel(writer, sheet_name="Summary")

I was looking over the pandas docs, and I don't really see any options to set column widths. Is there a trick to make it such that the columns auto-adjust to the data? Or is there something I can do after the fact to the xlsx file to adjust the column widths?

(I am using the OpenPyXL library, and generating .xlsx files - if that makes any difference.)

tdy
  • 36,675
  • 19
  • 86
  • 83
badideas
  • 3,189
  • 3
  • 25
  • 26
  • 1
    doesn't look possible at the moment, please open an issue for this enhancement on github (and maybe a PR?). doesn't look that hard to do. – Jeff Jun 26 '13 at 18:08
  • thanks Jeff, i have submitted the issue. i'm not sure if i will have time to actually dive into the pandas codebase to solve it, but you never know :) – badideas Jun 26 '13 at 19:19
  • yep....saw your issue.....comment on the issue if you need some help! (essentially need to pass an optional argument to ``to_excel``, maybe ``col_style=dict`` which contains col header style elements (rather than the default ``header_style`` which seems to be hard coded now – Jeff Jun 26 '13 at 19:27
  • 8
    [Link to pandas issue](https://github.com/pydata/pandas/issues/4049) – dmvianna Feb 11 '14 at 00:00

20 Answers20

118

Inspired by user6178746's answer, I have the following:

# Given a dict of dataframes, for example:
# dfs = {'gadgets': df_gadgets, 'widgets': df_widgets}

writer = pd.ExcelWriter(filename, engine='xlsxwriter')
for sheetname, df in dfs.items():  # loop through `dict` of dataframes
    df.to_excel(writer, sheet_name=sheetname)  # send df to writer
    worksheet = writer.sheets[sheetname]  # pull worksheet object
    for idx, col in enumerate(df):  # loop through all columns
        series = df[col]
        max_len = max((
            series.astype(str).map(len).max(),  # len of largest item
            len(str(series.name))  # len of column name/header
            )) + 1  # adding a little extra space
        worksheet.set_column(idx, idx, max_len)  # set column width
writer.save()
John Y
  • 14,123
  • 2
  • 48
  • 72
alichaudry
  • 2,573
  • 2
  • 18
  • 27
  • 13
    FYI: In my case I needed to use "index=False" in the "df.to_excel(...)" call, or else the columns were off by 1 – Jesper - jtk.eth Jan 12 '17 at 04:20
  • 1
    yep, I also had to add df.to_excel(writer, sheet_name=sheetname, index=False) – Heikki Pulkkinen Jun 20 '18 at 06:21
  • 5
    If you can't use index=False (because you have a multiindex on rows), then you can get the index level depth with df.index.nlevels and then use this to add on to your set column call: `worksheet.set_column(idx+nlevels, idx+nlevels, max_len)`. Otherwise the length is *calculated* for the first column of the frame, and then *applied* to the first column in the excel, which is probably the index. – ac24 Jul 06 '18 at 08:20
  • 1
    For anyone still looking for this answer, `enumerate(df)` should be `enumerate(df.columns)` since you're iterating over each column in `df`. – Dascienz Sep 13 '18 at 20:05
  • 2
    @Dascienz the same way iterating over a `dict` actually iterates over the keys in the `dict` (you don't have to manually say `dict.keys()`), iterating over a `pd.DataFrame` iterates over the columns. You don't have to manually iterate over `df.columns`. – alichaudry Sep 13 '18 at 21:20
  • @alichaudry Ah, I see! Thanks for clarification! – Dascienz Sep 13 '18 at 22:10
  • 2
    Pandas supports a nice notation for calculation string length and other stuff: `series.astype(str).map(len).max()` can be rewritten as: `series.astype(str).str.len().max()`. – Chaoste Mar 05 '19 at 21:25
  • 1
    it seems this works well for string but a lot less well for date format, where the actual width can be much larger than what is calculated here – jmd Apr 13 '21 at 23:55
  • 8
    If you get `AttributeError: 'Worksheet' object has no attribute 'set_column'`, you may be missing XlsxWriter and pandas is falling back on openpyxl. `pip install XlsxWriter` should solve it :) – Philippe Hebert Oct 15 '21 at 16:37
  • Good job! I also had to add `writer.handles = None` at the end, otherwise Excel wouldn't open it – Cristobal Sarome Sep 08 '22 at 16:20
  • FYI I had a dataframe with duplicate column name so in place of ***series = df[col]*** Use ***series = df.iloc[:,idx]*** – Pavan Agarwal Mar 02 '23 at 11:58
  • The `save` method has been deprecated. Use `close`. – Code Pope Aug 14 '23 at 10:51
63

Dynamically adjust all the column lengths

writer = pd.ExcelWriter('/path/to/output/file.xlsx') 
df.to_excel(writer, sheet_name='sheetName', index=False, na_rep='NaN')

for column in df:
    column_length = max(df[column].astype(str).map(len).max(), len(column))
    col_idx = df.columns.get_loc(column)
    writer.sheets['sheetName'].set_column(col_idx, col_idx, column_length)

writer.save()

Manually adjust a column using Column Name

col_idx = df.columns.get_loc('columnName')
writer.sheets['sheetName'].set_column(col_idx, col_idx, 15)

Manually adjust a column using Column Index

writer.sheets['sheetName'].set_column(col_idx, col_idx, 15)

In case any of the above is failing with

AttributeError: 'Worksheet' object has no attribute 'set_column'

make sure to install xlsxwriter:

pip install xlsxwriter

and use it as the engine:

writer = pd.ExcelWriter('/path/to/output/file.xlsx', engine='xlsxwriter') 

For a more comprehensive explanation you can read the article How to Auto-Adjust the Width of Excel Columns with Pandas ExcelWriter on TDS.

Martijn Courteaux
  • 67,591
  • 47
  • 198
  • 287
Giorgos Myrianthous
  • 36,235
  • 20
  • 134
  • 156
  • What is `df` here? Could you please show code, including `df` initialization? – parsecer Jul 19 '21 at 22:51
  • @parsecer You can refer to the article I've shared at the bottom of the post. – Giorgos Myrianthous Aug 12 '21 at 10:23
  • 2
    Worked perfectly, including the auto widths, explicit widths by column name and exception resolved by installing xlswriter. Thanks :) – MattG Sep 29 '21 at 05:41
  • 1
    This detection of column width will not work when the column is a multi-index. Multi-Index is rendered in excel as a cell merge. – LogZ Sep 06 '22 at 15:59
  • I noticed that the OP used `engine='openpyxl'`, but you said to install `xlsxwriter`. Is `openpyxl` not capable of this, or is `xlsxwriter` just easier to use? – Joe Apr 08 '23 at 20:14
38

There is a nice package that I started to use recently called StyleFrame.

it gets DataFrame and lets you to style it very easily...

by default the columns width is auto-adjusting.

for example:

from StyleFrame import StyleFrame
import pandas as pd

df = pd.DataFrame({'aaaaaaaaaaa': [1, 2, 3], 
                   'bbbbbbbbb': [1, 1, 1],
                   'ccccccccccc': [2, 3, 4]})
excel_writer = StyleFrame.ExcelWriter('example.xlsx')
sf = StyleFrame(df)
sf.to_excel(excel_writer=excel_writer, row_to_add_filters=0,
            columns_and_rows_to_freeze='B2')
excel_writer.save()

you can also change the columns width:

sf.set_column_width(columns=['aaaaaaaaaaa', 'bbbbbbbbb'],
                    width=35.3)

UPDATE 1

In version 1.4 best_fit argument was added to StyleFrame.to_excel. See the documentation.

UPDATE 2

Here's a sample of code that works for StyleFrame 3.x.x

from styleframe import StyleFrame
import pandas as pd

columns = ['aaaaaaaaaaa', 'bbbbbbbbb', 'ccccccccccc', ]
df = pd.DataFrame(data={
        'aaaaaaaaaaa': [1, 2, 3, ],
        'bbbbbbbbb': [1, 1, 1, ],
        'ccccccccccc': [2, 3, 4, ],
    }, columns=columns,
)
excel_writer = StyleFrame.ExcelWriter('example.xlsx')
sf = StyleFrame(df)
sf.to_excel(
    excel_writer=excel_writer, 
    best_fit=columns,
    columns_and_rows_to_freeze='B2', 
    row_to_add_filters=0,
)
excel_writer.save()
AsafSH
  • 675
  • 6
  • 10
  • The StyleFrame package may be easy to use, but I don't see how "by default the columns width is auto-adjusting". When I run the code sample you gave, all the columns are the same width, and all three headers are wrapped. Your sample data is also poorly chosen, because they are all almost the same width naturally. To really illustrate automatic adjustment, you should choose some really wide data and some narrow data. When I do this for myself, the column widths are *still* exactly the same as before. There was no adjustment whatsoever. – John Y Oct 03 '18 at 21:49
  • Maybe at one point in StyleFrame's history, the column widths were automatically adjusted by default, but at least today, you have to specify the column or columns you want adjusted in the `best_fit` parameter. Also, when I tried this, I got [very poor results](https://github.com/pandas-dev/pandas/issues/4049#issuecomment-426829120). – John Y Oct 03 '18 at 22:53
  • the width seems to be off 1 column. I tried enabling and disabling the `index` parameter but no dice. –  Jan 22 '19 at 12:03
  • 1
    thanks! for those looking: How you add more styling to header for example: `sf.apply_headers_style(Styler(bold=False))` it took me a long time to figure that out. And in the import statement, `from StyleFrame import StyleFrame, Styler` . here's all the options apart from bold: https://styleframe.readthedocs.io/en/2.0.5/api_documentation.html#styler-class – Nikhil VJ Mar 28 '20 at 13:05
  • Unfortunately, this answer is outdated and I only get import errors if I try to apply it as the API seems to have changed significantly. – Hagbard Jul 03 '20 at 14:35
  • 3
    @Hagbard as of version 3 the import should be `from styleframe import StyleFrame` in order to comply with PEP8 name conventions – DeepSpace Sep 26 '20 at 11:14
  • I see an issue dealing with multi_index dataframes - just fail once passing `index=True` in the method `to_excel` – Guido Nov 11 '20 at 15:40
36

I'm posting this because I just ran into the same issue and found that the official documentation for Xlsxwriter and pandas still have this functionality listed as unsupported. I hacked together a solution that solved the issue i was having. I basically just iterate through each column and use worksheet.set_column to set the column width == the max length of the contents of that column.

One important note, however. This solution does not fit the column headers, simply the column values. That should be an easy change though if you need to fit the headers instead. Hope this helps someone :)

import pandas as pd
import sqlalchemy as sa
import urllib


read_server = 'serverName'
read_database = 'databaseName'

read_params = urllib.quote_plus("DRIVER={SQL Server};SERVER="+read_server+";DATABASE="+read_database+";TRUSTED_CONNECTION=Yes")
read_engine = sa.create_engine("mssql+pyodbc:///?odbc_connect=%s" % read_params)

#Output some SQL Server data into a dataframe
my_sql_query = """ SELECT * FROM dbo.my_table """
my_dataframe = pd.read_sql_query(my_sql_query,con=read_engine)

#Set destination directory to save excel.
xlsFilepath = r'H:\my_project' + "\\" + 'my_file_name.xlsx'
writer = pd.ExcelWriter(xlsFilepath, engine='xlsxwriter')

#Write excel to file using pandas to_excel
my_dataframe.to_excel(writer, startrow = 1, sheet_name='Sheet1', index=False)

#Indicate workbook and worksheet for formatting
workbook = writer.book
worksheet = writer.sheets['Sheet1']

#Iterate through each column and set the width == the max length in that column. A padding length of 2 is also added.
for i, col in enumerate(my_dataframe.columns):
    # find length of column i
    column_len = my_dataframe[col].astype(str).str.len().max()
    # Setting the length if the column header is larger
    # than the max column value length
    column_len = max(column_len, len(col)) + 2
    # set the column length
    worksheet.set_column(i, i, column_len)
writer.save()
TrigonaMinima
  • 1,828
  • 1
  • 23
  • 35
25

There is probably no automatic way to do it right now, but as you use openpyxl, the following line (adapted from another answer by user Bufke on how to do in manually) allows you to specify a sane value (in character widths):

writer.sheets['Summary'].column_dimensions['A'].width = 15
Community
  • 1
  • 1
ojdo
  • 8,280
  • 5
  • 37
  • 60
  • 1
    The default ExcelWriter engine pandas is using has changed since 2013 to Xlsxwriter, which does not contain a `column_dimensions` attribute. If you want to keep using openpyxl, simply specify it when creating the writer using `pd.ExcelWriter(excel_filename, engine='openpyxl')` – ojdo Dec 18 '19 at 11:20
  • @Sunil: check the other answers using `Xlsxwriter` as the engine to see how to specify the column width with today's default engine. – ojdo Dec 18 '19 at 11:22
17

By using pandas and xlsxwriter you can do your task, below code will perfectly work in Python 3.x. For more details on working with XlsxWriter with pandas this link might be useful https://xlsxwriter.readthedocs.io/working_with_pandas.html

import pandas as pd
writer = pd.ExcelWriter(excel_file_path, engine='xlsxwriter')
df.to_excel(writer, sheet_name="Summary")
workbook = writer.book
worksheet = writer.sheets["Summary"]
#set the column width as per your requirement
worksheet.set_column('A:A', 25)
writer.save()
Ashu007
  • 745
  • 1
  • 9
  • 13
7

I found that it was more useful to adjust the column with based on the column header rather than column content.

Using df.columns.values.tolist() I generate a list of the column headers and use the lengths of these headers to determine the width of the columns.

See full code below:

import pandas as pd
import xlsxwriter

writer = pd.ExcelWriter(filename, engine='xlsxwriter')
df.to_excel(writer, index=False, sheet_name=sheetname)

workbook = writer.book # Access the workbook
worksheet= writer.sheets[sheetname] # Access the Worksheet

header_list = df.columns.values.tolist() # Generate list of headers
for i in range(0, len(header_list)):
    worksheet.set_column(i, i, len(header_list[i])) # Set column widths based on len(header)

writer.save() # Save the excel file
jack1536
  • 151
  • 2
  • 2
6

At work, I am always writing the dataframes to excel files. So instead of writing the same code over and over, I have created a modulus. Now I just import it and use it to write and formate the excel files. There is one downside though, it takes a long time if the dataframe is extra large. So here is the code:

def result_to_excel(output_name, dataframes_list, sheet_names_list, output_dir):
    out_path = os.path.join(output_dir, output_name)
    writerReport = pd.ExcelWriter(out_path, engine='xlsxwriter',
                    datetime_format='yyyymmdd', date_format='yyyymmdd')
    workbook = writerReport.book
    # loop through the list of dataframes to save every dataframe into a new sheet in the excel file
    for i, dataframe in enumerate(dataframes_list):
        sheet_name = sheet_names_list[i]  # choose the sheet name from sheet_names_list
        dataframe.to_excel(writerReport, sheet_name=sheet_name, index=False, startrow=0)
        # Add a header format.
        format = workbook.add_format({
            'bold': True,
            'border': 1,
            'fg_color': '#0000FF',
            'font_color': 'white'})
        # Write the column headers with the defined format.
        worksheet = writerReport.sheets[sheet_name]
        for col_num, col_name in enumerate(dataframe.columns.values):
            worksheet.write(0, col_num, col_name, format)
        worksheet.autofilter(0, 0, 0, len(dataframe.columns) - 1)
        worksheet.freeze_panes(1, 0)
        # loop through the columns in the dataframe to get the width of the column
        for j, col in enumerate(dataframe.columns):
            max_width = max([len(str(s)) for s in dataframe[col].values] + [len(col) + 2])
            # define a max width to not get to wide column
            if max_width > 50:
                max_width = 50
            worksheet.set_column(j, j, max_width)
    writerReport.save()
    return output_dir + output_name

rafat.ch
  • 113
  • 1
  • 7
  • I got following error when i replicated this code: AttributeError: 'str' object has no attribute 'to_excel'. It think it has something to do with the way "dataframe_list" is created. Mine is a list with 6 dataframe names – user3019973 Jul 15 '20 at 13:31
  • Yes, the "dataframe_list" should have dataframes and not dataframe names. – rafat.ch Sep 07 '20 at 13:33
5

Combining the other answers and comments and also supporting multi-indices:

def autosize_excel_columns(worksheet, df):
  autosize_excel_columns_df(worksheet, df.index.to_frame())
  autosize_excel_columns_df(worksheet, df, offset=df.index.nlevels)

def autosize_excel_columns_df(worksheet, df, offset=0):
  for idx, col in enumerate(df):
    series = df[col]
    max_len = max((
      series.astype(str).map(len).max(),
      len(str(series.name))
    )) + 1
    worksheet.set_column(idx+offset, idx+offset, max_len)

sheetname=...
df.to_excel(writer, sheet_name=sheetname, freeze_panes=(df.columns.nlevels, df.index.nlevels))
worksheet = writer.sheets[sheetname]
autosize_excel_columns(worksheet, df)
writer.save()
kgibm
  • 852
  • 10
  • 22
5

Yes, there is there is something you can do subsequently to the xlsx file to auto-adjust the column widths. Use xlwings to autofit columns. It's a pretty simple solution, see the 6 last lines of the example code. The advantage of this procedure is that you don't have to worry about font size, font type or anything else. Requirement: Excel installation.

import pandas as pd
import xlwings as xw

path = r"test.xlsx"

# Export your dataframe in question.
df = pd._testing.makeDataFrame()
df.to_excel(path)

# Autofit all columns with xlwings.
with xw.App(visible=False) as app:
    wb = xw.Book(path)

    for ws in wb.sheets:
        ws.autofit(axis="columns")

    wb.save(path)
    wb.close()
mouwsy
  • 1,457
  • 12
  • 20
4

you can solve the problem by calling the following function, where df is the dataframe you want to get the sizes and the sheetname is the sheet in excel where you want the modifications to take place

def auto_width_columns(df, sheetname):
        workbook = writer.book  
        worksheet= writer.sheets[sheetname] 
    
        for i, col in enumerate(df.columns):
            column_len = max(df[col].astype(str).str.len().max(), len(col) + 2)
            worksheet.set_column(i, i, column_len)
Michel Kluger
  • 164
  • 1
  • 6
  • 1
    codes only doesn't answer the question you have to add some explanations or take time and read documentation about [How do I write a good answer?](https://stackoverflow.com/help/how-to-answer) – Umutambyi Gad Jul 19 '20 at 16:07
  • 1
    Hello! While this code may solve the question, [including an explanation](https://meta.stackexchange.com/q/114762) of how and why this solves the problem would really help to improve the quality of your post, and probably result in more up-votes. Remember that you are answering the question for readers in the future, not just the person asking now. Please [edit] your answer to add explanations and give an indication of what limitations and assumptions apply. – Brian61354270 Jul 19 '20 at 17:11
  • Good, simple solution here. Keep in mind if you're using an index, `df.columns` will have a different shape than what `df.to_excel(writer,sheet_name=...)` will output in the excel file. That can misalign the `enumerate`'s `i` with what `worksheet.set_column` is expecting. I resolved this with `df.reset_index().to_excel(...)`, but there's probably a better solution. – jmb Jun 04 '21 at 22:06
3
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
Ssubrat Rrudra
  • 870
  • 8
  • 20
3

Please try to use worksheet.autofit() I have reached this method with pip install XlsxWriter==3.0.9

P.S. I'm newbie to writing answers, I apologize for the dryness of the answer.

1

Easiest solution is to specify width of column in set_column method.

    for worksheet in writer.sheets.values():
        worksheet.set_column(0,last_column_value, required_width_constant)
1

This function works for me, also fixes the index width

def write_to_excel(writer, X, sheet_name, sep_only=False):
    #writer=writer object
    #X=dataframe
    #sheet_name=name of sheet
    #sep_only=True:write only as separate excel file, False: write as sheet to the writer object
    if sheet_name=="": 
        print("specify sheet_name!")
    else:
        X.to_excel(f"{output_folder}{prefix_excel_save}_{sheet_name}.xlsx")
        if not sep_only: 
            X.to_excel(writer, sheet_name=sheet_name)
            
            #fix column widths
            worksheet = writer.sheets[sheet_name]  # pull worksheet object
            for idx, col in enumerate(X.columns):  # loop through all columns
                series = X[col]
                max_len = max((
                    series.astype(str).map(len).max(),  # len of largest item
                    len(str(series.name))  # len of column name/header
                    )) + 1  # adding a little extra space
                worksheet.set_column(idx+1, idx+1, max_len)  # set column width (=1 because index = 1)
                
            #fix index width
            max_len=pd.Series(X.index.values).astype(str).map(len).max()+1
            worksheet.set_column(0, 0, max_len)
            
        if sep_only: 
            print(f'{sheet_name} is written as seperate file')
        else:
            print(f'{sheet_name} is written as seperate file')
            print(f'{sheet_name} is written as sheet')
    return writer

call example:

writer = write_to_excel(writer, dataframe, "Statistical_Analysis")
1

A lot of valid solutions on here. I think the easiest and cleanest way to achieve is using Microsoft's pywin32 package which closely 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.

Jay Jara
  • 91
  • 4
  • Not platform-independent, but if you can live with that restriction, a pretty elegant solution. +1 – ojdo Apr 09 '23 at 22:10
0

I may be a bit late to the party but this code works when using 'openpyxl' as your engine, sometimes pip install xlsxwriter wont solve the issue. This code below works like a charm. Edit any part as you wish.

def text_length(text):
    """
    Get the effective text length in characters, taking into account newlines
    """
    if not text:
        return 0
    lines = text.split("\n")
    return max(len(line) for line in lines)

def _to_str_for_length(v, decimals=3):
    """
    Like str() but rounds decimals to predefined length
    """
    if isinstance(v, float):
        # Round to [decimal] places
        return str(Decimal(v).quantize(Decimal('1.' + '0' * decimals)).normalize())
    else:
        return str(v)


def auto_adjust_xlsx_column_width(df, writer, sheet_name, margin=3, length_factor=1.0, decimals=3, index=False):

    sheet = writer.sheets[sheet_name]
    _to_str = functools.partial(_to_str_for_length, decimals=decimals)
    # Compute & set column width for each column
    for column_name in df.columns:
        # Convert the value of the columns to string and select the 
        column_length =  max(df[column_name].apply(_to_str).map(text_length).max(), text_length(column_name)) + 5
        # Get index of column in XLSX
        # Column index is +1 if we also export the index column
        col_idx = df.columns.get_loc(column_name)
        if index:
            col_idx += 1
        # Set width of column to (column_length + margin)
        sheet.column_dimensions[openpyxl.utils.cell.get_column_letter(col_idx + 1)].width = column_length * length_factor + margin
    # Compute column width of index column (if enabled)
    if index: # If the index column is being exported
        index_length =  max(df.index.map(_to_str).map(text_length).max(), text_length(df.index.name))
        sheet.column_dimensions["A"].width = index_length * length_factor + margin
Imperial_J
  • 306
  • 1
  • 7
  • 23
0

An openpyxl version based on @alichaudry's code.
The code 1) loads an excel file, 2) adjusts column widths and 3) saves it.

def auto_adjust_column_widths(excel_file : "Excel File Path", extra_space = 1) -> None:
    """
    Adjusts column widths of the excel file and replaces it with the adjusted one.
    Adjusting columns is based on the lengths of columns values (including column names).
    Parameters
    ----------
    excel_file :
        excel_file to adjust column widths.
    
    extra_space : 
        extra column width in addition to the value-based-widths
    """

    from openpyxl import load_workbook
    from openpyxl.utils import get_column_letter


    wb = load_workbook(excel_file)

    
    for ws in wb:
        df = pd.DataFrame(ws.values,)

        
        for i,r in (df.astype(str).applymap(len).max(axis=0) + extra_space).iteritems():
            ws.column_dimensions[get_column_letter(i+1)].width = r

    
    wb.save(excel_file)
Crispy13
  • 230
  • 1
  • 3
  • 16
0

attention, in previuos answers a lot of outdated methods and hard crutches.

FutureWarning: save is not part of the public API, usage can give unexpected results and will be removed in a future version
  writer.save()

i found an easy solution for this old, but important problem:

from UliPlot.XLSX import auto_adjust_xlsx_column_width

with pd.ExcelWriter("example.xlsx") as writer:
    df.to_excel(writer, sheet_name="MySheet")
    auto_adjust_xlsx_column_width(df, writer, sheet_name="MySheet", margin=1)

THAT IS ALL YOU NEED

the decision is not mine, so I have to post a link to the author, you can thank him

papadulo
  • 3
  • 2
0

Since you are using openpyxl engine, you can try this below solution. The columns get adjusted automatically

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
Mounesh
  • 561
  • 5
  • 18