Skip to content

XlsxWriterでExcelファイルを保存する際のエラー対処法

markdown
## 問題: 'XlsxWriter'オブジェクトに'save'属性がないエラー

PandasでExcelファイルを操作する際、`XlsxWriter`をエンジンとして使用している場合、以下のようなエラーが発生することがあります:

```python
AttributeError: 'XlsxWriter' object has no attribute 'save'. Did you mean: '_save'?

このエラーは主に、Excelファイルの保存処理で非推奨となった.save()メソッドを使用しようとした際に発生します。

エラーの原因となる典型的なコード

python
writer = pd.ExcelWriter('output.xlsx', engine='xlsxwriter')
# ... Excel操作のコード ...
writer.save()  # ここでAttributeErrorが発生

エラーの背景

  • Pandas 1.5.0(2020年リリース)以降、ExcelWriter.save()メソッドは非推奨となりました
  • Pandas 2.1.0(2023年リリース)では完全に削除され、代わりに.close()メソッドを使用する必要があります
  • 公式ドキュメントではclose()を推奨していますが、古いチュートリアルではsave()が使われている場合があります

解決策: close()メソッドの使用

最も簡単で推奨される方法は、save()の代わりにclose()を使用することです:

python
writer = pd.ExcelWriter('output.xlsx', engine='xlsxwriter')
# ... データ処理やチャート追加などの操作 ...

writer.close()  # ファイルを保存して閉じる

実践的コード例

python
import pandas as pd
import xlsxwriter

# サンプルデータ作成
data = {
    "Name": ["山田太郎", "佐藤花子", "鈴木一郎"],
    "年齢": [28, 32, 45],
    "性別": ["男性", "女性", "男性"]
}
df = pd.DataFrame(data)

# ExcelWriterオブジェクトの作成
writer = pd.ExcelWriter("社員データ.xlsx", engine="xlsxwriter")

# DataFrameをExcelに書き出し
df.to_excel(writer, sheet_name="社員一覧", index=False)
df.to_excel(writer, sheet_name="Sheet1")

# ワークブックとワークシートの取得
workbook = writer.book
worksheet = writer.sheets["Sheet1"]

# 折れ線グラフの追加
chart = workbook.add_chart({"type": "line"})
chart.add_series({
    "values": "=Sheet1!$B$2:$B$4",
    "categories": "=Sheet1!$A$2:$A$4",
    "name": "年齢推移"
})

# グラフをシートに挿入
worksheet.insert_chart("D2", chart)

# ファイルの保存(closeを使用)
writer.close()

close()メソッドの重要な特徴

  • ファイルを保存し、同時にリソースを解放
  • Excelファイル操作が確実に完了することを保証
  • バージョン1.5.0以上のPandasで正しく動作
  • ファイルの書き込み後は編集不可能

ベストプラクティス: with文を利用したコンテキストマネージャー

さらに安全で現代的な方法は、with文を使用してファイル操作を行うことです。この方法では、ファイルのクローズ忘れを防ぎ、例外発生時も確実にリソースを解放します。

python
import pandas as pd
import xlsxwriter

df = pd.DataFrame({
    "商品名": ["ノートPC", "スマートフォン", "タブレット"],
    "販売数": [150, 300, 200],
    "単価": [120000, 80000, 60000]
})

with pd.ExcelWriter("販売データ.xlsx", engine="xlsxwriter") as writer:
    df.to_excel(writer, sheet_name="月次売上", index=False)
    
    workbook = writer.book
    worksheet = writer.sheets["月次売上"]
    
    # 棒グラフの作成
    chart = workbook.add_chart({"type": "column"})
    chart.add_series({
        "values": "='月次売上'!$C$2:$C$4",
        "categories": "='月次売上'!$A$2:$A$4",
        "name": "各商品の販売数"
    })
    chart.set_title({"name": "月別商品販売数比較"})
    worksheet.insert_chart("E2", chart)

::: success with文の利点

  1. 自動リソース解放 - ブロックを抜けると自動でclose()が実行される
  2. 例外安全性 - 途中でエラーが発生してもファイルが確実に閉じられる
  3. コードの可読性向上 - ファイル操作の範囲が明確になる
  4. メモリリーク防止 - リソースの解放忘れが起きない :::

補足: Excelチャート作成時の注意点

チャートを追加する際は、データ範囲の指定が非常に重要です。よくある間違いと解決策:

一般的な間違い

python
# 誤った範囲指定 (Sheet名の後に「.$」が残っている)
chart.add_series({"values": "=Sheet1.$B$2:$B$4"})

正しい指定方法

python
# 「!」でシート名とセル範囲を区切る
chart.add_series({"values": "=Sheet1!$B$2:$B$4"})
チャート範囲指定のベストプラクティス
  1. 完全修飾シート名を使用: 'Sheet Name'!A1:B10
  2. シート名にスペースがある場合は必ず引用符で囲む
  3. セル参照は絶対参照($A$1)で指定すると安全
  4. 動的に範囲を指定したい場合:
    python
    # 行数を動的に取得
    max_row = len(df) + 1
    chart.add_series({
        "values": f"=Sheet1!$B$2:$B${max_row}",
        "categories": f"=Sheet1!$A$2:$A${max_row}"
    })

対応バージョン情報

ライブラリ推奨バージョン非推奨メソッドを含むバージョン
Pandas2.1.0以上1.5.0(警告)~2.1.0(削除)
XlsxWriter3.0.3以上全バージョンでsave属性なし

最新の環境では、close()メソッドまたはwith文の使用が必須となります。古いコードでsave()を使用している場合は、即座に修正することをお勧めします。