pandas.ExcelWriterでExcelの列幅を自動調整する方法はありますか?


99

いくつかのExcelレポートを生成するように求められます。私は現在、データにパンダをかなり多用しています。そのため、当然のことながら、pandas.ExcelWriterメソッドを使用して、これらのレポートを生成します。ただし、固定列幅は問題です。

ここまでのコードは非常に単純です。「df」というデータフレームがあるとします。

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

私はパンダのコードを調べていましたが、列の幅を設定するためのオプションが本当にありません。列がデータに自動調整されるようにするために、宇宙にトリックがありますか?または、列幅を調整するためにxlsxファイルに対して事後に実行できることはありますか?

(私はOpenPyXLライブラリを使用しており、.xlsxファイルを生成しています-違いがある場合)。

ありがとうございました。


1
現時点では可能ではないようです。githubでこの拡張機能の問題を開いてください(そしてPRか?)。難しいことではありません。
ジェフ

ジェフに感謝、私は問題を提出しました。実際にパンダのコードベースに飛び込んで解決する時間があるかどうかはわかりませんが、あなたにはわかりません:)
badideas

うん....あなたの問題を見ました.....あなたがいくつかの助けが必要な場合は、問題についてコメントしてください!(本質的に任意の引数を渡す必要があるto_excelかもしれない、col_style=dictというよりも、デフォルト(COLヘッダーのスタイル要素が含まれているheader_styleハードコードされた、今しているようだ
ジェフ

回答:


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 2018

1
まだこの答えを探している人のために、enumerate(df)あるべきenumerate(df.columns)あなたは内の各列を反復処理しているのでdf
Dascienz 2018

2
@Dascienzはdict、のキーを実際に反復するのと同じ方法でdict(手動で言う必要はありませんdict.keys())、pd.DataFrame列を反復します。手動で反復する必要はありませんdf.columns
alichaudry

26

同じ問題に遭遇し、Xlsxwriterとpandasの公式ドキュメントにこの機能がサポートされていないことが記載されているため、これを投稿します。私が抱えていた問題を解決するソリューションを一緒にハッキングしました。基本的に、各列を繰り返し処理し、worksheet.set_columnを使用して、列の幅==その列のコンテンツの最大長を設定します。

ただし、重要な注意点が1つあります。このソリューションは列ヘッダーに適合せず、単に列値に適合します。代わりにヘッダーを合わせる必要がある場合は、簡単に変更できます。これが誰かを助けることを願っています:)

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エンジンが、column_dimensions属性を含まないXlsxwriterに変更されました。openpyxlを使い続ける場合は、ライターを作成するときにそれを指定しますpd.ExcelWriter(excel_filename, engine='openpyxl')
ojdo

@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パッケージは使いやすいかもしれませんが、「デフォルトでは列幅が自動調整される」のかわかりません。指定したコードサンプルを実行すると、すべての列が同じ幅で、3つのヘッダーすべてがラップされます。また、サンプルデータもすべて自然にほぼ同じ幅であるため、適切に選択されていません。自動調整を実際に説明するには、非常に広いデータと狭いデータを選択する必要があります。私は自分のためにこれを行うと、列幅は、まだ前と全く同じ。調整は一切ありませんでした。
John Y

多分StyleFrameの歴史のある時点で、列幅はデフォルトで自動的に調整されましたが、少なくとも今日では、調整したい列をbest_fitパラメータで指定する必要があります。また、これを試したところ、結果非常に悪かった
John Y

幅が1列ずれているようです。indexパラメータを有効または無効にしてみましたが、サイコロはありませんでした。

1
ありがとう!たとえば、ヘッダーにスタイルを追加する方法:sf.apply_headers_style(Styler(bold=False))それを理解するのに長い時間がかかりました。そして、import文では、from StyleFrame import StyleFrame, Styler。太字以外のすべてのオプションは次のとおり
Nikhil VJ

残念ながら、この回答は古くなっており、APIが大幅に変更されたように見えるため、適用しようとした場合にのみインポートエラーが発生します。
ハバード

10

パンダと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()、列ヘッダーのリストを生成し、これらのヘッダーの長さを使用して列の幅を決定します。

以下の完全なコードを参照してください。

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ファイルを作成および形成します。ただし、欠点が1つあります。データフレームが非常に大きい場合は時間がかかります。だからここにコードです:

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' object has no attribute 'to_excel'。「dataframe_list」の作成方法と関係があるようです。鉱山は6つのデータフレーム名を持つリストです
user3019973

はい。「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
こんにちは!このコードは問題を解決する可能性がありますが、これが問題を解決する方法と理由の説明含めると、投稿の品質が向上し、おそらくより多くの投票が得られます。あなたが今尋ねている人だけでなく、将来の読者のための質問に答えていることを忘れないでください。回答を編集して説明を追加し、適用される制限と前提を示してください。
ブライアン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.