Pythonでレーダーチャートを書きたい(自前でSeries,DF用をそれぞれ書く)

レーダーチャートはmatplotlibなどにはデフォルトがなく、自前実装が必要です。自分の用途に合わせ得て最低限データフレームとシリーズにそれぞれ対応した関数をまとめておきます

基本的な処理

  1. 表示の設定を行う
  2. ベースの表示を円形にする
  3. x軸(ここでは、可視化する変数数)を円上に均等に割り当てる
  4. y軸(ここでは、上の軸の長さ)を設定する

  5. データの可視化を行う

  6. 対象のデータのxとyの位置を指定し線でつなぐ

シリーズを渡す場合

indexがx軸の数(可視化軸)、値がy軸(位置)であるとします。

import matplotlib.pyplot as plt
import pandas as pd

def rader_chart(pd_series):

  # x軸の数と、配置のための角度を計算する
  vertex_num = [v for v in range(pd_series.size)]
  f = lambda x : x / len(vertex_num) * 2 * 3.14
  angles = list(map(f,vertex_num))

  #表示の設定を行う
  ax = plt.subplot(111,polar=True)
  plt.xticks(angles,pd_series.index)
  plt.ylim(0,pd_series.max())

  #データの可視化を行う
  plot_data = list(pd_series.values)
  plot_data += plot_data[:1]
  angles += angles[:1]

  ax.plot(angles,plot_data)

v = pd.Series([i * 10 for i in range(6)])
rader_chart(v)
rader_chart(v[::-1])

二回実施ずれば重ねることも可能です。 f:id:esu-ko:20200805223848p:plain

ただし、このままだと、最大値が違う場合、うまく表示できません。 データフレーム版も検討します。

データフレームの場合

ピボットテーブルやgroupbyしたデータを渡すことをイメージします。 このときindexが線そのものの数、columnがx軸の数であることを想定します。

コードはほぼ同じです。

def rader_chart_from_df(pd_df):
  vertex_num = [v for v in range(pd_df.shape[1])]

  f = lambda x : x / len(vertex_num) * 2 * 3.14
  angles = list(map(f,vertex_num))

  ax = plt.subplot(111,polar=True)
  plt.xticks(angles,pd_df.columns)
  plt.ylim(0,pd_df.max().max())

  #ループを回して、グループごとに可視化する
  angles += angles[:1]
  for col in pd_df.T.columns:
    plot_data = pd_df.T[col].to_list()
    plot_data += plot_data[:1]
  

    ax.plot(angles,plot_data,label=col)
  plt.legend()
import random
df = pd.DataFrame(
    {
        'ctg_a':[10,20,30,40,50],
        'ctg_b':[random.random() * 100 for i in range(5)],
        'ctg_c':[random.random() * 100 for i in range(5)],
        'ctg_d':[random.random() * 100 for i in range(5)]

    }
    ,index = ['A','B','C','D','E']
)

rader_chart_from_df(df)

f:id:esu-ko:20200805224301p:plain

ファセットは今後考えるとします。