前回までの作業で、Microsoft Excelファイルの特定のセルにデータをハメ込む方法を実装した。実装にはPandasとOpenPyXLを使い、スクリプトとして扱いやすくなるようにArgparseでオプションを処理した。

今回はExcelのセルを装飾する方法を説明する。まずは、フォントを赤くしてみよう。

連載「PythonでExcel作業の効率化を図ろう」のこれまでの回はこちらを参照

マイナスの請求データに対応する

前回に使用した請求データExcelデータに、次のスクリーンショットのようにマイナスの請求価格の項目を追加する。

  • 7行目にマイナスの単価データを追加

    7行目にマイナスの単価データを追加

このデータは割引ということで単価がマイナスの値になっている。前回までのスクリプトであればこの項目も問題なくはめ込みが行われるが、マイナスに値になっているのでほかの単価とはちょっと違う表示になるようにしたい。

ここではこの文字を赤く、そして目立つように太字にするように装飾を行うことにする。OpenPyXLはそうした装飾に対応しているので、OpenPyXLを使うことになる。

文字を赤くする機能を追加する

それでは先に、今回の目的を達成するために書き換えたスクリプトを次に示す。

gen_invoice_3.py

import argparse
import openpyxl
import pandas

from openpyxl.styles import Font

#=========================================================================
# 初期値を設定
#=========================================================================
invoice_template_xlsx_file_path = '税の計算を含むサービス請求書.xlsx'
invoice_template_sheet_name = 'サービス請求書'
invoice_output_xlsx_file_path = 'サンプルファイル.xlsx'
billing_company_data_xlsx_file_path = '請求先データ.xlsx'
billing_data_xlsx_file_path = '請求データ.xlsx'
billing_company_name = 'マイナビシステムズD'
billing_month = '202401'
sales_tax_rate = 0.1

#=========================================================================
# コマンドライン引数を解析
#=========================================================================
parser = argparse.ArgumentParser(description='Excelデータファイルから指定された会社の指定された月の請求データを抽出します。')
parser.add_argument('-t', '--templateexcel', help='請求書テンプレートExcelファイルのパス')
parser.add_argument('-s', '--templatesheetname', help='請求書テンプレートのシート名')
parser.add_argument('-o', '--outputexcel', help='請求書出力Excelファイルのパス')
parser.add_argument('-b', '--billingexcel', help='請求データExcelファイルのパス')
parser.add_argument('-c', '--companyexcel', help='会社データExcelファイルのパス')
parser.add_argument('-n', '--name', help='検索する会社名')
parser.add_argument('-m', '--month', help='対象月')
parser.add_argument('-x', '--salestaxrate', help='消費税率')
args = parser.parse_args()

if args.templateexcel:
    invoice_template_xlsx_file_path = args.templateexcel
if args.templatesheetname:
    invoice_template_sheet_name = args.templatesheetname
if args.outputexcel:
    invoice_output_xlsx_file_path = args.outputexcel
if args.companyexcel:
    billing_company_data_xlsx_file_path = args.companyexcel
if args.billingexcel:
    billing_data_xlsx_file_path = args.billingexcel
if args.name:
    billing_company_name = args.name
if args.month:
    billing_month = args.month
if args.salestaxrate:
    sales_tax_rate = args.salestaxrate

#=========================================================================
# 指定された会社の会社データを取得
#=========================================================================
dataframe = pandas.read_excel(billing_company_data_xlsx_file_path)
company_data = dataframe[
    dataframe[dataframe.columns[0]] == billing_company_name
]

#=========================================================================
# 指定された会社の指定された月の請求データを取得
#=========================================================================
dataframe = pandas.read_excel(billing_data_xlsx_file_path, dtype={'対象月': str})
billing_data = dataframe[
    (dataframe[dataframe.columns[0]] == billing_company_name) &
    (dataframe[dataframe.columns[1]] == billing_month)
]

#=========================================================================
# 請求書テンプレートの読み込み
#=========================================================================
workbook = openpyxl.load_workbook(invoice_template_xlsx_file_path)
sheet = workbook[invoice_template_sheet_name]

#=========================================================================
# 請求データを書き込み
#=========================================================================
i = company_data.index[0]

name = company_data.at[i,'会社名']
zip = company_data.at[i,'郵便番号']
address = company_data.at[i,'住所']
tel = company_data.at[i,'電話番号']
charge = company_data.at[i,'請求先名']
email = company_data.at[i,'メールアドレス']

# 請求先企業
sheet['B7'] = charge
sheet['B8'] = name
sheet['B9'] = zip
sheet['B10'] = address
sheet['B11'] = tel

# 請求書
sheet['E4'] = '000-01-001'
sheet['E5'] = '月次請求'

# 消費税
sheet['E24'] = sales_tax_rate

# 請求内容
i = 13
for index, row in billing_data.iterrows():
    sheet.cell(row=i, column=2).value = row['項目名']
    sheet.cell(row=i, column=3).value = row['数']
    sheet.cell(row=i, column=4).value = row['単価']

    # 請求金額がマイナスだった場合には前景色を赤に、スタイルを太字に変える
    if row['単価'] < 0:
        sheet.cell(row=i, column=4).font = Font(color="FF0000", bold=True)

    i = i + 1

#=========================================================================
# 請求書ファイルを作成
#=========================================================================
workbook.save(invoice_output_xlsx_file_path

ほとんどは前回に紹介した「gen_invoice_2.py」と同じだ。gen_invoice_2.pyに赤字の装飾を行う部分を追加してgen_invoice_3.pyを作ってある。

まず、ファイルの先頭の方に次の行を追加してopenpyxl.styles.FontをFontという短縮名で扱えるようにしている。

openpyxl.styles.FontをFontで扱えるように設定

from openpyxl.styles import Font

そして請求データをハメ込む処理を次のように変更している。

請求データをハメ込む部分を書き換え

# 請求内容
i = 13
for index, row in billing_data.iterrows():
    sheet.cell(row=i, column=2).value = row['項目名']
    sheet.cell(row=i, column=3).value = row['数']
    sheet.cell(row=i, column=4).value = row['単価']

    # 請求金額がマイナスだった場合には前景色を赤に、スタイルを太字に変える
    if row['単価'] < 0:
        sheet.cell(row=i, column=4).font = Font(color="FF0000", bold=True)

    i = i + 1

具体的にはデータをはめ込んだあとで次の処理を追加している。これがセルの前景色を赤くする処理だ。

セルの前景色を赤くする処理

    # 請求金額がマイナスだった場合には前景色を赤に、スタイルを太字に変える
    if row['単価'] < 0:
        sheet.cell(row=i, column=4).font = Font(color="FF0000", bold=True)

まず、if row['単価'] < 0:として単価がマイナスかどうかを判定している。この判定が真値だった場合にsheet.cell(row=i, column=4).font = Font(color="FF0000", bold=True)の処理を行っている。「Font(color="FF0000", bold=True)」が「赤、ボールド」という装飾を意味しており、これをsheet.cell(row=i, column=4).fontに代入して装飾を上書きしている。今回はこの処理で十分に目的を達することができる。