openpyxlのchartでグラフの枠線を消す

# openpyxlのchartでグラフの枠線を消す

openpyxlは便利なライブラリで、excelのグラフも自動で作ることができます。
たくさんのデータから、同じようなたくさんのグラフを作る場合など、excelでポチポチポチポチとクリックをしたくない時にとても便利です。
便利なのですが、グラフの枠線を消したり背景を変えることがうまくできなかったので、調べてみました。

## まずグラフを作成

円グラフを表示してみます。

```python
import openpyxl
from openpyxl.chart import PieChart, Reference


wb = openpyxl.Workbook()
ws = wb.active

ws["A1"] = "りんご"
ws["B1"] = 30
ws["A2"] = "みかん"
ws["B2"] = 60

chart = PieChart()
chart.add_data(Reference(ws, min_col=2, min_row=1, max_row=2))
chart.set_categories(Reference(ws, min_col=1, min_row=1, max_row=2))

ws.add_chart(chart, "B4")
wb.save("out.xlsx")
```

こんなふうになりました。

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245486/8a7c90e1-0c3b-be56-9784-becd4f09624d.png)

この矢印のところの枠線を消したり、この枠線の内側を塗りつぶすのが目標です。

## 枠の中を塗りつぶしてみる

すこし調べると`plot_area`の`graphicalProperties`というのを設定するといいみたいです。
わかりやすいように、赤く塗ってみます。

```python
from openpyxl.chart.shapes import GraphicalProperties
...

chart.plot_area.graphicalProperties = GraphicalProperties(solidFill="cc0000")

```

![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245486/b885ac0d-5b77-0f0b-8513-e18fa43c3e3c.png)

うーん、思っていた範囲と違います。

`legend`というのもありますが、これは、違う気がします。
ま、一応やってみましょう。
緑にしてみます。

```python
chart.legend.graphicalProperties = GraphicalProperties(solidFill="00cc00")
```

![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245486/e7cfa424-c1ea-e1ef-f7a2-320b9b407934.png)

ま、そうですよね。
legendってそこですよね。


もう少し調べてみると、
`chart.graphical_properties`というのがあるようです。
Camel Caseじゃなくて、Snake Caseです。

試してみましょう。

```python
chart.graphical_properties = GraphicalProperties(solidFill="0000cc")
```

![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245486/e7cfa424-c1ea-e1ef-f7a2-320b9b407934.png)

うーーん。だめです。変化なしです。

検索してみると、動かないとか、古いバージョンでは動いたとかいくつか嫌な情報があります。

## 調査

ということで、ソースを見てみます。

`PieChart`は`_PieChartBase`を継承して、`_PieChartBase`は`ChartBase`を継承して、この`ChartBase`に`graphical_properties`が定義されています。

```python:site-packages/openpyxl/chart/_chart.py
class ChartBase(Serialisable):
    ....
    graphical_properties = Typed(expected_type=GraphicalProperties, allow_none=True)
```

しかし、よくソースを追いかけてみると、graphical_propertiesは`__init__`でNoneに初期化されているだけでどこからも参照されていません。
これは一体どうしたことでしょうか。

`_write`関数にある`ChartSpace`の`spPr`が`GraphicalProperties`を持つようなので、無理矢理入れてみます。

```python:site-packages/openpyxl/chart/_chart.py
class ChartBase(Serialisable):
    ....
    def _write(self):
        ....
        cs = ChartSpace(chart=container)
        cs.style = self.style
        cs.roundedCorners = self.roundedCorners
        cs.pivotSource = self.pivotSource
        cs.spPr = self.graphical_properties  <== この行を追加
        return cs.to_tree()
```

![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245486/beaafc07-a5d5-dd2a-18d6-5b9eda79968b.png)

できました！！！

なんなんでしょうね。バグなんでしょうか。

## ついに枠を消す

ここまでできたら、本題の枠を消すのをやってみましょう。
こんなコードになりました。

```python
import openpyxl
from openpyxl.chart import PieChart, Reference
from openpyxl.chart.shapes import GraphicalProperties, LineProperties


wb = openpyxl.Workbook()
ws = wb.active

ws["A1"] = "りんご"
ws["B1"] = 30
ws["A2"] = "みかん"
ws["B2"] = 60

chart = PieChart()
chart.add_data(Reference(ws, min_col=2, min_row=1, max_row=2))
chart.set_categories(Reference(ws, min_col=1, min_row=1, max_row=2))

chart.graphical_properties = GraphicalProperties(ln=LineProperties(noFill=True))

ws.add_chart(chart, "B4")
wb.save("out.xlsx")
```

![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245486/00e20d42-6145-1b3a-c45b-fb7bf04d972a.png)

できました！！

## さいごに

ライブラリを直接いじったのですが、なんかほかにうまくできないでしょうかね。
また、時間あるとき挑戦してみましょう。