Python 詳解雷達圖/蛛網(wǎng)圖

雷達圖-pyecharts

蛛網(wǎng)圖祷肯,最早知道是在玩FIFA游戲的時候沉填,球員的能力用蛛網(wǎng)圖來表示與比較,那時覺得非常新鮮佑笋。后來翼闹,在實際的工作中,其實很少用到:一方面蒋纬,直接提供蛛網(wǎng)圖的工具少猎荠;另一方面,過往的經(jīng)歷中多維度比較用到的地方也比較少蜀备。

在學習Python的過程中关摇,重新燃起對雷達圖的興趣,但在python重要的圖庫MatplotlibSeaborn里都沒有直接實現(xiàn)雷達圖的函數(shù)碾阁。因此输虱,雖然感興趣,也沒有去觸及脂凶,直到一天在Udacity數(shù)據(jù)分析進階VIP班的一個學生的Tableau作業(yè)里看到他使用了雷達圖(Tableau圖庫里也沒有直接提供雷達圖)宪睹,使我饒有興趣地去思考雷達圖到底是什么愁茁?

最初的想法

最初的想法,在直角坐標系通過畫圓的方式尋找多邊形在圓軸上點的坐標亭病,只要知道半徑r長度鹅很,以及原點與圓周上的點的連線與X軸的夾角\theta便能通過三角函數(shù)求出x與y 的坐標。

向量.png

半徑r可看作是一個向量罪帖。向量是一個方向道宅,向量中的每一個元素代表著維度,維度的值是維度方向的距離胸蛛。直角坐標系由x軸,y軸及原點組成的二維空間樱报,x是一個維度葬项,x的值在x軸方向上與原點之間的距離,y是另一個維度迹蛤,同樣的民珍,y的值則是在y軸方向上與原點的距離,x與y平行移動的交匯點為坐標盗飒,坐標點與原點的連線是x軸與y軸上的兩個兩個向量的相加所形成的新向量嚷量,暫命名為A向量,A向量的長度為r逆趣,圍繞著原點旋轉(zhuǎn)便能形成一個以原點為圓心蝶溶,r為半徑的圓这敬,根據(jù)A向量與x軸行程的角度\theta 總能得出A向量在x軸上的長度為x = \cos\theta \times r储狭,在y軸上的長度為y = \sin\theta \times r,由此祖秒,可以得出該在圓上的任意一個點的坐標(x,y)痕囱。

假設(shè)雷達圖由6個維度構(gòu)成田轧,那么最初躺在x軸上的向量r相當于旋轉(zhuǎn)了6次,每次旋轉(zhuǎn)60o在圓周上留下一個點鞍恢,點與點之間的連線構(gòu)成了雷達圖傻粘。那么,使用折線圖便能實現(xiàn)雷達圖帮掉。

突然醒悟

仔細翻讀Matplotlib的范例弦悉,看到了polar坐標系,突然想明白:為什么不直接旋轉(zhuǎn)X坐標軸呢蟆炊?將直角坐標系中的X軸首尾相連繞成了一個圓警绩,將x軸的線性的長度轉(zhuǎn)換成了弧長,Y軸不變盅称,在此之下的折線圖就是雷達圖肩祥,僅此而已后室。想明白了,生成雷達圖便成了輕而易舉之事混狠。接下來岸霹,將詳細解釋雷達圖編寫的過程。

用Python繪制雷達圖

pyechart用python語言制作了一系列流行的圖将饺,其中包括雷達圖贡避。我將其雷達圖的截圖放在了本文的最頂端。然而pyechart只是用Python語言生成的Java予弧,應用在html里刮吧。當然,在實際應用中掖蛤,用網(wǎng)頁顯示與觀眾的互動性更強杀捻,如果用網(wǎng)頁作為儀表盤,顯然使用pyechart就好了蚓庭。但在這里致讥,我期望去了解雷達圖的原理,因此借用pyechart-雷達圖 示例中的數(shù)據(jù)器赞,用Matplotlib 來重現(xiàn)垢袱。

用Matplotlib 繪制的雷達圖

這是使用Matplotlib畫出的結(jié)果,除了不會動態(tài)顯示數(shù)據(jù)以外港柜,長相與pyechart的雷達圖基本保持了一致请契,過程并不復雜。接下來夏醉,將分步驟展現(xiàn)實現(xiàn)的過程與代碼姚糊。

Python分步驟實現(xiàn)雷達圖

1. 范例數(shù)據(jù)

schema = [ 
("銷售", 6000),
("管理", 16000),
("信息技術(shù)", 30000),
("客戶服務", 38000),
("研發(fā)", 52000), 
("市場", 25000)
]
v1 = [[4300, 10000, 28000, 35000, 50000, 19000]]
v2 = [[5000, 14000, 28000, 31000, 42000, 21000]]

schema 中包含標簽與6個維度分別的總分,v1授舟、v2可能是2個部門分別按6個維度打分的結(jié)果救恨。整理數(shù)據(jù),首先抽出labels释树, 然后對v1肠槽、v2 進行歸一(標準化,normalize)奢啥,將分值轉(zhuǎn)化為比率秸仙,或百分制。

# 拆分schema到標簽labs與總分full_marks
labs = []
full_marks = []
for value in schema:
    labs.append(value[0])
    full_marks.append(value[1])

# v1,v2進行歸一處里
Y = np.vstack((v1,v2))          
Y = Y/np.array(full_marks)

print('labs = {}'.format(labs))
print('Y = {}'.format(Y))
--------------------------------------------------------------------------
Output:
labs = ['銷售', '管理', '信息技術(shù)', '客戶服務', '研發(fā)', '市場']
Y = [[ 0.71666667  0.625       0.93333333  0.92105263  0.96153846  0.76      ]
 [ 0.83333333  0.875       0.93333333  0.81578947  0.80769231  0.84      ]]

2. X軸變形

x軸上所呈現(xiàn)的應該是labs桩盲,用labs的index來作為x軸上的坐標寂纪,由于x軸將由一根直線首尾相接成圓,原先x軸上的點離原點的距離r將相應地換算為弧長L,每一維度間所間隔的角度 \theta由維度N決定捞蛋,將圓周長切分成N個等份的弧度孝冒。弧長的計算公式為: L =2 r \times \pi \times \frac{\theta}{360}

# 獲取 r 與 theta
N = len(labs)
r = np.arange(N) 
theta = np.linspace(0, 360, N, endpoint=False) 

# 將角度轉(zhuǎn)化為單位弧度
X_ticks = np.radians(theta) # x軸標簽所在的位置

print(' N = {:d}, \n r = {}, \n theta = {}, \n X_ticks = {}'.format(N, r, theta, X_ticks))
-------------------------------------------------------------------
Output:
N = 6, 
r = [0 1 2 3 4 5], 
theta = [   0.   60.  120.  180.  240.  300.], 
X_ticks = [ 0.      1.0472  2.0944  3.1416  4.1888  5.236 ]

3. 制圖1

簡單地轉(zhuǎn)換一下X軸的數(shù)值拟杉,然后設(shè)置坐標系為“polar”庄涡,雷達圖應該就能被制作出來了。

fig, ax = plt.subplots(subplot_kw=dict(projection='polar'))
ax.plot(X_ticks, Y[0], marker='o')
ax.plot(X_ticks, Y[1], marker='o')
ax.set_xticks(X_ticks)
plt.show()
首次嘗試

首次嘗試的雷達圖有一些問題:

  1. 聯(lián)線缺了一個口搬设,需要將數(shù)列的第一個數(shù)字增補到最后一個穴店,使得首位相連;
  2. 圖像看起來有些歪拿穴,正中點在水平線上泣洞,尤其是單數(shù)維度時。因此需要旋轉(zhuǎn)圖像默色,使得正中點在垂直線上球凰。

4. 調(diào)整

# 獲取 r 與 theta
N = len(labs)
r = np.arange(N) 
theta = np.linspace(0, 360, N, endpoint=False) 

# 調(diào)整角度使得正中在垂直線上
adj_angle = theta[-1] + 90 - 360
theta += adj_angle

# 將角度轉(zhuǎn)化為單位弧度
X_ticks = np.radians(theta) # x軸標簽所在的位置

# 首尾相連
X = np.append(X_ticks,X_ticks[0])
Y = np.hstack((Y, Y[:,0].reshape(2,1)))

print('theta = {}, \nX = {}, \nY={}'.format(theta, X.round(4), Y.round(2)))
-------------------------------------------------------------------------
Output:
theta = [  30.   90.  150.  210.  270.  330.], 
X = [ 0.5236  1.5708  2.618   3.6652  4.7124  5.7596  0.5236], 
Y=[[ 0.72  0.62  0.93  0.92  0.96  0.76  0.72]
 [ 0.83  0.88  0.93  0.82  0.81  0.84  0.83]]

所有的角度增加了30o,X與Y軸的首尾的數(shù)字都已相同该窗,雷達圖應該就緒。

二次嘗試

執(zhí)行與首次制圖時相同的代碼蚤霞,只是把X_ticks與Y替換成調(diào)整后的X與Y酗失,雷達圖的內(nèi)里已經(jīng)全部出來了,與pyechart雷達圖的圖形一致昧绣,現(xiàn)在還差一些形狀與數(shù)據(jù)標簽规肴。

5. 背景制作

fig, ax = plt.subplots(figsize=(5, 5),
                             subplot_kw=dict(projection='polar'))
# 畫圖
ax.plot(X, Y[0], marker='o')
ax.plot(X, Y[1], marker='o')
ax.set_xticks(X)

# 設(shè)置背景坐標系
ax.set_xticklabels(labs, fontproperties = labFont, fontsize = 'large') # 設(shè)置標簽
ax.set_yticklabels([]) 
ax.spines['polar'].set_visible(False) # 將軸隱藏
ax.grid(axis='y') # 只有y軸設(shè)置grid


# 設(shè)置X軸的grid
n_grids = np.linspace(0,1, 6, endpoint=True) # grid的網(wǎng)格數(shù)
grids = [[i] * (len(X)) for i in n_grids] #grids的半徑

for i, grid in enumerate(grids[:-1]): # 給grid 填充間隔色
    ax.plot(X, grid, color='grey', linewidth=0.5)
    if (i>0) & (i % 2 == 0):
        ax.fill_between(X, grids[i], grids[i-1], color='grey', alpha=0.1) 

plt.show()
接近成功

基本上成功了,就差一個軸 (sprine) 的設(shè)置夜畴,非常抱歉沒有弄懂Matplotlib如何去設(shè)置軸的形狀拖刃,不過好在他的范例中給出了雷達圖的函數(shù)代碼,運行這段函數(shù)贪绘,向figure中的projection注冊了這段代碼后兑牡,將上文的代碼中的'polar' 改為'radar'便大功告成了。重寫的完整代碼如下:

# 調(diào)用Radar圖函數(shù)
N = len(labs)
theta = radar_factory(N, frame='polygon')

fig, ax = plt.subplots(figsize=(5, 5),
                             subplot_kw=dict(projection='radar'))
# 畫圖
ax.plot(X, Y[0], marker='o')
ax.plot(X, Y[1], marker='o')
ax.set_xticks(X)

# 設(shè)置背景坐標系
ax.set_xticklabels(labs, fontproperties = labFont, fontsize = 'large') # 設(shè)置標簽
ax.set_yticklabels([]) 
ax.spines['polar'].set_visible(False) # 將軸隱藏
ax.grid(axis='y') # 只有y軸設(shè)置grid


# 設(shè)置X軸的grid
n_grids = np.linspace(0,1, 6, endpoint=True) # grid的網(wǎng)格數(shù)
grids = [[i] * (len(X)) for i in n_grids] #grids的半徑

for i, grid in enumerate(grids[:-1]): # 給grid 填充間隔色
    ax.plot(X, grid, color='grey', linewidth=0.5)
    if (i>0) & (i % 2 == 0):
        ax.fill_between(X, grids[i], grids[i-1], color='grey', alpha=0.1) 

plt.show()

結(jié)果已在前述展示過了税灌,不再重復均函。


參考:
Radar chart (aka spider or star chart) https://matplotlib.org/gallery/specialty_plots/radar_chart.html?highlight=radar

pyechart-雷達圖 http://pyecharts.org/#/zh-cn/charts_base?id=radar(雷達圖)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市菱涤,隨后出現(xiàn)的幾起案子苞也,更是在濱河造成了極大的恐慌,老刑警劉巖粘秆,帶你破解...
    沈念sama閱讀 218,525評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件如迟,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機殷勘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評論 3 395
  • 文/潘曉璐 我一進店門此再,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人劳吠,你說我怎么就攤上這事引润。” “怎么了痒玩?”我有些...
    開封第一講書人閱讀 164,862評論 0 354
  • 文/不壞的土叔 我叫張陵淳附,是天一觀的道長。 經(jīng)常有香客問我蠢古,道長奴曙,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,728評論 1 294
  • 正文 為了忘掉前任草讶,我火速辦了婚禮洽糟,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘堕战。我一直安慰自己坤溃,他們只是感情好,可當我...
    茶點故事閱讀 67,743評論 6 392
  • 文/花漫 我一把揭開白布嘱丢。 她就那樣靜靜地躺著薪介,像睡著了一般。 火紅的嫁衣襯著肌膚如雪越驻。 梳的紋絲不亂的頭發(fā)上汁政,一...
    開封第一講書人閱讀 51,590評論 1 305
  • 那天,我揣著相機與錄音缀旁,去河邊找鬼记劈。 笑死,一個胖子當著我的面吹牛并巍,可吹牛的內(nèi)容都是我干的目木。 我是一名探鬼主播,決...
    沈念sama閱讀 40,330評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼懊渡,長吁一口氣:“原來是場噩夢啊……” “哼嘶窄!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起距贷,我...
    開封第一講書人閱讀 39,244評論 0 276
  • 序言:老撾萬榮一對情侶失蹤柄冲,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后忠蝗,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體现横,經(jīng)...
    沈念sama閱讀 45,693評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,885評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了戒祠。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片骇两。...
    茶點故事閱讀 40,001評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖姜盈,靈堂內(nèi)的尸體忽然破棺而出低千,到底是詐尸還是另有隱情,我是刑警寧澤馏颂,帶...
    沈念sama閱讀 35,723評論 5 346
  • 正文 年R本政府宣布示血,位于F島的核電站,受9級特大地震影響救拉,放射性物質(zhì)發(fā)生泄漏难审。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,343評論 3 330
  • 文/蒙蒙 一亿絮、第九天 我趴在偏房一處隱蔽的房頂上張望告喊。 院中可真熱鬧,春花似錦派昧、人聲如沸黔姜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽秆吵。三九已至,卻和暖如春岖是,著一層夾襖步出監(jiān)牢的瞬間帮毁,已是汗流浹背实苞。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評論 1 270
  • 我被黑心中介騙來泰國打工豺撑, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人黔牵。 一個月前我還...
    沈念sama閱讀 48,191評論 3 370
  • 正文 我出身青樓聪轿,卻偏偏與公主長得像,于是被迫代替她去往敵國和親猾浦。 傳聞我的和親對象是個殘疾皇子陆错,可洞房花燭夜當晚...
    茶點故事閱讀 44,955評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 1 前言 OpenGL渲染3D模型離不開空間幾何的數(shù)學理論知識,而本篇文章的目的就是對空間幾何進行簡單的介紹金赦,并對...
    RichardJieChen閱讀 6,998評論 1 11
  • 一前言 特征值 奇異值 二奇異值計算 三PCA 1)數(shù)據(jù)的向量表示及降維問題 2)向量的表示及基變換 3)基向量 ...
    Arya鑫閱讀 10,539評論 2 43
  • 1 CALayer IOS SDK詳解之CALayer(一) http://doc.okbase.net/Hell...
    Kevin_Junbaozi閱讀 5,152評論 3 23
  • 窗外淅淅瀝瀝的下著小雨音瓷,怎么邁不動出門的腳步?窗簾低垂,一片粉色夹抗,細雨如絲绳慎,朦朦朧朧,思緒,也不知所以杏愤,飄浮不定靡砌。...
    趣愛閱讀 142評論 0 0
  • 異鄉(xiāng) 埋葬著不同的姓氏 在田頭山間 不安的靈魂無處徘徊 放出脆弱的紙鳶 飄搖著 尋向死去的自己 一場雨 未肯灑落悲...
    瓦縫里的星空閱讀 169評論 0 0