pythonを使用してExcelファイルの操作を勉強しています。
本日の気づき(復習)は、罫線に関してです。
pythonでExcelを操作するため、openpyxlというパッケージを使用しています。
今回は前回の復習(日報作成)から約一か月ということで(適当)
いままでの勉強内容を含め再度の復習もかねて、表に罫線を引きたいと思います。
上記のようなブック「商品リストを」
こんな感じにしたいです。
今回の目標は
- 表の見出しやデータ量の増減に対応する。
- 表の位置がどこであっても対応する。
の二つです。
マージセルの操作関数
当初はWorksheet.iter_rowメソッドを使用してと考えていたのですが
公式に何かないかなとずるを考えだしたら・・・、ありました。
https://openpyxl.readthedocs.io/en/stable/styles.html#cell-styles-and-named-styles
from openpyxl.styles import Border, Side, PatternFill, Font, GradientFill, Alignment
from openpyxl import Workbook
def style_range(ws, cell_range, border=Border(), fill=None, font=None, alignment=None):
top = Border(top=border.top)
left = Border(left=border.left)
right = Border(right=border.right)
bottom = Border(bottom=border.bottom)
first_cell = ws[cell_range.split(":")[0]]
if alignment:
ws.merge_cells(cell_range)
first_cell.alignment = alignment
rows = ws[cell_range]
if font:
first_cell.font = font
for cell in rows[0]:
cell.border = cell.border + top
for cell in rows[-1]:
cell.border = cell.border + bottom
for row in rows:
l = row[0]
r = row[-1]
l.border = l.border + left
r.border = r.border + right
if fill:
for c in row:
c.fill = fill
フォントなどは今回使わないのですが、そのまま持ってきちゃいました。
目的の罫線を引くため、外枠の罫線設定を使用します。
対象範囲の縦線と横線を別に設定して引いていくという感じでしょうか。
Sideオブジェクト
Side(color=RGB形式の色指定, border_style=線のスタイル)
color引数は文字の時と同じですね。
border_style引数に関しては
- hair:極細
- thin:通常の太さ
- medium:通常と太線の中間
- thick:太線
- double:二重線
この辺はExcelと同じですね。
Borderオブジェクト
cell.border = Border(left=Sideオブジェクト,
right=Sideオブジェクト,
top=Sideオブジェクト,
bottom=Sideオブジェクト)
生成したSideオブジェクトを使用して、Borderオブジェクトを生成します。
そちらを、セルのborder属性に設定することで罫線を引く事が出来ます。
こちらを踏まえて
最終的なコード
from openpyxl.styles import Border, Side, PatternFill, Font, GradientFill, Alignment
from openpyxl import load_workbook
# 公式にあるマージセルの操作関数
def style_range(ws, cell_range, border=Border(), fill=None, font=None, alignment=None):
top = Border(top=border.top)
left = Border(left=border.left)
right = Border(right=border.right)
bottom = Border(bottom=border.bottom)
first_cell = ws[cell_range.split(":")[0]]
if alignment:
ws.merge_cells(cell_range)
first_cell.alignment = alignment
rows = ws[cell_range]
if font:
first_cell.font = font
for cell in rows[0]:
cell.border = cell.border + top
for cell in rows[-1]:
cell.border = cell.border + bottom
for row in rows:
l = row[0]
r = row[-1]
l.border = l.border + left
r.border = r.border + right
if fill:
for c in row:
c.fill = fill
wb = load_workbook('商品リスト.xlsx')
ws = wb.active
# 各線のスタイルを設定
hair = Side(color='000000', border_style='hair')
thin = Side(color='000000', border_style='thin')
double = Side(color='000000', border_style='double')
thick = Side(color='000000', border_style='thick')
# 縦線の種類と位置を設定
border_ver_thin = Border(left=thin)
border_ver_start = Border(left=thick)
border_ver_end = Border(left=thin, right=thick)
# 横線の種類と位置を設定
border_hor_hair = Border(top=hair)
border_hor_thin = Border(top=thin)
border_hor_double = Border(top=double)
border_hor_thick = Border(top=thick)
# 縦線を引く
for col in range(ws.min_column, ws.max_column + 1):
Alpha = ws.cell(row=ws.min_row, column=col).column_letter
ver_range = Alpha + f'{ws.min_row}' + ':' + Alpha + f'{ws.max_row}'
if col == ws.min_column:
style_range(ws, ver_range, border=border_ver_start)
elif col == ws.max_column:
style_range(ws, ver_range, border=border_ver_end)
style_range(ws, ver_range, border=border_ver_thin)
# 横線を引く
hor_start = ws.cell(row=ws.min_row, column=ws.min_column).column_letter
hor_end = ws.cell(row=ws.min_row, column=ws.max_column).column_letter
for row in range(ws.min_row, ws.max_row + 2):
hor_range = hor_start + str(row) + ':' + hor_end + str(row)
if row == ws.min_row or row == ws.max_row + 1:
style_range(ws, hor_range, border=border_hor_thick)
elif row == ws.min_row + 1:
style_range(ws, hor_range, border=border_hor_double)
elif (row - ws.min_row - 1) % 5 == 0:
style_range(ws, hor_range, border=border_hor_thin)
style_range(ws, hor_range, border=border_hor_hair)
wb.save('商品リスト_傍線.xlsx')
こんな感じになりました。
これから汎用性を高めたコードに変えていきたいのですが
今日は力尽きました・・・。
ちなみに、数値などの入力をしていなくてもセルの幅を変えてしまうと
そのセルもデータが入っていると認識されるので注意が必要です。