LoginSignup
2
1

More than 1 year has passed since last update.

[Seaborn]積み上げ棒グラフを出力してみた

Last updated at Posted at 2022-12-19

はじめに

最近、seabornというpythonでグラフを作るためのライブラリを使い始めたのですが、積み上げ棒グラフを作るのに少し手間かかったので、この機会にまとめてみることにしました。

サンプルソースを作成したので、困っている方の参考になれば幸いです。

(22/12/20 19:33追記)
コメント欄にて、簡潔な積み上げ棒グラフの作り方を教えて頂きました。ありがとうございます!

積み上げ棒グラフを出力

作成したサンプルソースは次のようになっています。

# パッケージのインポート
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib import rc
import seaborn as sns

# グラフの日本語対応
rc('font', family='BIZ UDGothic')

# データの用意
study_history = pd.DataFrame({'': [2021, 2021, 2021, 2022, 2022, 2022],
                              '学習内容': ['英語', 'プログラミング', '資格', '英語', 'プログラミング', '資格'],
                              '学習時間': [30, 150, 100, 150, 100, 100]})

# 勉強時間の全期間の合計が多い順に積み上げるための工夫
df = study_history.groupby('学習内容', as_index=False) \
    .agg({ '学習時間': 'sum' }) \
    .sort_values('学習時間', ascending=False) \
    .drop(columns='学習時間')
df['積み上げ順序'] = range(1, df.shape[0]+1)

study_history = pd.merge(study_history, df, on=['学習内容'], how='left')
study_history.sort_values(['', '積み上げ順序'], inplace=True)

# メモリ開放
del df

# 棒グラフを積み上げたときのtopの高さを作成
study_history['top'] = study_history.groupby('')['学習時間'].cumsum()

# カラーパレットの作成
colors = sns.color_palette(n_colors=3)

# 学習内容で分割してリストに格納
labels = study_history['学習内容'].unique()
dfs = [study_history.loc[study_history['学習内容']==label] for label in labels] 

# 積み上げ棒グラフの表示
fig, ax = plt.subplots(1, 1, figsize=(10, 5))
for i, _ in enumerate(labels):
    if i == 0:
        sns.barplot(x='', y='学習時間', data=dfs[i], ax=ax, label=labels[i], color=colors[i])
    else:
        sns.barplot(x='', y='学習時間', data=dfs[i], ax=ax, bottom=dfs[i-1]['top'], label=labels[i], color=colors[i])
ax.legend(loc='upper left')

上記サンプルソースを実行すると次のグラフが生成されます。

download.png

上から順番に解説します。

必要なパッケージをインポートしています。

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

今回用意したデータに日本語を含めました。

デフォルトだとグラフが文字化けするので、日本語の文字化け対応で次のコードを書いています。

rc('font', family='BIZ UDGothic')

積み上げ棒グラフに使うデータとして、架空のA君の学習履歴(年度と学習内容で勉強時間がサマリされたデータ)を用意してみました。

study_history = pd.DataFrame({'年度': [2021, 2021, 2021, 2022, 2022, 2022],
                              '学習内容': ['英語', 'プログラミング', '資格', '英語', 'プログラミング', '資格'],
                              '学習時間': [30, 150, 100, 150, 100, 100]})

学習履歴をデータフレームで表示すると次のようになっています。

学習内容 学習時間
0 2021 英語 30
1 2021 プログラミング 150
2 2021 資格勉強 100
3 2022 英語 150
4 2022 プログラミング 100
5 2022 英語 100

積み上げ棒グラフでは、学習時間の大きい棒グラフから積み上がってほしいので、順位を付与した後、昇順で並び替えてみました。

# 勉強時間の全期間の合計が多い順に積み上げるための工夫
df = study_history.groupby('学習内容', as_index=False) \
    .agg({ '学習時間': 'sum' }) \
    .sort_values('学習時間', ascending=False) \
    .drop(columns='学習時間')
df['積み上げ順序'] = range(1, df.shape[0]+1)

study_history = pd.merge(study_history, df, on=['学習内容'], how='left')
study_history.sort_values(['', '積み上げ順序'], inplace=True)

# メモリ開放
del df

sns.barplotの引数「bottom」に渡すためのデータを作成します。

対象の学習内容を含めが棒グラフの高さを出しておき、あとの話になりますが、bottomにはひとつ前の学習内容の棒グラフの高さを渡すようにします。

# 棒グラフを積み上げたときのtopの高さを作成
study_history['top'] = study_history.groupby('')['学習時間'].cumsum()

色を指定しないと異なる学習内容にも拘わらず、同色になってしまうので、カラーパレットを作っておきます。

# カラーパレットの作成
colors = sns.color_palette(n_colors=3)

学習内容ごとリストに格納し、学習内容のリストを使って学習内容別にデータを分割してリストに格納しておきます。

データをリストに格納しておくことで、ひとつ前の学習内容の棒グラフの高さ(top)に簡単にアクセスできるようにしています。

# 学習内容で分割してリストに格納
labels = study_history['学習内容'].unique()
dfs = [study_history.loc[study_history['学習内容']==label] for label in labels] 

for文で回してグラフを積み上げていきます。

一つ目はbottomが不要なので、処理を分けています。

# 積み上げ棒グラフの表示
fig, ax = plt.subplots(1, 1, figsize=(10, 5))
for i, _ in enumerate(labels):
    if i == 0:
        sns.barplot(x='', y='学習時間', data=dfs[i], ax=ax, label=labels[i], color=colors[i])
    else:
        sns.barplot(x='', y='学習時間', data=dfs[i], ax=ax, bottom=dfs[i-1]['top'], label=labels[i], color=colors[i])
ax.legend(loc='upper left')

以上になります。

おわりに

今回、積み上げ棒グラフを作るだけにも拘わらず、コードが長くなってしまいました。

簡潔な書き方がわかり次第追記しようと思います。

2
1
2

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
2
1