何をやりたいテクニックなのか
ゴールはこうです。
「pandas の DataFrame を Excel に書き出すとき、
列幅を“中身にちょうどいい幅”に自動調整したい」
xlsxwriter をエンジンに使い、worksheet.set_column() に「計算した幅」を渡すことで実現します。
ポイントは、
- まず普通に
to_excelで書き出す - DataFrame の中身(ヘッダー+データ)から「最大文字数」を列ごとに計算する
- その文字数をもとに
set_columnで列幅を設定する
という三段構えです。
基本パターンの全体像
最小の「自動列幅調整つき to_excel」
import pandas as pd
df = pd.DataFrame({
"日付": ["2025-01-01", "2025-01-02"],
"商品": ["りんご", "みかん"],
"金額": [1000, 123456]
})
with pd.ExcelWriter("auto_width.xlsx", engine="xlsxwriter") as writer:
df.to_excel(writer, sheet_name="売上", index=False)
workbook = writer.book
worksheet = writer.sheets["売上"]
for i, col in enumerate(df.columns):
col_data = df[col].astype(str).tolist()
col_data.append(str(col))
max_len = max(len(s) for s in col_data)
width = max_len + 2
worksheet.set_column(i, i, width)
Pythonこれで、「ヘッダー+その列の中で一番長い値」に合わせて、
各列の幅が自動的に調整された Excel ができます。
ここから、重要な部分を一つずつ分解していきます。
列幅を決めるための「長さの計算」を理解する
なぜ DataFrame 側で長さを計算するのか
xlsxwriter 自体には「自動で列幅をいい感じにしてくれる」機能はありません。
だから、自分で「この列は何文字くらい必要か」を計算してあげる必要があります。
やっていることはシンプルで、
- その列の全データを文字列に変換する
- 列名(ヘッダー)も候補に入れる
- その中で一番長い文字列の長さを取る
- その長さに少し余裕を足して列幅にする
という流れです。
コードの中身をかみ砕いて読む
for i, col in enumerate(df.columns):
col_data = df[col].astype(str).tolist()
col_data.append(str(col))
max_len = max(len(s) for s in col_data)
width = max_len + 2
worksheet.set_column(i, i, width)
Pythonenumerate(df.columns)
→ 列名と、その列の番号(0,1,2,…)を同時に取る
df[col].astype(str).tolist()
→ その列の値を全部文字列にして、リストにする
col_data.append(str(col))
→ 列名(ヘッダー)も候補に入れる(ヘッダーの方が長いこともある)
max_len = max(len(s) for s in col_data)
→ その列の中で一番長い文字列の長さを求める
width = max_len + 2
→ ぴったりだと窮屈なので、2 文字ぶんくらい余裕を足す
worksheet.set_column(i, i, width)
→ i 列目(A=0, B=1, …)の幅を width に設定する
この「長さを計算して set_column に渡す」というパターンさえ理解すれば、
あとは応用でどうとでもできます。
実務テンプレート:集計結果を自動列幅つきで出す
月次集計をきれいな列幅で出力する例
import pandas as pd
df = pd.read_excel("sales.xlsx", parse_dates=["日付"])
df["金額"] = pd.to_numeric(df["金額"], errors="coerce")
monthly = (
df.assign(月=df["日付"].dt.to_period("M"))
.groupby("月", as_index=False)["金額"].sum()
)
with pd.ExcelWriter("sales_monthly_auto_width.xlsx", engine="xlsxwriter") as writer:
monthly.to_excel(writer, sheet_name="月次集計", index=False)
workbook = writer.book
worksheet = writer.sheets["月次集計"]
for i, col in enumerate(monthly.columns):
col_data = monthly[col].astype(str).tolist()
col_data.append(str(col))
max_len = max(len(s) for s in col_data)
width = max_len + 2
worksheet.set_column(i, i, width)
Pythonこのテンプレートをベースにすれば、
どんな DataFrame でも
どんなシート名でも
「中身に合わせた列幅」で出力できるようになります。
もう少しだけ丁寧にしたバージョン(日本語・数値を意識する)
全角文字やカンマ付き数値を考慮したい場合の工夫
Excel の列幅は「文字数」と完全に 1:1 ではありません。
全角文字は広く見えたり、フォントによっても変わります。
厳密にやり始めるとキリがないので、
現場では「だいたいこれで困らない」くらいの調整で十分です。
例えば、全角文字が多い列には少し余裕を多めに取る、
数値列は固定幅にする、などの工夫もできます。
for i, col in enumerate(df.columns):
col_data = df[col].astype(str).tolist()
col_data.append(str(col))
max_len = max(len(s) for s in col_data)
if df[col].dtype.kind in "if": # 数値列なら
width = max(10, max_len + 2)
else:
width = max_len + 2
worksheet.set_column(i, i, width)
Pythonここでは、
数値列は最低 10 くらいの幅を確保
文字列列は「最大文字数+2」
というざっくりルールを入れています。
よくあるつまずきポイント
なぜ engine=”xlsxwriter” が必要なのか
worksheet.set_column は XlsxWriter のメソッドです。engine="xlsxwriter" を指定していないと、writer.book や writer.sheets[...] が
XlsxWriter のオブジェクトにならず、このメソッドが使えません。
「列幅をいじる」「書式をいじる」など、
Excel の見た目を触りたいときは、必ず engine="xlsxwriter" をセットで書く、
と覚えておいてください。
既存ファイルに追記するときは向いていない
mode="a" で既存ファイルにシート追加したい場合は、engine="openpyxl" を使うのが基本です。
XlsxWriter は「新規作成専用」と割り切ると、
頭の中が整理しやすくなります。
小さな練習アイデア
自分で、文字数のバラバラな列を持つ DataFrame を作って、
- 普通に
to_excelしたもの - 上の「自動列幅調整コード」を使ったもの
の 2 つを出力して、Excel で見比べてみてください。
「列幅をちゃんと調整するだけで、こんなに読みやすさが変わるのか」という感覚が、
一度体験として入ると、このテクニックは手放せなくなります。
