用python繪制極坐標(biāo)雷達圖
綜述
python的matplotlib畫圖庫的功能非常強大,可以畫很多很多種圖,我們?nèi)粘I钪杏龅降睦走_圖也不例外。
雷達圖也被稱為網(wǎng)絡(luò)圖,蜘蛛圖,星圖等,是一個不規(guī)則的多邊形。雷達圖可以形象地展示相同事物的多維指標(biāo),應(yīng)用場景非常多,比如本篇博客中,用來展示球員的不同能力的區(qū)別。
matplotlib庫中的雷達圖繪制是基于極坐標(biāo)的,因此所有的數(shù)據(jù)和標(biāo)簽都要根據(jù)角度來計算出位置。
本篇博客將詳細的解釋繪制雷達圖過程中的思路、過程以及各個函數(shù)方法的詳細解析,如有不正確的地方歡迎大佬指正~
繪圖代碼和解析
繪制一張多主體雷達圖
所謂多主體雷達圖,就是在一張圖中顯示多個多邊形組成的屬性圖,形成直觀的對比。
預(yù)處理
對應(yīng)的包下好,然后解決一下中文和符號顯示的問題,設(shè)置默認(rèn)的字體,修改繪圖樣式;
加載數(shù)據(jù)集(我這里的數(shù)據(jù)集來源:某綠色足球app),提取字典中的鍵和值分別保存在labels和score當(dāng)中。
import numpy as np import matplotlib.pyplot as plt plt.rcParams['font.sans-serif'] = ['KaiTi'] # 指定默認(rèn)字體 plt.rcParams['axes.unicode_minus'] = False # 解決保存圖像是負號'-'顯示為方塊的問題 plt.style.use('ggplot') # 設(shè)置ggplot主題樣式 # 原始數(shù)據(jù)集并獲取數(shù)據(jù)集長度 results = [{"速度": 68, "射門": 91, "傳球": 83, "盤帶": 83, "防守": 47, "力量": 82}, {"速度": 88, "射門": 87, "傳球": 82, "盤帶": 86, "防守": 42, "力量": 69}, {"速度": 58, "射門": 55, "傳球": 70, "盤帶": 67, "防守": 86, "力量": 77}] data_length = len(results[0]) # 將極坐標(biāo)根據(jù)數(shù)據(jù)長度進行等分,形成角度列表 angles = np.linspace(0, 2 * np.pi, data_length, endpoint=False) # 分離屬性字段和數(shù)據(jù) labels = [key for key in results[0].keys()] score = [[v for v in result.values()] for result in results]
封閉雷達圖
由于我們畫出來的圖是一個封閉的多邊形,而我們提取出來的score、labels和angles數(shù)據(jù)的每一項并不是首尾相接的,因此我們需要把每一個列表的第一項copy一下,然后添加到列表末尾。
angles = np.concatenate((angles, [angles[0]])) labels = np.concatenate((labels, [labels[0]])) score_Harry = np.concatenate((score[0], [score[0][0]])) score_Son = np.concatenate((score[1], [score[1][0]])) score_Tobi = np.concatenate((score[2], [score[2][0]]))
這里因為我弄了三個球員的數(shù)據(jù),所以有三條score數(shù)據(jù)。
提一下np.concatenate函數(shù),這是一個numpy庫中對多個數(shù)組進行合并的函數(shù),參數(shù)格式為:concatenate((arr1,arr2,arr3),axis=0),第一個括號里面是要合并的數(shù)組,可以填任意個,第二個axis參數(shù),與合并方式有關(guān),這里我們用不到就不多贅述了。
繪制圖像
繪制圖像基本跟繪制條形圖的步驟差不多,有幾個可以注意的點:
plot函數(shù)中,繪制條形圖是按照“橫坐標(biāo)-縱坐標(biāo)”來填寫第一和第二個參數(shù)的,由于我們雷達圖是基于極坐標(biāo)的,matplotlib也很智能的提供了“角度-半徑”的極坐標(biāo)參數(shù)填寫方式;
plot中的顏色只管邊框顏色,fill函數(shù)中的顏色是填充顏色,可以自由組合追求美觀;
fill函數(shù)中的alpha參數(shù)指的是覆蓋區(qū)的透明度,越小表示越透明,區(qū)間0-1;
plt.legend圖例函數(shù)中的loc,是描述圖例位置的
代碼如下:
# 設(shè)置圖形的大小 fig = plt.figure(figsize=(8, 6), dpi=100) # 新建一個子圖 ax = plt.subplot(111, polar=True) # 繪制雷達圖并填充顏色 ax.plot(angles, score_Harry, color='orange') ax.fill(angles, score_Harry, 'y', alpha=0.4) ax.plot(angles, score_Son, color='b') ax.fill(angles, score_Son, 'cyan', alpha=0.4) ax.plot(angles, score_Tobi, color='r') ax.fill(angles, score_Tobi, 'salmon', alpha=0.4) # 設(shè)置雷達圖中每一項的標(biāo)簽顯示 ax.set_thetagrids(angles * 180 / np.pi, labels, fontsize=15) ax.set_theta_zero_location('E') # 設(shè)置0度坐標(biāo)軸起始位置,東西南北 ax.set_rlim(0, 100) # 設(shè)置雷達圖的坐標(biāo)刻度范圍 ax.set_rlabel_position(270) # 設(shè)置雷達圖的坐標(biāo)值顯示角度,相對于起始角度的偏移量 ax.set_title("熱刺球員能力對比圖") plt.legend(["哈里·凱恩", "孫興愍", "托比"], loc='lower left') plt.show()
完整代碼:
import numpy as np import matplotlib.pyplot as plt # 解決中文顯示問題 plt.rcParams['font.sans-serif'] = ['KaiTi'] # 指定默認(rèn)字體 plt.rcParams['axes.unicode_minus'] = False # 解決保存圖像是負號'-'顯示為方塊的問題 plt.style.use('ggplot') # 設(shè)置ggplot樣式 # 原始數(shù)據(jù)集并獲取數(shù)據(jù)集長度 results = [{"速度": 68, "射門": 91, "傳球": 83, "盤帶": 83, "防守": 47, "力量": 82}, {"速度": 88, "射門": 87, "傳球": 82, "盤帶": 86, "防守": 42, "力量": 69}, {"速度": 58, "射門": 55, "傳球": 70, "盤帶": 67, "防守": 86, "力量": 77}] data_length = len(results[0]) angles = np.linspace(0, 2 * np.pi, data_length, endpoint=False) # 將極坐標(biāo)根據(jù)數(shù)據(jù)長度進行等分 # 分離屬性字段和數(shù)據(jù) labels = [key for key in results[0].keys()] score = [[v for v in result.values()] for result in results] # 使雷達圖數(shù)據(jù)封閉 angles = np.concatenate((angles, [angles[0]])) labels = np.concatenate((labels, [labels[0]])) score_Harry = np.concatenate((score[0], [score[0][0]])) score_Son = np.concatenate((score[1], [score[1][0]])) score_Tobi = np.concatenate((score[2], [score[2][0]])) # 設(shè)置圖形的大小 fig = plt.figure(figsize=(8, 6), dpi=100) # 新建一個子圖 ax = plt.subplot(111, polar=True) # 繪制雷達圖并填充顏色 ax.plot(angles, score_Harry, color='orange') ax.fill(angles, score_Harry, 'y', alpha=0.4) ax.plot(angles, score_Son, color='b') ax.fill(angles, score_Son, 'cyan', alpha=0.4) ax.plot(angles, score_Tobi, color='r') ax.fill(angles, score_Tobi, 'salmon', alpha=0.4) # 設(shè)置雷達圖中每一項的標(biāo)簽顯示 ax.set_thetagrids(angles * 180 / np.pi, labels, fontsize=15) ax.set_theta_zero_location('E') # 設(shè)置0度坐標(biāo)軸起始位置,東西南北 ax.set_rlim(0, 100) # 設(shè)置雷達圖的坐標(biāo)刻度范圍 ax.set_rlabel_position(270) # 設(shè)置雷達圖的坐標(biāo)值顯示角度,相對于起始角度的偏移量 ax.set_title("熱刺球員能力對比圖") plt.legend(["哈里·凱恩", "孫興愍", "托比"], loc='lower left') plt.show()
最后得到的雷達圖:
還是挺好看的(?)
繪制多張單主體雷達圖
數(shù)據(jù)處理部分跟上面一樣,我們直接從畫圖講起。
建立子圖
首先我們用plt.figure繪制好基本畫布之后,需要建立三個子圖(因為有三個球員):
ax1 = plt.subplot(131, polar=True) ax2 = plt.subplot(132, polar=True) ax3 = plt.subplot(133, polar=True)
我們把整個畫布看作一個矩陣,有m行n列;
第一個參數(shù)是一個三位數(shù),第一位表示該子圖在整個畫布的行位置,1表示總共把畫布劃分為1行;第二位表示列,3表示總共把畫布劃分為3列;第三個表示索引值,指的是具體的位置,按照從上到下從左到右排列,比如在一個2*2的畫布中,索引值為3表示在第二行第一個;
循環(huán)遍歷畫每個子圖
首先把畫圖用的子圖、數(shù)據(jù)、標(biāo)簽、顏色都用列表存起來,方便遍歷;
遍歷每一個子圖:
首先畫角度坐標(biāo)軸和框線,’-.'表示框線的樣式是有一個小線段加一個點組成,lw是linewidth的縮寫,表示線的粗細;
先繪制沿半徑方向的等值線,再繪制角度軸;
繪圖并填充顏色,跟上面一樣;
標(biāo)出數(shù)據(jù)下標(biāo),ha和va是調(diào)整水平和垂直方向的位置
最后調(diào)整labels、坐標(biāo)值范圍等參數(shù)
ax, data, name, color = [ax1, ax2, ax3], [score_Harry, score_Son, score_Tobi], ["哈里·凱恩", "孫興愍", "托比"], ["orange", "cyan", "green"] for i in range(3): # 繪制角度軸和框線 for j in np.arange(0, 100+20, 20): ax[i].plot(angles, 7*[j], '-.', lw=0.5, color='black') # 沿半徑方向的等值線 for j in range(5): ax[i].plot([angles[j], angles[j]], [0, 100], '-.', lw=0.5, color='black') # 繪制角度軸 # 繪制圖像并填充顏色 ax[i].plot(angles, data[i], color=color[i]) ax[i].fill(angles, data[i], color=color[i], alpha=0.4) # 數(shù)據(jù)下標(biāo) for a, b in zip(angles, data[i]): ax[i].text(a, b+5, '%.00f' % b, ha='center', va='center', fontsize=10, color='black') # 參數(shù)設(shè)置 ax[i].set_thetagrids(angles*180/np.pi, labels) ax[i].set_theta_zero_location('N') ax[i].set_rlim(0, 100) ax[i].set_rlabel_position(0) ax[i].set_title(name[i])
最后得到效果(個人審美有限,不喜勿噴):
總體來說,強大的matplotlib + 靈活運用代碼 + 美化 = 一幅好看的雷達圖~
總結(jié)
到此這篇關(guān)于用python繪制極坐標(biāo)雷達圖的文章就介紹到這了,更多相關(guān)python坐標(biāo)雷達圖內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python編程中*args與**kwargs區(qū)別作用詳解
這篇文章主要介紹了Python編程中*args與**kwargs區(qū)別作用詳解2021-10-10Python利用contextvars實現(xiàn)管理上下文變量
Python?在?3.7?的時候引入了一個模塊:contextvars,從名字上很容易看出它指的是上下文變量。所以本文就來和大家詳細講講如何使用contextvars實現(xiàn)管理上下文變量,需要的可以參考一下2022-07-07