【Python, matplotlib】レーダーチャートを作成してみる~初心者向け~

今回は、Pythonでのグラフ作成で苦労したレーダーチャートの作り方と考え方をまとめます。

上記図1のような、レーダーチャートを作成することです。このグラフを作成する過程も合わせて記載していきます。最後までご覧いただければ、レーダーチャートを自在に作成できるようになるはずです(多分)。

Baran

早速見ていきましょう!

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. レーダーチャート作成

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つ用意しています。

図3 レーダーチャート外観

subplotsのprojectionを詳しく知りたい方はこちら↓

projection{None, ‘aitoff’, ‘hammer’, ‘lambert’, ‘mollweide’, ‘polar’, ‘rectilinear’, str}, optional

The projection type of the subplot (Axes). str is the name of a custom projection, see projections. The default None results in a ‘rectilinear’ projection.

https://matplotlib.org/stable/api/figure_api.html#matplotlib.figure.Figure.add_subplot

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 レーダーチャート1 (線が閉じていない)

図4のようにすでにレーダーチャートのような図ができますが、線が閉じてるように修正していきます。以下のコードのように修正します。修正箇所は以下の2つです。

  1. angelsの回転座標を一つ増やす。num=len(df[f”{lable}”])+1
  2. 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のようなレーダーチャートが作成されます。もうほとんど完成ですね(笑)。

図5 レーダーチャート2 (線が閉じている)

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")
図6 レーダーチャート3 (線内部を塗りつぶす)

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')
図7 レーダーチャート4 (ラベル追加&表示位置を変更)

なお、”set_thetagrids”や”set_theta_zero_location”配下をご参考ください。

When called with no arguments, thetagrids simply returns the tuple (lineslabels). When called with arguments, the labels will appear at the specified angles.

matplotlib.pyplot.thetagrids

Set the location of theta’s zero.

set_theta_zero_location(selflocoffset=0.0)

2-5. 表示範囲指定

以下のコードで回転方向の表示範囲を指定します。今回は点数データが60 から100点なので、表示範囲を50から100とします。

ax[0].set_rlim(50, 100)
ax[1].set_rlim(50, 100)
図8 レーダーチャート5 (回転方向の表示範囲を変更)

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("--")
図9 レーダーチャート6 (回転方向の表示範囲を変更)

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)
図10 レーダーチャート7 (タイトルと凡例を表示)

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()
図11 レーダーチャート8 (完成形)

3. まとめ

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

Baran

ぜひ、有効にご活用ください。

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()

Baran

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

Baran

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

Twitterもやってまーす。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

ABOUT US

Baran-gizagiza
経歴:浪人→理系大学院卒業→大手製造業に就職(技術職)→アメリカ赴任中 仕事は、研究・設計など上流工程の仕事に携わっています。企業勤務を継続しながら、新しいことにチャレンジしたいと思い、ブログを下記はじめました。 このブログでは、趣味である 筋トレ(健康、ダイエット) AIとデータ(高校数学、プログラミング) 読書(主に自己啓発系) を中心に、人生経験やおすすめ情報の発信しています。