openpyxlをうす〜く理解しよう~その2/3（体裁を整える編）

# はじめに

前回の続きです。
前回はこちら

https://qiita.com/ikedachin/items/7a0a08a4823ab5e1382f



ざっぱに、今回の内容はこんな感じ

- 体裁情報の取得（セル塗りつぶし、罫線、フォント）
- 体裁の設定の例を追って理解する

この二つ
だけど、結構ボリュームあるよ。
<br>
<br>

まずは前回用意したこのエクセルを読み込みましょう。
![スクリーンショット 2024-04-16 18.04.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3655320/98631935-94e4-40d6-f72d-9e959c9e6062.png)
<br>
<br>

```python
import openpyxl

workbook = openpyxl.load_file('ファイル名')
worksheet = workbook['Sheet1']
```
<br>
<br>

# セル情報の取得
## セルの色の取得

```python
print(worksheet.cell(row=1, column=2).fill)
```
出力
```
<openpyxl.styles.fills.PatternFill object>
Parameters:
patternType='solid', fgColor=<openpyxl.styles.colors.Color object>
Parameters:
rgb=None, indexed=None, auto=None, theme=4, tint=0.3999755851924192, type='theme', bgColor=<openpyxl.styles.colors.Color object>
Parameters:
rgb=None, indexed=64, auto=None, theme=None, tint=0.0, type='indexed'
```
なんだか`Parameters`ってのに色々値が入っていますね。

公式で言うとこの辺りを参考にしましょう。
https://openpyxl.readthedocs.io/en/stable/styles.html#indexed-colours

色の指定方法には何種類かありそうです。
- 16進数での表現
上の出力で言うと・・・今回の例では無い。汗
ま、上のリンクで言う`00FF0000`みたいな表現で色を表わしています。
<br>

- indexedでの表現
上の出力で言うと、一番下の行の`indexd=64`ってとこ。
<br>

- themeでの表現
上の出力で言うと下から3行目、`theme=4`ですね。
で、これらのindexed,themeの一覧が公式にあるかというとないと言う。www
`tint`の濃淡らしい。-1~1の値を取れます。　−1に近づくとくら〜い感じです。



<br>



じゃ、なんとなく、わかってきましたね。
なんとなくわかったら十分です。次行きましょ！
<br>
<br>


## 罫線の色の取得

ぶっちゃけ、公式hp見ながら試してみたら当たり。w
これで、罫線の情報が取得できます。

```python
worksheet.cell(row=1, column=2).border
```
```
<openpyxl.styles.borders.Border object>
Parameters:
outline=True, diagonalUp=False, diagonalDown=False, start=None, end=None, left=<openpyxl.styles.borders.Side object>
Parameters:
style=None, color=None, right=<openpyxl.styles.borders.Side object>
Parameters:
style=None, color=None, top=<openpyxl.styles.borders.Side object>
Parameters:
style=None, color=None, bottom=<openpyxl.styles.borders.Side object>
Parameters:
style=None, color=None, diagonal=<openpyxl.styles.borders.Side object>
Parameters:
style=None, color=None, vertical=None, horizontal=None
```
diagonalは対角の意味なのできっと斜め線のやつですね。
outlineがTrueってことは外枠に罫線が付いていると推測。
ここでも色はいろんな表現がされてそうなことが読み取れます。
詳しくは踏み込まない。なぜなら「使う時にわかればいいじゃん！」

<br>
<br>

## フォントの色の取得
<br>
また、適当のfontを渡してみたらビンゴ。

```python
worksheet.cell(row=1, column=2).font
```
```
<openpyxl.styles.fonts.Font object>
Parameters:
name='Yu Gothic', charset=None, family=2.0, b=False, i=False, strike=None, outline=None, shadow=None, condense=None, color=<openpyxl.styles.colors.Color object>
Parameters:
rgb=None, indexed=None, auto=None, theme=1, tint=0.0, type='theme', extend=None, sz=11.0, u=None, vertAlign=None, scheme='minor'
```
フォント名、ボールドやイタリックは付いていない。
文字サイズは11で、色の指定もありそう。

<br>
<br>

## セルの高さと幅の取得
まずはセルの高さ
```python
print(worksheet.row_dimensions)
```
出力
```
DimensionHolder(<bound method Worksheet._add_row of <Worksheet "Sheet1">>,
                {1: <openpyxl.worksheet.dimensions.RowDimension at 0x107a6e980>,
                 2: <openpyxl.worksheet.dimensions.RowDimension at 0x10c9f9140>,
                 3: <openpyxl.worksheet.dimensions.RowDimension at 0x10c142c00>,
                 4: <openpyxl.worksheet.dimensions.RowDimension at 0x10c9e4a40>})
```
お、4行分の何かが辞書っぽい形式で取れましたね。
<br>
<br>
最初の行と思われる`1`を撮ってきて、`height`を取ってみましょう。
```python
print(worksheet.row_dimensions[1].height)
```
出力
```
22.0
```
エクセルで確認するとちゃんと22.0でした。
<br>
<br>


次に幅の取得を目指しましょう。
```python
print(worksheet.column_dimensions)
```

出力
```
DimensionHolder(<bound method Worksheet._add_column of <Worksheet "Sheet1">>,
                {})
```
<br>
<br>
あれ、辞書の中身がない・・・
これ、なんか安定しません。時々、少しのcolumnsの情報が取れます。
↓のように辞書で取れることもあるんですよね。なんだろこれ？

```
DimensionHolder(<bound method Worksheet._add_column of <Worksheet "Sheet1">>,
                {'A': <openpyxl.worksheet.dimensions.ColumnDimension at 0x1051ff6c0>})
```
<br>
<br>
行の時の真似をしてみたらうまく行った。

```python
print(worksheet.column_dimensions['A'].width)
```
出力
```
13.0
```
はい。深追いはしません。次いこ、次。



## アラインメントの取得
ここまできたらなんとなくわかってきますね。勘が冴えてきました。うふふ
```python
worksheet.cell(row=1, column=2).alignment
```
出力
```
<openpyxl.styles.alignment.Alignment object>
Parameters:
horizontal=None, vertical=None, textRotation=0, wrapText=None, shrinkToFit=None, indent=0.0, relativeIndent=0.0, justifyLastLine=None, readingOrder=0.0
```
文字の左右の位置やら上下の位置、縦書きやら、回転、折り返しなんかが書かれていそう。

<br>
<br>
<br>

# 体裁の設定
さて、ここからは体裁を整える方法を作っていきましょう


## 色の指定の仕方
この辺で一度色の指定の仕方をよく見てみましょう。
`Color`クラスのインポートが必要。
公式はこの辺り。

https://openpyxl.readthedocs.io/en/stable/styles.html#colours



```python
from openpyxl.styles.colors import Color

c1 =  Color(theme=4, tint=0.5)
c2 =  Color(theme=4, tint=-0.8)
c3 =  Color(rgb="00FF0000", tint=0)
```
今回は`theme`と`rgb`で指定してみました。これで色が作れたので、色を使っていきます。
<br>
<br>

ここからは公式ページがわかりやすいので、エッセンスをどんどんもらっていきましょう。
この辺り

https://openpyxl.readthedocs.io/en/stable/styles.html#styling-merged-cells



## セルの塗りつぶし
一色でセルを塗りつぶす場合は`PatternFill`を使うっぽい。
A列の１〜３行に色をつけていきまっしょい。
```python
from openpyxl.styles import PatternFill

# 色をつくる
c1 =  Color(theme=4, tint=0.5)
c2 =  Color(theme=4, tint=-0.8)
c3 =  Color(rgb="00FF0000", tint=0)

# セル.fillにPtternFillを使って色と塗りつぶしタイプを渡す
worksheet.cell(row=1, column=1).fill = PatternFill(fgColor=c1, fill_type='solid')
worksheet.cell(row=2, column=1).fill = PatternFill(fgColor=c2, fill_type='solid')
worksheet.cell(row=3, column=1).fill = PatternFill(fgColor=c3, fill_type='solid')
```
ワークシートのセルの`.fill`に`PatternFill()`で色を指定する感じっすね。
<br>
<br>

![スクリーンショット 2024-04-22 21.53.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3655320/44f95074-4ad7-d83e-f0bb-487905dd0f61.png)


A1、A2、A3に色がつきました。





## セルの文字色の設定
Fontクラスを使うのでインポート。
```python
from openpyxl.styles import Font

worksheet.cell(row=1, column=2).font  = Font(name='Meiryo UI', bold=True, italic=True, color=c3, size=16)
worksheet.cell(row=2, column=2).font  = Font(name='MS P Gothic', bold=False, italic=True, color=c2, size=16)
worksheet.cell(row=3, column=2).font  = Font(name='MS P Gothic', bold=True, italic=False, color=c1, size=16)
```
色はさっき作ったc1、c2、c3を使いました。
Bの列の１〜３行にフォントを設定
セルの塗りつぶしと同じ使用パターン。Fontクラスに渡す引数が分かれば色々とやれそう。

<br>
<br>

![スクリーンショット 2024-04-22 22.01.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3655320/826acc20-1ef3-4dc3-5610-2de575aac437.png)
フォントの設定ができることがわかったので、次行こ、次
今回の目的は**うす〜く知ること**だ!
<br>
<br>



## セルの罫線の設定
Borderクラスを使います。
```python
from openpyxl.styles import Border, Side

# ここは公式から拾ってきた
border = Border(left=Side(border_style=None,
                          color='FF000000'),
                right=Side(border_style=None,
                           color='FF000000'),
                top=Side(border_style=None,
                         color='FF000000'),
                bottom=Side(border_style=None,
                            color='FF000000'),
                diagonal=Side(border_style=None,
                              color='FF000000'),
                diagonal_direction=0,
                outline=Side(border_style=None,
                             color='FF000000'),
                vertical=Side(border_style=None,
                              color='FF000000'),
                horizontal=Side(border_style=None,
                               color='FF000000')
               )
```
よくみてみよう。
left / right / top / bottom
これはわかるな・・・

diagonal
diagonal_direction
toutline
vertical
horizontal

謎や

ということで試すのだ
<br>
<br>


#### left / right / top / bottom
```python
worksheet.cell(row=6, column=3).border = Border(left=Side(border_style=None, color=c1), 
                                                right=Side(border_style='dot', color=c2), 
                                                top= Side(border_style='double', color=c2), 
                                                bottom=Side(border_style='dotdash'))
```
エラーくらった

```
ValueError: Value must be one of {'double', 'hair', 'dotted', 'mediumDashDot', 'slantDashDot', 'mediumDashDotDot', 'dashDot', 'dashed', 'thin', 'medium', 'dashDotDot', 'thick', 'mediumDashed'}"
```
お、`dotdash`ではなくて`dashDot`なんすね。他にも`None`は受け付けなくて、`dot`ではなく、`dotted`
つか、これってどこかに書いてあるんだろうか。
いや、`openpyxl`は**まずやってみろ**と言っているのか？
<br>
<br>


気を取り直して。
```python
worksheet.cell(row=6, column=3).border = Border(left=Side(border_style='thin', color=c3), 
                                                right=Side(border_style='thick', color=c3), 
                                                top= Side(border_style='double', color=c3), 
                                                bottom=Side(border_style='dashDot', color=c3))
```
<br>
<br>


うぇ〜い

![スクリーンショット 2024-04-22 22.36.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3655320/15182cf3-faf7-d867-71f2-a7973bd4d441.png)

こんな感じでできるんすね。
<br>
<br>


## セルの高さと幅の設定
これで最後っす
その１でやった`height`と`width`。これに値を渡してあげましょう。

```python
worksheet.row_dimensions[3].height = 50
worksheet.column_dimensions['C'].width = 40
```

ホイっ！
<br>
<br>
![スクリーンショット 2024-04-22 22.44.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3655320/adb13075-fc99-def5-ca30-24ed210e49fc.png)

# 終わりに
とういことで、自分が理解しやすくするために、ざっくりと`openpyxl`を見渡してきました。
ざっと公式を見ているとシートのロックだったり、パスワードをかけたりと色いろできそうです。
ただし、そういうのは実際にやるときに調べればいいし、ざっくり理解しておくことで心理的ハードルが下がります。
僕にはそっちの方が大事。

並行してGAS（Google Apps Script）でスプレッドシートを触っていましたが、基本的には似ています。どちらか一つができるようになると心理的ハードルはさらに下がりそうです。

ということで、今回はここまで。
ではまた！