\ 迷ったらまずTechAcademyの無料カウンセリング! /
【Matplotlib】ドーナツグラフ!円中心に割合% (pie, text)

データの割合を表示する際に,円グラフがよく使われていますが,モダンなデザインにするために円グラフの中心部分をくりぬいたドーナツグラフが使われるがあります
本記事ではMatplotlibでドーナツグラフと2重ドーナツグラフを描画する方法について解説します
ドーナツグラフの凡例やラベル,パーセント表示,要素の座標変更,色,カラーマップ,太さ,テキストなどのカスタマイズ方法も詳細に解説しています

円グラフに関しては下記記事を参考にしてください

ドーナツグラフのオプション一覧
Matplotlibでは,ドーナツグラフはAxes.pie関数を使って描画します
- 引数
 - 
- x (配列):1次元配列で指定する円グラフの各要素
 - explode (配列):グラフの中心からの各要素の距離の割合
 - labels (リスト):各要素のラベル
 - colors (配列):グラフの色
 - autopct (文字列, 関数):ラベルを数値割合で表示
 - pctdistance (float):グラフの中心とautopct が生成するテキスト位置との比率
 - shadow (bool):グラフの影
 - labeldistance (float):ラベルの距離
 - counterclock (bool):要素の方向.時計回りか反時計回りか
 - startangle (float):グラフの始点のx軸から反時計回りの回転角度
 - radius (float):グラフの半径
 - wedgeprops (dict):各要素(wedge)を辞書形式でカスタマイズ
 - textprops (dict):テキスト要素を辞書形式でカスタマイズ
 - center ((float, float)):グラフの中心の座標
 - frame (bool):グラフの軸
 - rotatelabels (bool):各ラベルの回転
 - normalize (bool):グラフの数値の正規化
 - radius (float) : 円の半径
 
 - 返値
 - 
- patches (リスト):matplotlib.patches.Wedgeの配列
 - texts (リスト):ラベルTextのリスト
 - autotexts (リスト):数値ラベル用のTextリスト.autopctがNoneでない場合にのみ
 
 - 公式ドキュメント
 
基本的なドーナツグラフ (wedgeprops, color)
円グラフから中心部分をくりぬいたドーナツグラフを描画します
Axes.pie関数の引数wedgepropsで円グラフの幅を指定することで,ドーナツグラフを描画できます
要素の幅 (wedgeprops)
引数wedgepropsは辞書型で指定し,{'width': 0.3}としました
下記のタブにコードとフローチャートの解説をしています
import matplotlib.pyplot as plt
import numpy as np
# step1 データの作成
width = 0.3
vals = [40, 60]
# step2 グラフフレームの作成
fig, ax = plt.subplots()
# step3 ドーナツグラフの描画
ax.pie(vals, startangle=90,
        # ドーナツの幅
        wedgeprops={'width':width}
)
ax.set_title('Donut chart')
plt.show()
要素の色 (colors)
要素の色はcolors=配列で指定します
色のグラデーションがほしかったので,Bluesというカラーマップを使用しました

カラーマップはデータ数値に合わせて色を変化させることができます
この関数はデータの最小値から最大値にかけてのRGBAの配列を生成します
- 引数
 - 
- name (文字列) : カラーマップの名前
 - N (int) : RGBの量子化レベルの数
 
 - 返値
 - 
- データがスカラー:RGBAの配列 (tuple)
 - データが配列:RGBAの配列 (データ配列+4行)
 
 - 公式ドキュメント
 
import matplotlib.pyplot as plt
import numpy as np
# step1 データの作成
width = 0.3
vals = [40, 60]
# step1.1 カラーマップの作成
cmap = plt.get_cmap('Blues')
colors = cmap(np.linspace(0.2, 0.7, len(vals)))
# step2 グラフフレームの作成
fig, ax = plt.subplots()
# step3 ドーナツグラフの描画
ax.pie(vals, startangle=90,
        # ドーナツの幅
        wedgeprops={'width':width},
        # カラー
        colors=colors
)
ax.set_title('Donut chart')
plt.show()
円中心の割合% (Axes.text)
Axes.text関数を使って,ドーナツグラフの中心に割合の%や文字を表示します
Axes.text関数のオプション一覧は次のとおりです
- 引数
 - 
- x, y (float) : テキストを配置するグラフの位置を座標で指定.座標系はtransformパラメータで変更可能
 - s (文字列) : 表示したいテキスト
 - fontdict (辞書) : テキストの色やフォントの一括設定
 - fontsize (float or size) : フォントサイズ.数値もしくは,サイズ指定{
'xx-small','x-small','small','medium','large','x-large','xx-large'} - horizontalalignment or ha (‘left’, ‘center’, ‘right’) : 水平方向の調整
 - verticalalignment or va (‘baseline’, ‘bottom’, ‘center’, ‘center_baseline’, ‘top’) : 垂直方向の調整
 - color or c (color) : テキストの色
 
 - 返値
 - 
- Text : テキストオブジェクトが作成されます
 
 - 公式ドキュメント
 
割合%の表示 (fontsize)
Axes.textの引数に座標(x, y)=(0, 0)と文字(s)=60%+Donut Chartを指定します
さらにフォントサイズ=20としました
# step4 テキストの追加
ax.text(0, 0, r'60%'+'\nDonut Chart', fontsize=20)
割合%の配置 (horizontalalignment, verticalalignment)
割合%の表示では,表示した文字の位置が中央ぞろえになっていませんでした
horizontalalignment='center'は水平方向, verticalalignment='center'は垂直方向の中央に配置します
# step4 テキストの追加
ax.text(0, 0, r'60%'+'\nDonut Chart', fontsize=20, 
        horizontalalignment='center', 
        verticalalignment='center'
)
モダンデザインのドーナツグラフ (color)
割合%とその他のテキストを分けて,割合%のみ強調させます
まず,強調したい割合%のテキストとその他のテキストで2つのAxes.text関数を使います
割合%の配置のverticalalignmentを活用して,上側のテキストをbottom,下側のテキストをtopとすることでどのフォントサイズにしても干渉しなくなります
# step1.1 カラーマップの作成
color_text = cmap(0.7)
# step4 テキストの追加
ax.text(0, 0, r'60%', color=color_text, fontsize=32, fontweight='medium',
        horizontalalignment='center', verticalalignment='bottom')
ax.text(0, 0, r'Donut Chart', color=color_text, fontsize=20, 
        horizontalalignment='center', verticalalignment='top')
凡例とnumpy.array (Axes.legend)
ドーナツグラフでの凡例の表示と配置方法について解説します
また,前章まではグラフデータにリストを使用していましたが,numpy.arrayのndarray型を使用します
- 引数
 - 
- handles (Artistのリスト) : 凡例に追加するアーティスト(ライン、パッチ)のリスト
 - labels (文字列のリスト) : アーティストの隣に表示するラベルのリスト.handlesと同じ要素数でなければならない
 - loc (文字列 or float) : 凡例の位置.
'best',upper left','upper right','lower left','lower right','right','center left','center right','upper center','lower center','center' - bbox_to_anchor (BboxBase) : loc と連動して凡例を配置するために使用されるボックス
 
 - 返値
 - 公式ドキュメント
 
凡例 (loc, bbox_to_anchor)
用意した配列はnumpy.arrayのndarray型で,4行2列の2次元配列です
各行ごとに総和を計算して,4要素の1次元配列にしてグラフに使いました
凡例の位置はloc='center left'で中央左ぞろえかつbbox_to_anchor=(1, 0, 0.5, 1)でx方向右側にグラフ1つ分動かしています
import matplotlib.pyplot as plt
import numpy as np
# step1 データの作成
labels = ['A', 'B', 'C', 'D']
width = 0.3
vals = np.array([[60, 32], [40, 35], [29, 10], [18, 5]])
# step2 グラフフレームの作成
fig, ax = plt.subplots()
# step3 ドーナツグラフの描画
ax.pie(vals.sum(axis=1), labels=labels, 
        wedgeprops={'width':width},
        startangle=90
)
ax.set_title('Donut chart with a legend')
# 凡例
ax.legend(loc='center left', bbox_to_anchor=(1, 0, 0.5, 1))
plt.show()
回転方向 (counterclock)
Axes.pie関数の引数counterclock=Falseとすることで,円グラフの回転方向を時計回りにできます
# step3 ドーナツグラフの描画
ax.pie(vals.sum(axis=1), labels=labels,
        wedgeprops={'width':width},
        startangle=90, 
        counterclock=False
)
円の開始位置 (startangle)
Axes.pie関数の引数startangleに角度を指定することで,要素の円周方向の位置を自由に変えることができます
基本開始位置は(x, y)=(1, 0)の位置です
# step3 ドーナツグラフの描画
ax.pie(vals.sum(axis=1), labels=labels,
        wedgeprops={'width':width},
        startangle=0, 
        counterclock=False
)
グループごとの数値ラベル (autopct, pctdistance)
Axes.pieの引数にautopctを指定することで数値ラベルが表示できます
また,pctdistanceで数値ラベルの位置を変更できます
# step3 ドーナツグラフの描画
ax.pie(vals.sum(axis=1), labels=labels, startangle=90, counterclock=False,
        wedgeprops={'width':width},
        # 数値%ラベルの表記
        autopct='%.1f%%', 
        # 数値%ラベルの位置
        pctdistance=0.85,
)
2重のドーナツグラフ (radius)
データが大区分,中区分と細かく分けられている場合,ドーナツグラフを2重にして,各要素を細かく見れるようにします
Matplotlibでは,内側のドーナツグラフの半径をradiusで小さくする+カラーマップで色を分けるを組み合わせて描画します
使用するカラーマップはtab20cで,4つごとに色が大きく変わります

外側のドーナツグラフ
前章までのドーナツグラフと同様に描画してください
色はカラーマップが1色4組のため,4の倍数でカラーマップに配列を渡し,メインの色だけの色配列を作成しますcmap(np.arange(vals.shape[0])*4)=cmap([0, 4, 8, 12])
# step1 ラベルとデータの作成
labels = ['A', 'B', 'C', 'D']
width = 0.3
vals = np.array([[60, 32], [40, 35], [29, 10], [18, 5]])
# step2 グラフフレームの作成
fig, ax = plt.subplots()
# step3 カラーマップの作成
cmap = plt.colormaps['tab20c']
# 外側のドーナツグラフの色
outer_colors = cmap(np.arange(vals.shape[0])*4)
# vals.shape[0]=行数
# np.arange(4)=[0, 1, 2, 3]
# cmap([0, 4, 8, 12])
# step4 外側のドーナツグラフの描画
ax.pie(vals.sum(axis=1), radius=1, startangle=90, counterclock=False,
    labels=labels,
    autopct='%.0f%%', 
    pctdistance=1.15-width, 
    wedgeprops={'width':width, 'edgecolor':'white'},
    colors=outer_colors)
plt.show()
内側のドーナツグラフ (radius)
メイン色が4の倍数であるため,各行に4の倍数を割り当て,列ごとに+1しますcmap([1, 2, 5, 6, 9, 10, 13, 14])
データはnumpy.flattenで1次元配列にしています
radius=1-widthでグラフの半径を外側のグラフの幅分だけ小さくします
# step3 カラーマップの作成
cmap = plt.colormaps['tab20c']
# 内側のドーナツグラフの色
inner_colors = cmap([i*4+j+1 for i, vs in enumerate(vals) for j in range(vs.size)])
# i*4: 各行に4の倍数を割り当て
# j+1: 列ごとに+1
# step5 内側ドーナツグラフの描画
ax.pie(vals.flatten(), radius=1-width, startangle=90, counterclock=False,
    autopct='%.0f%%', 
    pctdistance=1.1-width, 
    wedgeprops={'width':width, 'edgecolor':'white'},
    colors=inner_colors)
2重ドーナツグラフ
外側のドーナツグラフと内側のドーナツグラフをまとめて描画します
下記のタブにコードとフローチャートの解説をしています
# step1 ラベルとデータの作成
labels = ['A', 'B', 'C', 'D']
width = 0.3
vals = np.array([[60, 32], [40, 35], [29, 10], [18, 5]])
# step2 グラフフレームの作成
fig, ax = plt.subplots()
# step3 カラーマップの作成
cmap = plt.colormaps['tab20c']
outer_colors = cmap(np.arange(vals.shape[0])*4)
inner_colors = cmap([i*4+j+1 for i, vs in enumerate(vals) for j in range(vs.size)])
# step4 外側のドーナツグラフの描画
ax.pie(vals.sum(axis=1), radius=1, startangle=90, counterclock=False,
    labels=labels,
    autopct='%.0f%%', 
    pctdistance=1.15-width, 
    wedgeprops={'width':width, 'edgecolor':'white'},
    colors=outer_colors)
# step5 内側ドーナツグラフの描画
ax.pie(vals.flatten(), radius=1-width, startangle=90, counterclock=False,
    autopct='%.0f%%', 
    pctdistance=1.1-width, 
    wedgeprops={'width':width, 'edgecolor':'white'},
    colors=inner_colors)
ax.set_title('tab20c in double donut chart')
ax.legend(loc='center left', bbox_to_anchor=(1, 0, 0.5, 1))
plt.show()
参考文献
ドーナツ円グラフ
ラベル付きの円グラフとドーナツ円グラフ


コメント