1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Python】Sideオブジェクト、Borderオブジェクトを使って罫線をひく。

Last updated at Posted at 2021-03-14

pythonを使用してExcelファイルの操作を勉強しています。
本日の気づき(復習)は、罫線に関してです。
pythonでExcelを操作するため、openpyxlというパッケージを使用しています。

今回は前回の復習(日報作成)から約一か月ということで(適当)
いままでの勉強内容を含め再度の復習もかねて、表に罫線を引きたいと思います。

image.png

上記のようなブック「商品リストを」

image.png

こんな感じにしたいです。

今回の目標は

  • 表の見出しやデータ量の増減に対応する。
  • 表の位置がどこであっても対応する。

の二つです。

マージセルの操作関数

当初は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')

こんな感じになりました。
これから汎用性を高めたコードに変えていきたいのですが
今日は力尽きました・・・。

ちなみに、数値などの入力をしていなくてもセルの幅を変えてしまうと
そのセルもデータが入っていると認識されるので注意が必要です。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?