CHAPTER 6 ・ pandas を一歩進める / Lesson 27
見やすいExcelを出力する
複数シート、列幅、数字の書式、ヘッダーの色。そのまま上司に渡せる帳票を、Pythonで作ります。
このレッスンが終わったら
「ExcelWriter で複数シートに書き、openpyxl で列幅や数字の書式を整えられる」と言える。
こんな場面、ありませんか?
集計した結果を、上司や他部署に渡すために、Excelで出したい。基礎編で学んだ to_excel で書き出すと、確かに、Excelファイルはできます。ただ、そのまま渡すには、少し物足りない仕上がりです。
まず、何も整えずに書き出した結果を、openpyxl(Excelファイルを読み書きする道具)で読み直して、列幅や書式を確かめます。
この欄では、サンプルファイルが使えます。実行のたびに、ファイルは最初の状態に戻ります。
▶ 実行を押すと、ここに結果が出ます
値は入っていますが、列幅は標準のまま(13)、金額の書式は General(桁区切りなし)、見出しに色はなく、ウィンドウ枠の固定もありません(None)。この回では、これらを整えます。
複数のシートに書き出す
1つのExcelファイルの中に、複数のシートを作ります。合計のシートと、部署ごとの明細のシートです。pd.ExcelWriter を with で開き、sheet_name でシートの名前を指定して、何度も書き込みます。
この欄では、サンプルファイルが使えます。実行のたびに、ファイルは最初の状態に戻ります。
▶ 実行を押すと、ここに結果が出ます
シートが4枚(合計・企画・営業・総務)できました。startrow=2 は、「表を、3行目から書き始める」指定です。上の2行を空けておいて、あとで表題を書くために使います。
仕組みを読む
役割は、2つに分かれます。値を書くのは pandas、見た目を整えるのは openpyxl です。
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桁の色コードで指定します。
変えて、試す
① 列幅・桁区切り・見出しの色。 合計シートを整えて、読み直して確かめます。
この欄では、サンプルファイルが使えます。実行のたびに、ファイルは最初の状態に戻ります。
▶ 実行を押すと、ここに結果が出ます
列幅は 16、金額の書式は #,##0 になりました。列幅は「半角文字が何個入るか」で数えるので、日本語(全角)は1文字で2個ぶんです。B2 の値は 251000 のままです。表示形式を変えても、中の値は数字のままで、Excelで開くと 251,000 と見えます。
② 帳票として仕上げる。 合計シートに表題と合計行を足し、部署別シートには、見出し行の固定とオートフィルターを付けます。
この欄では、サンプルファイルが使えます。実行のたびに、ファイルは最初の状態に戻ります。
▶ 実行を押すと、ここに結果が出ます
シートの名前、表題、合計の値、固定した位置、フィルターの範囲が、思いどおりに入っています。これが、読み直して確かめるということです。自分のパソコンで動かして Excel で開けば、見出しが紺色で、金額に桁区切りが付いた表が見られます。
③ 数式は、書けるが、Pythonでは結果が見えない。 ws["B7"] = "=SUM(B4:B6)" のように、Excelの数式も書けます。ただし、計算結果は、Excelで開くまで保存されません。
この欄では、サンプルファイルが使えます。実行のたびに、ファイルは最初の状態に戻ります。
▶ 実行を押すと、ここに結果が出ます
1行目は数式の文字、2行目(計算結果)は None です。Excelで開けば 300 と表示されますが、Pythonで読み直しても、結果は取れません。Pythonであとから値を使う帳票は、数式ではなく、計算した値を書いておくのが安全です。
自分で書く
お題① orders.csv を、「営業」の行と「企画」の行に分けて、1つのExcelファイルの2つのシートに書き出してください。読み直して、シート名の一覧を表示します。
この欄では、サンプルファイルが使えます。実行のたびに、ファイルは最初の状態に戻ります。
▶ 実行を押すと、ここに結果が出ます
ヒントを見る
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列の幅を表示します。
この欄では、サンプルファイルが使えます。実行のたびに、ファイルは最初の状態に戻ります。
▶ 実行を押すと、ここに結果が出ます
ヒントを見る
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 の表示形式を表示します。
この欄では、サンプルファイルが使えます。実行のたびに、ファイルは最初の状態に戻ります。
▶ 実行を押すと、ここに結果が出ます
ヒントを見る
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)仕事ならどう使う?
理解チェックセルの number_format を "#,##0" にしました。セルの中身は、どうなりますか?
理解チェックws["B7"] = "=SUM(B4:B6)" で書いたExcelを、Pythonの openpyxl で(data_only=True で)読み直すと、B7 は?