149

我被要求生成一些 Excel 报告。我目前大量使用 pandas 来处理我的数据,所以我很自然地想使用 pandas.ExcelWriter 方法来生成这些报告。然而,固定的列宽是一个问题。

到目前为止我的代码很简单。假设我有一个名为“df”的数据框:

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

我正在查看 pandas 代码,但我并没有看到任何设置列宽的选项。宇宙中是否有一个技巧可以使列自动调整到数据?或者,事后我可以对 xlsx 文件做些什么来调整列宽?

(我正在使用 OpenPyXL 库,并生成 .xlsx 文件——如果这有什么不同的话。)

谢谢你。

4

14 回答 14

84

user6178746 的回答启发,我有以下内容:

# 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()
于 2016-11-10T19:23:47.110 回答
35

我发布这个是因为我刚刚遇到了同样的问题,发现 Xlsxwriter 和 pandas 的官方文档仍然将此功能列为不受支持。我拼凑了一个解决方案,解决了我遇到的问题。我基本上只是遍历每一列并使用 worksheet.set_column 设置列宽 == 该列内容的最大长度。

然而,一个重要的注意事项。此解决方案不适合列标题,仅适合列值。如果您需要改为适合标题,那应该是一个简单的更改。希望这可以帮助某人:)

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()
于 2016-04-11T16:35:12.607 回答
30

我最近开始使用一个不错的包 StyleFrame。

它获取 DataFrame 并让您非常轻松地对其进行样式设置...

默认情况下,列宽是自动调整的。

例如:

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()

您还可以更改列宽:

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

更新 1

在 1.4 版本best_fit中,参数被添加到StyleFrame.to_excel. 请参阅文档

更新 2

这是适用于 StyleFrame 3.xx 的代码示例

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()
于 2015-09-20T13:15:03.697 回答
28

动态调整所有列长

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()

使用列名手动调整列

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

使用列索引手动调整列

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

如果上述任何一项都失败了

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

确保安装xlsxwriter

pip install xlsxwriter

有关更全面的说明,您可以阅读文章如何在 TDS 上使用 Pandas ExcelWriter 自动调整 Excel 列的宽度。

于 2020-05-05T16:15:22.473 回答
23

现在可能没有自动的方法可以做到这一点,但是当您使用 openpyxl 时,以下行(改编自用户Bufke关于如何手动执行的另一个答案)允许您指定一个合理的值(以字符宽度为单位):

writer.sheets['Summary'].column_dimensions['A'].width = 15
于 2013-07-23T13:43:09.303 回答
15

通过使用 pandas 和 xlsxwriter,您可以完成您的任务,下面的代码将在 Python 3.x 中完美运行。有关与熊猫一起使用 XlsxWriter 的更多详细信息,此链接可能很有用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()
于 2019-08-02T03:55:06.357 回答
7

我发现根据列标题而不是列内容调整列更有用。

使用df.columns.values.tolist()我生成列标题列表并使用这些标题的长度来确定列的宽度。

请参阅下面的完整代码:

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
于 2019-08-27T22:44:29.903 回答
5

在工作中,我总是将数据框写入 excel 文件。因此,我没有一遍又一遍地编写相同的代码,而是创建了一个模数。现在我只需将其导入并使用它来编写和格式化 Excel 文件。但是有一个缺点,如果数据帧特别大,则需要很长时间。所以这里是代码:

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

于 2019-11-14T14:38:59.353 回答
4

您可以通过调用以下函数来解决问题,其中 df 是您想要获取大小的数据框,而 sheetname 是您希望进行修改的 excel 中的工作表

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)
于 2020-07-19T15:44:45.187 回答
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
于 2019-05-29T04:34:14.673 回答
3

结合其他答案和评论并支持多指数:

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()
于 2019-05-10T13:52:54.027 回答
1

是的,事后您可以对 xlsx 文件执行一些操作来调整列宽。使用 xlwings自动调整列。这是一个非常简单的解决方案,请参见示例代码的最后六行。此过程的优点是您不必担心字体大小、字体类型或其他任何事情。要求:Excel安装。

import pandas as pd
import xlwings as xw

file_path = r"report_formtting_files.xlsx"

df = pd._testing.makeDataFrame()

writer = pd.ExcelWriter(file_path, engine="xlsxwriter")
df.to_excel(writer, sheet_name="Sheet1", index=False)
workbook = writer.book
worksheet1 = writer.sheets["Sheet1"]
num_format = workbook.add_format({"num_format": '#,##0.00'})
worksheet1.set_column("A:D", cell_format=num_format)
writer.close()

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

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

    wb.save(file_path)
    wb.close()
于 2020-11-02T18:09:21.887 回答
1

此功能对我有用,还修复了索引宽度

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

调用示例:

writer = write_to_excel(writer, dataframe, "Statistical_Analysis")
于 2021-07-22T09:22:44.817 回答
1

最简单的解决方案是在 set_column 方法中指定列的宽度。

    for worksheet in writer.sheets.values():
        worksheet.set_column(0,last_column_value, required_width_constant)
于 2018-10-03T03:35:29.703 回答