OpenPyXLで自動でエクセルのウィンドウ枠の固定をする

Pythonでエクセルをいじるようになると、見た目の仕上げとしてウィンドウ枠を固定したくなります。

OpenPyXLでウィンドウ枠の固定を自動で設定できるようにします。

テスト用にエクセルを準備する

サンプルデータとして、次のようなエクセルのデータを作成します。

実行すると、pythonのコードと同じディレクトリにtest.xlsxというファイルが出力されます。

import openpyxl
import os

data = {
    'Ken' : { 'Country': 'US', 'Job': 'Artist', 'Age': 56 },
    'Alan' : { 'Country': 'Japan', 'Job': 'Carpenter', 'Age': 27 },
    'Steven' : { 'Country': 'China', 'Job': 'Artist', 'Age': 40 }
}

wb = openpyxl.Workbook()
ws = wb.create_sheet(title='test')

headers = ['Name'] + list(data[list(data.keys())[0]].keys())
for header in headers:
    col = headers.index(header) + 1
    ws.cell(row=1, column=col).value = header
row = 2
for name in data:
    ws.cell(row=row, column=1).value = name
    for header in data[name]:
        col = headers.index(header) + 1
        ws.cell(row=row, column=col).value = data[name][header]
    row += 1

filename = 'test.xlsx'
file_path = os.path.join(os.getcwd(), filename)
wb.remove(wb['Sheet'])
wb.save(file_path)

エクセルのウィンドウ枠の固定をする

作成済みのtest.xlsxを開いて、OpenPyXLのウィンドウ枠の固定の処理をします。

ウィンドウ枠の固定は、ws.freeze_panes=’C3′ で実現しています。

import os
import openpyxl

filename = 'test.xlsx'
file_path = os.path.join(os.getcwd(), filename)
wb = openpyxl.load_workbook(file_path)
ws = wb['test']

ws.freeze_panes = 'C3'

filename = 'test_freeze_panes.xlsx'
file_path = os.path.join(os.getcwd(), filename)
wb.save(file_path)

出力ファイルはこうなります。C3のセルで固定できていることがわかります。

いろいろなデータに対応できるように柔軟なコードにする

現在の実装は、C3という固定値を使っているため、汎用性がありません。

今回のデータを見てみると、1行目はヘッダで、2行目からは各個人の情報が書かれています。
そのため、Nameの列が左端で固定されていて、それより右の情報をスクロールできる状態になっていれば良さそうです。

汎用性のあるコードに修正してみます。

ヘッダがNameとなっている列を自動検出し、列の列名をget_column_letterで取得します。
その列名と2行目を指定して、B2でウィンドウ枠の固定をします。

このコードによって、複数のデータでNameの列がどこにあってもNameの右で固定することができます。

import os
import openpyxl
from openpyxl.utils import get_column_letter, column_index_from_string

filename = 'test.xlsx'
file_path = os.path.join(os.getcwd(), filename)
wb = openpyxl.load_workbook(file_path)
ws = wb['test']

for col in range(1, ws.max_column+1):
    if ws.cell(row=1, column=col).value == 'Name':
        freeze_col_str = get_column_letter(col+1)
        break
ws.freeze_panes = freeze_col_str + str(2)
print(freeze_col_str + str(2))

filename = 'test_freeze_panes_b.xlsx'
file_path = os.path.join(os.getcwd(), filename)
wb.save(file_path)

出力ファイルを見るとNameの右で固定できていることがわかります。