はじめに
鶏頭図という言葉はあんまり馴染みのない言葉だと思いますが、この図を考案したのはかの有名なナイチンゲールであると言われています。
英語ではpolar area diagramとかNightingale rose diagramだとか言われているらしいです。
なるほど確かに鶏の鶏冠のように見えるから「鶏頭」なのかと思いがちですが、wikipediaによるとどうやらナイチンゲールはこの図を鶏頭とは読んでいなかったそう。
(https://ja.wikipedia.org/wiki/%E5%86%86%E3%82%B0%E3%83%A9%E3%83%95)
名前の由来はさておき、ナイチンゲールはこのような可視化の技術を使ってクリミア戦争に参加した兵の衛生状態などを政治家などにわかりやすく伝えていたそうです。確かに極座標的な表現を使うことで、角度だけではなく、面積も用いることができ二次元の情報を視覚的にわかりやすく表現できています。
温故知新ということで私もこのプロットを使おうと思ったのですが、思ったよりも苦戦してしまったので、そのやり方を備忘的に記しておこうかなと思います。
準備
今回はmatplotlibを使って実装してみたいと思います。
barplotのwidthをxと対応させて、axのpolarパラメーターをTrueにすることによって綺麗な鶏頭図に仕立て上げるという戦法で行きます。
import
使うのはこの二種類。
import matplotlib.pyplot as plt
import numpy as np
データの用意
適当に10個用意してみましょう。
x = np.array([np.random.randint(1, 10) for i in range(10)])
y = np.array([np.random.randint(1, 10) for i in range(10)])
まずはbarplot
幅をxに対応させ、高さをyに対応させます。
最後に丸くするので、横軸の幅はそれぞれの合計が2πになるように標準化します。
そうすると今度はxの位置をうまく調整して、さまざまな幅の軸が重ならず上手く隣り合うように調整してあげる必要があります。
width = x * 2 * np.pi / sum(x)
theta = np.insert(width.cumsum(), 0, 0)[:-1]
plt.figure(figsize=(10, 10))
ax = plt.subplot(111)
ax.bar(theta, y, width=width, align='edge')
解説します。
widthはxを合計が2πになるように標準化したもので理解できると思います。
thetaに関してですが、累積和を求めてそれぞれのwidthに対応したx軸上の位置を決めてあげます。しかし、最初の一個目は0にしてあげたいので0を先頭にinsertして、最後のx軸の値は要らなくなるのでスライスして消えてもらいます。
幅の異なるbarたちが肩を寄せ合って並んでくれました。なんと微笑ましい。
polarにする
こいつを丸めてあげましょう。
plt.figure(figsize=(10, 10))
ax = plt.subplot(111, polar=True)
ax.bar(theta, y, width=width, align='edge')
WAになって踊ろうを彷彿させる図が出来ました。barたちが形を変えながらも、綺麗に犇めきあっているのが気持ちいいです。
見やすく整える
なんだかスタートが右からだし、左回りだし見づらいですね。
時間に縛られて生きる現代人の感覚的にはやはり12時スタート、右回りにしたいものです。
おまけに度数表記より%表記にしたいのでやっちゃいます。
ax.set_theta_zero_location('N')
ax.set_theta_direction(-1)
ax.set_thetagrids(np.arange(0, 360, 36), labels=["0%", "10%", "20%", "30%","40%","50%", "60%", "70%", "80%", "90%"])
ax.set_rgrids(np.arange(0, y.max()+1, 1), angle=0)
全コード
忙しい方はこちらをどうぞ。
import matplotlib.pyplot as plt
import numpy as np
x = np.array([np.random.randint(1, 10) for i in range(10)])
y = np.array([np.random.randint(1, 10) for i in range(10)])
width = x * 2 * np.pi / sum(x)
theta = np.insert(width.cumsum(), 0, 0)[:-1]
plt.figure(figsize=(10, 10))
ax = plt.subplot(111, polar=True)
ax.bar(theta, y, width=width, align='edge', color=plt.cm.Paired(np.arange(10)))
ax.set_theta_zero_location('N')
ax.set_theta_direction(-1)
ax.set_thetagrids(np.arange(0, 360, 36), labels=["0%", "10%", "20%", "30%","40%","50%", "60%", "70%", "80%", "90%"])
ax.set_rgrids(np.arange(0, y.max()+1, 1), angle=0)
plt.show()
終わりに
plotのセンスを磨く前にまずは色々自在に操れるようになりたいです。やりたいplotイメージがあっても実装につまりがちです。このplotめちゃ苦戦した。