CHAPTER 6 ・ pandas を一歩進める / Lesson 27

見やすいExcelを出力する

複数シート、列幅、数字の書式、ヘッダーの色。そのまま上司に渡せる帳票を、Pythonで作ります。

目安 25分 ・ インストール不要

このレッスンが終わったら

「ExcelWriter で複数シートに書き、openpyxl で列幅や数字の書式を整えられる」と言える。

STEP 1

こんな場面、ありませんか?

集計した結果を、上司や他部署に渡すために、Excelで出したい。基礎編で学んだ to_excel で書き出すと、確かに、Excelファイルはできます。ただ、そのまま渡すには、少し物足りない仕上がりです。

まず、何も整えずに書き出した結果を、openpyxl(Excelファイルを読み書きする道具)で読み直して、列幅や書式を確かめます。

to_excel だけで書き出して、読み直すpandas・サンプルファイル付き
Ctrl / ⌘ + Enter でも実行

この欄では、サンプルファイルが使えます。実行のたびに、ファイルは最初の状態に戻ります。

結果
▶ 実行を押すと、ここに結果が出ます

値は入っていますが、列幅は標準のまま(13)、金額の書式は General(桁区切りなし)、見出しに色はなく、ウィンドウ枠の固定もありません(None)。この回では、これらを整えます。

STEP 2

複数のシートに書き出す

1つのExcelファイルの中に、複数のシートを作ります。合計のシートと、部署ごとの明細のシートです。pd.ExcelWriter を with で開き、sheet_name でシートの名前を指定して、何度も書き込みます。

合計シートと、部署別シートを作るpandas・サンプルファイル付き
Ctrl / ⌘ + Enter でも実行

この欄では、サンプルファイルが使えます。実行のたびに、ファイルは最初の状態に戻ります。

結果
▶ 実行を押すと、ここに結果が出ます

シートが4枚(合計・企画・営業・総務)できました。startrow=2 は、「表を、3行目から書き始める」指定です。上の2行を空けておいて、あとで表題を書くために使います。

STEP 3

仕組みを読む

役割は、2つに分かれます。値を書くのは pandas、見た目を整えるのは openpyxl です。

ExcelWriter の流れを日本語にしてみる
with pd.ExcelWriter("report.xlsx", engine="openpyxl") as writer:report.xlsx に書き込む準備をして、writer と呼ぶ。with を抜けると、保存して閉じる
summary.to_excel(writer, sheet_name="合計", ...)writer の中の「合計」シートに、表を書く
ws = writer.sheets["合計"]書き込んだ「合計」シートを取り出して、ws と呼ぶ。ここから見た目を整える

ExcelWriterは、「1つのExcelファイルに、何回かに分けて書き込む」ための道具です。ws に指定できる、主な見た目は次のとおりです。

整えたいこと書き方
列の幅ws.column_dimensions["A"].width = 16
数字の表示形式(桁区切り)cell.number_format = "#,##0"
太字・文字色cell.font = Font(bold=True, color="FFFFFF")
背景色cell.fill = PatternFill("solid", fgColor="1F4E78")
ウィンドウ枠の固定ws.freeze_panes = "A2"(1行目を固定)
オートフィルターws.auto_filter.ref = ws.dimensions

色は、1F4E78 のような6桁の色コードで指定します。

STEP 4

変えて、試す

① 列幅・桁区切り・見出しの色。 合計シートを整えて、読み直して確かめます。

合計シートの見た目を整えるpandas・サンプルファイル付き
Ctrl / ⌘ + Enter でも実行

この欄では、サンプルファイルが使えます。実行のたびに、ファイルは最初の状態に戻ります。

結果
▶ 実行を押すと、ここに結果が出ます

列幅は 16、金額の書式は #,##0 になりました。列幅は「半角文字が何個入るか」で数えるので、日本語(全角)は1文字で2個ぶんです。B2 の値は 251000 のままです。表示形式を変えても、中の値は数字のままで、Excelで開くと 251,000 と見えます。

② 帳票として仕上げる。 合計シートに表題と合計行を足し、部署別シートには、見出し行の固定とオートフィルターを付けます。

部署別シート+合計シートの帳票pandas・サンプルファイル付き
Ctrl / ⌘ + Enter でも実行

この欄では、サンプルファイルが使えます。実行のたびに、ファイルは最初の状態に戻ります。

結果
▶ 実行を押すと、ここに結果が出ます

シートの名前、表題、合計の値、固定した位置、フィルターの範囲が、思いどおりに入っています。これが、読み直して確かめるということです。自分のパソコンで動かして Excel で開けば、見出しが紺色で、金額に桁区切りが付いた表が見られます。

③ 数式は、書けるが、Pythonでは結果が見えない。 ws["B7"] = "=SUM(B4:B6)" のように、Excelの数式も書けます。ただし、計算結果は、Excelで開くまで保存されません。

数式を書いて、読み直すpandas・サンプルファイル付き
Ctrl / ⌘ + Enter でも実行

この欄では、サンプルファイルが使えます。実行のたびに、ファイルは最初の状態に戻ります。

結果
▶ 実行を押すと、ここに結果が出ます

1行目は数式の文字、2行目(計算結果)は None です。Excelで開けば 300 と表示されますが、Pythonで読み直しても、結果は取れません。Pythonであとから値を使う帳票は、数式ではなく、計算した値を書いておくのが安全です。

STEP 5

自分で書く

お題① orders.csv を、「営業」の行と「企画」の行に分けて、1つのExcelファイルの2つのシートに書き出してください。読み直して、シート名の一覧を表示します。

お題①:2つのシートに分けて書くpandas・サンプルファイル付き
Ctrl / ⌘ + Enter でも実行

この欄では、サンプルファイルが使えます。実行のたびに、ファイルは最初の状態に戻ります。

結果
▶ 実行を押すと、ここに結果が出ます
ヒントを見る

with pd.ExcelWriter("two.xlsx", engine="openpyxl") as writer: の中で、orders[orders["部署"] == "営業"].to_excel(writer, sheet_name="営業", index=False) のように2回書きます。読み直しは pd.ExcelFile("two.xlsx").sheet_names です。

答えの例を見る
import pandas as pd

orders = pd.read_csv("orders.csv")

with pd.ExcelWriter("two.xlsx", engine="openpyxl") as writer:
  orders[orders["部署"] == "営業"].to_excel(writer, sheet_name="営業", index=False)
  orders[orders["部署"] == "企画"].to_excel(writer, sheet_name="企画", index=False)

print(pd.ExcelFile("two.xlsx").sheet_names)

お題② 部署別の合計を書き出すときに、A列の幅を 20 にしてください。読み直して、A列の幅を表示します。

お題②:A列の幅を 20 にするpandas・サンプルファイル付き
Ctrl / ⌘ + Enter でも実行

この欄では、サンプルファイルが使えます。実行のたびに、ファイルは最初の状態に戻ります。

結果
▶ 実行を押すと、ここに結果が出ます
ヒントを見る

ws.column_dimensions["A"].width = 20 と書きます。ws は、with の中で取り出したシートです。

答えの例を見る
import pandas as pd
from openpyxl import load_workbook

summary = pd.read_csv("orders.csv").groupby("部署", as_index=False)["金額"].sum()

with pd.ExcelWriter("summary.xlsx", engine="openpyxl") as writer:
  summary.to_excel(writer, sheet_name="合計", index=False)
  ws = writer.sheets["合計"]
  ws.column_dimensions["A"].width = 20

print(load_workbook("summary.xlsx")["合計"].column_dimensions["A"].width)

お題③ 金額の列(B列)の、2行目から最終行までに、桁区切りの表示形式 #,##0 を付けてください。読み直して、B2 と B4 の表示形式を表示します。

お題③:金額に桁区切りの書式を付けるpandas・サンプルファイル付き
Ctrl / ⌘ + Enter でも実行

この欄では、サンプルファイルが使えます。実行のたびに、ファイルは最初の状態に戻ります。

結果
▶ 実行を押すと、ここに結果が出ます
ヒントを見る

for row in range(2, ws.max_row + 1): で行を回し、ws.cell(row=row, column=2).number_format = "#,##0" と書きます。

答えの例を見る
import pandas as pd
from openpyxl import load_workbook

summary = pd.read_csv("orders.csv").groupby("部署", as_index=False)["金額"].sum()

with pd.ExcelWriter("summary.xlsx", engine="openpyxl") as writer:
  summary.to_excel(writer, sheet_name="合計", index=False)
  ws = writer.sheets["合計"]
  for row in range(2, ws.max_row + 1):
      ws.cell(row=row, column=2).number_format = "#,##0"

ws = load_workbook("summary.xlsx")["合計"]
print(ws["B2"].number_format)
print(ws["B4"].number_format)
STEP 6

仕事ならどう使う?

理解チェックセルの number_format を "#,##0" にしました。セルの中身は、どうなりますか?

理解チェックws["B7"] = "=SUM(B4:B6)" で書いたExcelを、Pythonの openpyxl で(data_only=True で)読み直すと、B7 は?