有没有一种方法可以使用pandas.ExcelWriter自动调整Excel列的宽度?


99

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

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

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

我正在查看pandas代码,但实际上没有看到任何设置列宽的选项。宇宙中是否有技巧可以使列自动调整为数据?还是在事实之后我可以对xlsx文件做一些事情来调整列宽?

(我正在使用OpenPyXL库,并生成.xlsx文件-如果有区别的话。)

谢谢。


1
目前尚无法实现,请在github上打开此增强功能的问题(也许还提供PR?)。看起来并不难。
杰夫

谢谢杰夫,我已经提交了这个问题。我不确定我是否有时间去深入研究熊猫代码库来解决它,但您永远不知道:)
badideas 2013年

是的....看到您的问题.....如果需要帮助,请对此问题发表评论!(本质上需要将一个可选参数传递给to_excel,可能col_style=dict包含col标头样式元素(而不是默认值header_style,现在似乎已经对其进行了硬编码
Jeff

Answers:


56

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

7
仅供参考:就我而言,我需要在“ df.to_excel(...)”调用中使用“ index = False”,否则列将被关闭1
denvar

1
是的,我还必须添加df.to_excel(writer,sheet_name = sheetname,index = False)
Heikki Pulkkinen

2
如果您不能使用index = False(因为行上有一个多索引),则可以使用df.index.nlevels获得索引级别的深度,然后将其用于添加到您设置的列调用中:worksheet.set_column(idx+nlevels, idx+nlevels, max_len)。否则,将计算框架第一列的长度,然后将其应用于 excel中的第一列,这很可能是索引。
ac24

1
对于仍在寻找此答案的任何人,enumerate(df)应该是enumerate(df.columns)因为您要遍历中的每一列df
Dascienz

2
@Dascienz以相同的方式遍历a中dict的键dict(实际上不必dict.keys()遍历)(遍历pd.DataFrame列中的遍历)。您不必手动进行迭代df.columns
alichaudry

26

我发布此消息是因为我遇到了同样的问题,发现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()

1
好的解决方案。我喜欢您使用熊猫而不是其他包裹的方式。

我认为您需要()在max函数内部:`max(column_len(),len(col))+ 2`
Serdia

21

现在可能尚无自动方法,但是当您使用openpyxl时,以下几行(由Bufke用户改写了有关手动操作的另一答案)允许您指定合理的值(以字符宽度表示):

writer.sheets['Summary'].column_dimensions['A'].width = 15

自2013年以来,默认使用的ExcelWriter引擎pandas已更改为Xlsxwriter,其中不包含column_dimensions属性。如果您想继续使用openpyxl,只需在使用pd.ExcelWriter(excel_filename, engine='openpyxl')
ojdo '19

@Sunil:检查其他答案Xlsxwriter作为引擎,以了解如何使用当今的默认引擎指定列宽。
ojdo

21

我最近开始使用一个不错的程序包,称为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.4版中,best_fit参数已添加到中StyleFrame.to_excel。请参阅文档


StyleFrame包可能易于使用,但是我看不到“默认情况下列宽是自动调整的”。当我运行您提供的代码示例时,所有列的宽度均相同,并且所有三个标头都被换行。样本数据的选择也很差,因为它们的宽度自然都几乎相同。为了真正说明自动调整,您应该选择一些真正的宽数据和一些狭窄的数据。当我为自己执行此操作时,列宽与以前完全相同。没有任何调整。
约翰Y

也许在StyleFrame的历史记录中的某一时刻,默认情况下会自动调整列宽,但是至少在今天,您必须在best_fit参数中指定要调整的一列或多列。另外,当我尝试这样做时,我得到的结果很差
约翰Y

宽度似乎偏离1列。我尝试启用和禁用index参数,但没有骰子。

1
谢谢!对于那些寻找的人:例如,如何在页眉中添加更多样式:sf.apply_headers_style(Styler(bold=False))花了我很长时间才弄清楚。并在import语句中from StyleFrame import StyleFrame, Styler。这里的所有选项除了大胆:styleframe.readthedocs.io/en/2.0.5/...
尼基尔VJ

不幸的是,这个答案已经过时,并且由于API似乎已经发生了很大的变化,如果尝试应用它,我只会遇到导入错误。
哈格巴德

10

通过使用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()

4

我发现基于列标题而不是列内容来调整列更有用。

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

请参阅下面的完整代码:

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

4

在工作中,我总是将数据帧写入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()
    writerReport.close()
    return output_dir + output_name

复制此代码时出现以下错误:AttributeError:'str'对象没有属性'to_excel'。它认为与“ dataframe_list”的创建方式有关。我的是一个有6个数据

是的,“ dataframe_list”应具有数据框,而不应具有数据框名称。
rafat.ch

4

动态调整所有列长

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)

使用列名手动调整列

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

2

结合其他答案和评论,还支持多索引:

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

2
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

1

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

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

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

1
代码仅不能回答您必须添加一些解释或花时间并阅读有关如何编写一个好的答案的
Gad

1
你好!尽管这段代码可以解决问题,但包括解释如何以及为何解决该问题的说明,确实可以帮助提高您的帖子质量,并可能导致更多的投票。请记住,您将来会为读者回答问题,而不仅仅是现在问的人。请编辑您的答案以添加说明,并指出适用的限制和假设。
布赖恩
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.