Pythonのmatplotlibで積み上げ棒グラフを作成しデータラベルを追加してみた

# matplotlibで積み上げ棒グラフを描いてみる

## モチベーション
積み上げ棒グラフをPythonで描く際に、エクセルみたいにデータラベルを表示できたらいいなぁと思い、いざ調べてみるとデータラベルを表示できるような記事が無く、コピペできるコードもありませんでした。そこで、積み上げ棒グラフにデータラベルをつけようと思った時にコピペできるコードを書いてみました。

ちなみに、積み上げ棒グラフだけ描ければいいのであれば、このページの一番最後にある**簡単に積み上げ棒グラフを描く**を参考にしてください。

## インポート
以下のライブラリーをインポートします。

```python

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

sns.set(font='IPAexGothic')

%matplotlib inline
```

## ダミーデータの作成
ダミーデータはA,B,C支店の月別の売り上げデータを作成しました。

```python

dataset = pd.DataFrame([[100, 200, 50], [300, 400, 600], [50, 300, 60]], 
                       columns=['A支店', 'B支店', 'C支店'], 
                       index=['4月', '5月', '6月'])
```

|	|A支店|	B支店|	C支店|
|------:|:---:|:---:|:------:|
|4月	|100|	200|	50|
|5月	|300|	400|	600|
|6月	|50|	300|	60|

## 棒グラフを描く
まずは簡単な棒グラフを描いてみます。
各支店の月の売り上げを合計した棒グラフを描いてみましょう。
描いてみたは良いもののこれだけだと、各月にどれくらい売り上げがあるのかわかりません。。。
そんな時は、積み上げ棒グラフを使いましょう！

```python
fig, ax = plt.subplots(figsize=(10, 8))
ax.bar(dataset.columns, dataset.sum())
plt.show()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/378513/a45eebf1-c13b-350a-fc8d-99bd3a48cc41.png)


## 積み上げ棒グラフを描く
積み上げ棒グラフは棒グラフを描く時と同様に`ax.bar()`を使います。
この時の引数`bottom`にバーのベースとなるy座標を指定します。
積み上げ棒グラフができました！！！やはり、データラベルが欲しいですね。
参考サイト：https://matplotlib.org/3.1.1/api/_as_gen/matplotlib.axes.Axes.bar.html

```python

fig, ax = plt.subplots(figsize=(10, 8))
for i in range(len(dataset)):
    ax.bar(dataset.columns, dataset.iloc[i], bottom=dataset.iloc[:i].sum())
ax.set(xlabel='支店名', ylabel='売り上げ')
ax.legend(dataset.index)
plt.show()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/378513/fde52e30-149f-589a-18d4-9b109f6bd75b.png)

## 積み上げ棒グラフ内にデータラベルを表示する
いよいよここからが本題です。
データラベルは、`plt.text()`でx座標とy座標を指定して挿入します。
そうすると、いい感じにできました！

```python

fig, ax = plt.subplots(figsize=(10, 8))
for i in range(len(dataset)):
    ax.bar(dataset.columns, dataset.iloc[i], bottom=dataset.iloc[:i].sum())
    for j in range(len(dataset.columns)):
        plt.text(x=j, 
                 y=dataset.iloc[:i, j].sum() + (dataset.iloc[i, j] / 2), 
                 s=dataset.iloc[i, j], 
                 ha='center', 
                 va='bottom'
                )
ax.set(xlabel='支店名', ylabel='売り上げ')
ax.legend(dataset.index)
plt.show()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/378513/e0683916-b112-44fd-fa6a-14dd71fcad95.png)



## 100％積み上げ棒グラフを描く
積み上げ棒グラフを使う時には100%積み上げ棒グラフも使用したくなりますよね。
まずはデータを加工します。
以下のコードで支店別の売り上げを割合に変換します。

```python

plot_dataset = pd.DataFrame(index = dataset.index)
for col in dataset.columns:
    plot_dataset[col] = round(100 * dataset[col] / dataset[col].sum(), 1)
```

|	|A支店|	B支店|	C支店|
|------:|:---:|:---:|:------:|
|4月	|22.2|	22.2|	7.0|
|5月	|66.7|	444.|	84.5|
|6月	|11.1|	33.3|	8.5|

変換したデータを使って100%積み上げ棒グラフを描きましょう。
コードは先ほどのコードを同じです。（変数だけ変更しています。）

```python

fig, ax = plt.subplots(figsize=(10, 8))
for i in range(len(plot_dataset)):
    ax.bar(plot_dataset.columns, 
           plot_dataset.iloc[i], 
           bottom=plot_dataset.iloc[:i].sum()
          )
    for j in range(len(plot_dataset.columns)):
        plt.text(x=j, 
                 y=plot_dataset.iloc[:i, j].sum()+(plot_dataset.iloc[i, j]/2), 
                 s=f'{plot_dataset.iloc[i, j]}%', 
                 ha='center', 
                 va='bottom'
                )
ax.set(xlabel='支店名', ylabel='売り上げ')
ax.legend(plot_dataset.index)
plt.show()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/378513/3f985b9f-4a01-5a7e-2d6b-9e973934be99.png)

## 簡単に積み上げ棒グラフを描く
積み上げ棒グラフを描くだけなら以下のコードで簡単に描けます。

```python
fig, ax = plt.subplots(figsize=(10, 8))
dataset.T.plot(kind='bar', stacked=True, ax=ax)
plt.show()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/378513/e331eb5d-f6bd-c9ac-2d7a-63463e851c8b.png)