2018年3月19日月曜日

openpyxlで行のグルーピング

PythonでExcelを読み書きするライブラリの1つとして、openpyxlがあります。
公式サイトには列のグルーピングについては記載されていましたが、行のグルーピングについては記載されていませんでした。
ソースを参照しながら工夫したらどうにかできたので公開します。
今後公式から行のグルーピングについてアナウンスされるかもしれませんので、ご留意ください。
以下、ソースです。



# -*- coding:utf-8 -*-

from openpyxl import Workbook
from openpyxl.worksheet.dimensions import RowDimension

data = [('スポーツ', '売上高'),
        [[('ゴルフ', 500000),
          ('ゴルフ', 200000),
          ('ゴルフ', 150000)],
         ('ゴルフ合計', '=SUBTOTAL(9,B2:B4)')],
        [[('サファリ', 900000),
          ('サファリ', 400000)],
         ('サファリ合計', '=SUBTOTAL(9,B6:B7)')],
        [[('テニス', 180000),
          ('テニス',  20000)],
         ('テニス合計', '=SUBTOTAL(9,B9:B10)')],
        ('総計', '=SUBTOTAL(9,B2:B10)')]


def write_data(sheet, data, row=1, level=0):
    print(sheet, data, row, level)
    _row = row
    for item in data:
        if isinstance(item, tuple):
            for col in range(len(item)):
                sheet.cell(_row, col+1, value=item[col])
            sheet.row_dimensions[_row] = RowDimension(sheet,
                                                      index=_row,
                                                      outline_level=level,
                                                      hidden=(level != 0))
            _row += 1
            continue
        _row += write_data(sheet, item, row=_row, level=level+1)
    wrote_count = _row - row
    return wrote_count


book = Workbook()
sheet = book.active

write_data(sheet, data)

book.save('grouping.xlsx')

dataはワークシートのデータ リストに小計を挿入するをもとにしました。
tupleがExcelの行に対応し、listはグループに対応します。集計行を手で書いているのがいけてないです。
write_data関数が再起呼び出しになっています。

ポイントは、Worksheetオブジェクトのrow_dimensionsプロパティへRowDimensionオブジェクトをセットするところです。
row_dimensionsプロパティは辞書のようなオブジェクトです。キーがかぶらなければいいだろうということで、行番号をキーとして使用しています。

プログラムを実行すると、次のようなExcelファイルが出力されます。
出力直後はすべて折り畳まれた状態(1行目と12行目のみ表示された状態)です。

イマイチ歪な方法ではありますが、Excelの小計機能相当のプログラムが書けました。
さらに発展させて、集計結果に対して関数を適用するなども可能かと思います。

参考
openpyxl


0 件のコメント:

コメントを投稿