今回は、Pythonでのグラフ作成で苦労したレーダーチャートの作り方と考え方をまとめます。
上記図1のような、レーダーチャートを作成することです。このグラフを作成する過程も合わせて記載していきます。最後までご覧いただければ、レーダーチャートを自在に作成できるようになるはずです(多分)。
▼ Contents
1. サンプルデータ
使用するデータは以下のコードのように各科目の点数(100点満点)を想定して作成します。そうすると、図2のようなデータフレームが作成できます。他のデータフレームであれば、ご自身のデータでも問題ありません。
import pandas as pd
data = {'A': [100, 90, 80, 70, 60],
'B': [60, 70, 80, 90, 100]
}
df = pd.DataFrame(data, index=['Math', 'Science', 'Japanese', 'English', 'PE'])

2. レーダーチャート作成
2-1. レーダーチャート外観 (Subplots)
まずはレーダーチャートの外形の作成ため、今回はsubplots関数を使用します。以下のコードを入力します。”subplot_kw={‘projection’: ‘polar’}”で”polar”を設定します。
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots(1, 2, figsize=(20, 24), subplot_kw={'projection': 'polar'})
出力すると、図3のような座標が表示されます。今回は説明のため、図を2つ用意しています。

subplotsのprojectionを詳しく知りたい方はこちら↓
projection{None, ‘aitoff’, ‘hammer’, ‘lambert’, ‘mollweide’, ‘polar’, ‘rectilinear’, str}, optional
The projection type of the subplot (
https://matplotlib.org/stable/api/figure_api.html#matplotlib.figure.Figure.add_subplotAxes
). str is the name of a custom projection, seeprojections
. The default None results in a ‘rectilinear’ projection.
2-2. データプロット
それではデータをプロットしていきたいと思います。以下のコードを入力します。
“angles”はプロットする回転座標の値を格納します。
“values”は、anglesで指定した回転座標の値を格納します。
angles_A = np.linspace(start=0, stop=2*np.pi, num=len(df["A"]), endpoint=True)
values_A = df["A"]
angles_B = np.linspace(start=0, stop=2*np.pi, num=len(df["B"]), endpoint=True)
values_B = df["B"]
fig, ax = plt.subplots(1, 2, figsize=(20, 24), subplot_kw={'projection': 'polar'})
ax[0].plot(angles_A, values_A, 'o-', color="blue", label="A")
ax[1].plot(angles_B, values_B, 'o-', color="blue", label="B")

図4のようにすでにレーダーチャートのような図ができますが、線が閉じてるように修正していきます。以下のコードのように修正します。修正箇所は以下の2つです。
- angelsの回転座標を一つ増やす。num=len(df[f”{lable}”])+1
- valuesの最後の値に、最初の値を追加します。np.concatenate((df[f”{lable}”], [df[f”{lable}”][0]]))、例 ‘A’: [100, 90, 80, 70, 60] => ‘A’: [100, 90, 80, 70, 60, 100]となる。
angles_A = np.linspace(start=0, stop=2*np.pi, num=len(df["A"])+1, endpoint=True)
values_A = np.concatenate((df["A"], [df["A"][0]]))
angles_B = np.linspace(start=0, stop=2*np.pi, num=len(df["B"])+1, endpoint=True)
values_B = np.concatenate((df["B"], [df["B"][0]]))
fig, ax = plt.subplots(1, 2, figsize=(20, 24), subplot_kw={'projection': 'polar'})
ax[0].plot(angles_A, values_A, 'o-', color="blue", label="A")
ax[1].plot(angles_B, values_B, 'o-', color="blue", label="B")
上記コードを入力すると、図5のようなレーダーチャートが作成されます。もうほとんど完成ですね(笑)。

2-3.データ塗りつぶし
あとは、線の内側を色で塗りつぶして見たいと思います。以下のコードを入力します。すると、図6のように線の内側も塗りつぶせます。
ax[0].fill(angles_A, values_A, alpha=0.3, color="blue")
ax[1].fill(angles_B, values_B, alpha=0.3, color="blue")

2-4. ラベル設定と回転座標設定
次に各点の名前をつけていきます。angelsで指定した回転座標のみのラベルが作成されます。また、”Math”のラベルを上にしたいので、以下のコードでレーダーチャート位置表示を変更します。今回は、set_theta_zero_location(‘N’)として、頂点(Math)を北側(つまり’N’)にしています。
ax[0].set_thetagrids(angles[:-1] * 180 / np.pi, columns, fontsize=15)
ax[0].set_theta_zero_location('N')
ax[1].set_thetagrids(angles[:-1] * 180 / np.pi, columns, fontsize=15)
ax[1].set_theta_zero_location('N')

なお、”set_thetagrids”や”set_theta_zero_location”配下をご参考ください。
When called with no arguments,
matplotlib.pyplot.thetagridsthetagrids
simply returns the tuple (lines, labels). When called with arguments, the labels will appear at the specified angles.
Set the location of theta’s zero.
set_theta_zero_location
(self, loc, offset=0.0)
2-5. 表示範囲指定
以下のコードで回転方向の表示範囲を指定します。今回は点数データが60 から100点なので、表示範囲を50から100とします。
ax[0].set_rlim(50, 100)
ax[1].set_rlim(50, 100)

2-6. グリッドライン変更
グリッドラインの表示を変更します。例えば、80点が平均点の場合、80点ラインをわかりやすく点線表示に変更します。
以下のコードを入力します。注意点はグリッドデータは、回転軸方向の値で定められているので、現在の状況では、[60, 70, 80, 90, 100]のグリッドラインデータを持っています。
そのため、”gridlines[2]”は[60, 70, 80, 90, 100]の3番目の”80″のグリッドラインを変更しています。出力結果は図9のようになります。
gridlines = ax[0].yaxis.get_gridlines()
gridlines[2].set_color("black")
gridlines[2].set_linewidth(2)
gridlines[2].set_linestyle("--")
gridlines = ax[1].yaxis.get_gridlines()
gridlines[2].set_color("black")
gridlines[2].set_linewidth(2)
gridlines[2].set_linestyle("--")

2-7. 凡例・タイトル
あとは、タイトルと凡例の位置を指定します。
ax[0].set_title("A", fontsize=15)
ax[0].legend(bbox_to_anchor=(1, 1), loc='upper right', ncol=2)
ax[1].set_title("B", fontsize=15)
ax[1].legend(bbox_to_anchor=(1, 1), loc='upper right', ncol=2)

2-8. グラフを重ねる
こちらは上記のコードを”A”と”B”でfor文を使用すれば実現できます。以下はサンプルコードです。
fig, ax = plt.subplots(1, 2, figsize=(20, 24), subplot_kw={'projection': 'polar'})
columns = df.index
for i, label in enumerate(df.columns):
ax[i].plot(angles_A, values_A, 'o-', color="blue", label="A")
ax[i].fill(angles_A, values_A, alpha=0.3, color="blue")
ax[i].plot(angles_B, values_B, 'o-', color="red", label="B")
ax[i].fill(angles_B, values_B, alpha=0.3, color="red")
ax[i].set_thetagrids(angles[:-1] * 180 / np.pi, columns, fontsize=15)
ax[i].set_theta_zero_location('N')
ax[i].set_rlim(50, 110)
gridlines = ax[i].yaxis.get_gridlines()
gridlines[2].set_color("black")
gridlines[2].set_linewidth(2)
gridlines[2].set_linestyle("--")
ax[i].set_title(f"Sample {label}", fontsize=15)
ax[i].legend(bbox_to_anchor=(1, 1), loc='upper right', ncol=2)
plt.show()

3. まとめ
今回の全体コードは以下です。少しコードが複雑になりやすいですが、一つずつコードを理解していけば、作成はそこまで難しくはないと思います。

ぜひ、有効にご活用ください。
data = {
'A': [100, 90, 80, 70, 60],
'B': [60, 70, 80, 90, 100]
}
df = pd.DataFrame(data, index=['Math', 'Science', 'Japanese', 'English', 'PE'])
angles_A = np.linspace(start=0, stop=2*np.pi, num=len(df["A"])+1, endpoint=True)
values_A = np.concatenate((df["A"], [df["A"][0]]))
angles_B = np.linspace(start=0, stop=2*np.pi, num=len(df["B"])+1, endpoint=True)
values_B = np.concatenate((df["B"], [df["B"][0]]))
fig, ax = plt.subplots(1, 2, figsize=(20, 24), subplot_kw={'projection': 'polar'})
for i, label in enumerate(df.columns):
ax[i].plot(angles_A, values_A, 'o-', color="blue", label="A")
ax[i].fill(angles_A, values_A, alpha=0.3, color="blue")
ax[i].plot(angles_B, values_B, 'o-', color="red", label="B")
ax[i].fill(angles_B, values_B, alpha=0.3, color="red")
columns = df.index
ax[i].set_thetagrids(angles[:-1] * 180 / np.pi, columns, fontsize=15)
ax[i].set_theta_zero_location('N')
ax[i].set_rlim(50, 110)
gridlines = ax[i].yaxis.get_gridlines()
gridlines[2].set_color("black")
gridlines[2].set_linewidth(2)
gridlines[2].set_linestyle("--")
ax[i].set_title(f"Sample {label}", fontsize=15)
ax[i].legend(bbox_to_anchor=(1, 1), loc='upper right', ncol=2)
plt.show()

それでは、よいPythonライフを!

以下の記事も書いています。よかったらご覧ください。コメントいただけると嬉しいです。

Twitterもやってまーす。
早速見ていきましょう!