openpyxlで罫線を引く

# Introduction

ここに以下のようなエクセルデータファイル(test.xlsx)があります。

![スクリーンショット 2019-03-13 15.27.15.png](https://qiita-image-store.s3.amazonaws.com/0/335400/18e7cf4c-c5bc-1331-64b2-49def6facda7.png)

あるときこのエクセルに罫線(ここでは黒い枠線)をつけてほしいと依頼がありました。
エクセルファイルやシートの数が一つであれば手作業で罫線をつけてもよいですが、今後大量のエクセルファイルに同様の作業をしなければならない可能性が出てくるかもしれません。そうなった時のために、この作業を自動化しておけると便利ですね。

# スクリプトとその実行結果

エクセルを読み込み、値の入っている範囲に罫線を引くスクリプトを以下に示します。

```python:sheet_border.py

'''
    sheet_border.py
    purpose: read xlsx and set border automatically
'''

import openpyxl as xl
from openpyxl.styles.borders import Border, Side


# set input file name
inputfile = 'test.xlsx'

side = Side(style='thin', color='000000')

# set border (black thin line)
border = Border(top=side, bottom=side, left=side, right=side)

# read tmp xlsx
wb1 = xl.load_workbook(filename=inputfile)
ws1 = wb1.worksheets[0]

# write in sheet
for row in ws1:
    for cell in row:
        ws1[cell.coordinate].border = border

# save xlsx file
wb1.save(inputfile)
```

結果は以下のようになります。

![スクリーンショット 2019-03-13 15.31.05.png](https://qiita-image-store.s3.amazonaws.com/0/335400/b0718836-b85b-7785-fe09-07bae6f7b726.png)

# スクリプト詳細

## from openpyxl.styles.borders import Border, Side

```python
from openpyxl.styles.borders import Border, Side
```

とすることで、Border関数とSide関数を直接呼び出すことができます。このSide関数は、その名の通りSideオブジェクトを返す関数です。Border関数で色や線の太さを指定するために使うため、同時にインポートしています。

## Side関数

```python
side = Side(style='thin', color='000000')
```

この一行でside変数にSideオブジェクトを代入しています。ここでは、線の色は黒、細い罫線を指定しています。引数styleには'thin'の他にも‘dashDot’, ‘dashDotDot’, ‘double’, ‘hair’, ‘dotted’, ‘mediumDashDotDot’, ‘dashed’, ‘mediumDashed’, ‘slantDashDot’, ‘thick’, ‘thin’, ‘medium’, ‘mediumDashDot’が指定可能です。
試しに以下のように変更して実行してみます。

```python
side = Side(style='thick', color='FF0000')
```

すると結果は以下のように、太い赤線の罫線が引かれたものになります。

![スクリーンショット 2019-03-13 15.52.14.png](https://qiita-image-store.s3.amazonaws.com/0/335400/4b0c1fe0-a153-4e09-24ff-64530fd2777c.png)

## Border関数

```python
border = Border(top=side, bottom=side, left=side, right=side)
```

この一行でborder変数にBorderオブジェクトを代入しています。ここでセルのtop(上側), bottom(下側), left(左側), right(右側)にどのような罫線を引くかを指定しています。ここでは全ての辺に同じsideを指定しています。

## 罫線を書き込む

```python
# write in sheet
for row in ws1:
    for cell in row:
        ws1[cell.coordinate].border = border
```

この部分で、先にBorder関数で指定した罫線書式を各セルの罫線オブジェクトに代入しています。

# 応用: 値が入っていない部分には枠をつけない

test.xlsxが以下のようなものだったとしましょう。

![スクリーンショット 2019-03-13 16.01.15.png](https://qiita-image-store.s3.amazonaws.com/0/335400/888d6b2f-f08a-5071-9559-738edb1d1c7c.png)

これで上に示したsheet_border.pyを実行すると、結果は以下のようになります。

![スクリーンショット 2019-03-13 16.03.38.png](https://qiita-image-store.s3.amazonaws.com/0/335400/6a3b4f9b-9a16-71d7-ed8e-e4bf3e8d43b3.png)

上図から分かるように、11行目やE列目のように全く値の入っていない部分にもまたがって罫線もとい枠線を引くことが適用されています。
値のない部分には枠線をつけたくない場合は、以下のようにsheet_border.pyを書き換えます。

```python
# write in sheet
for row in ws1:
    for cell in row:
        if ws1[cell.coordinate].value:
            ws1[cell.coordinate].border = border
```

上述のようにif文を追加することにより、**セルの値がNoneでないときのみ枠線を書き込む**ようにすることができます。この結果は以下のようになります。

![スクリーンショット 2019-03-13 16.07.49.png](https://qiita-image-store.s3.amazonaws.com/0/335400/d084ccd5-d507-6c54-8af4-69b1ffd9500e.png)

これで大量のエクセルファイルがあっても、一つ一つに手作業で罫線を入れていくという面倒な作業からは解放されそうですね。