【matplotlib】可視化實(shí)戰(zhàn)——繪制凸起的餅狀圖

需求

客戶希望繪制一個(gè)特殊的餅狀圖,具體需求如下:

  1. 每個(gè)扇形外側(cè)都有一個(gè)指向扇形的注釋,要有箭頭;
  2. 能夠指定每個(gè)扇形的半徑;
  3. 能夠指定每個(gè)扇形的顏色;
  4. 餅狀圖要有陰影;
  5. 各個(gè)扇形要有一定的凸起。

實(shí)現(xiàn)

首先,針對(duì)需求我們進(jìn)行一下分析,先從需求 2 看起,plt.pie() 方法提供了一個(gè)關(guān)鍵字參數(shù) radius,通過(guò)這個(gè)參數(shù)可以指定餅狀圖的半徑,但是這里只能傳遞一個(gè)浮點(diǎn)數(shù),不能傳遞一個(gè)數(shù)組,也就是說(shuō)不能單獨(dú)指定每一個(gè)扇形的半徑,如果傳遞一個(gè)容器類型,則會(huì)拋出 TypeError: 'radius' must be an instance of numbers.Number, not a list 錯(cuò)誤。因此我們只得另辟蹊徑,首先 plt.pie() 方法是有返回值的,一般情況下他會(huì)返回兩個(gè)值,第一個(gè)是包含所有扇形 Artist 子實(shí)例的 Wedge 對(duì)象列表;第二個(gè)是包含所有扇形標(biāo)簽的 Text 對(duì)象列表;除此之外,如果 autopct 參數(shù)不為空,則會(huì)返回第三個(gè)值,從需求 1 和需求 2 來(lái)看,我們就需要前兩個(gè)返回值即可,因此代碼是 wedges, texts, *_ = plt.pie(...)。通過(guò) Wedge 對(duì)象的 set_radius() 方法完成需求 2。這里提一嘴,由于我們?cè)O(shè)置了陰影,調(diào)用 Axes.patches 屬性不光會(huì)獲取餅狀圖所有的 Wedge 對(duì)象,也會(huì)獲取所有的陰影 Shadow對(duì)象,當(dāng)然我們可以進(jìn)行過(guò)濾,但是實(shí)現(xiàn)起來(lái)多了一步,沒(méi)那個(gè)必要。

需求 3、需求 4 和需求 5 非常簡(jiǎn)單,plt.pie() 方法本身提供了相關(guān)的關(guān)鍵字參數(shù),只需要指定 shadow=Truecolor=colors[i]explode=explodes 就可以實(shí)現(xiàn)。真正的難點(diǎn)是需求 1,所以重點(diǎn)說(shuō)一下,我們都知道 plt.pie() 方法提供了 labelslabeldistance 這兩個(gè)參數(shù),這兩個(gè)參數(shù)可以控制每個(gè)標(biāo)簽和標(biāo)簽的位置,但是這樣無(wú)法實(shí)現(xiàn)箭頭功能,因此使用 plt.pie() 方法本身提供的能力是無(wú)法實(shí)現(xiàn)需求的。從需求 1 上來(lái)看,繪制要有注釋和箭頭,這兩個(gè)名詞放在一起我們應(yīng)該非常敏感才對(duì),這不就是典型的指向型注釋嘛,因此我們需要使用 annotate 方法實(shí)現(xiàn)需求 1,知道了方法和目標(biāo),實(shí)現(xiàn)起來(lái)就很簡(jiǎn)單了,至此所有的需求都已經(jīng)被實(shí)現(xiàn)了。

最后,整個(gè)程序的完整代碼如下:

import matplotlib.pyplot as plt  
import numpy as np  
  
data = '0.37 0.02 0.24 0.26 0.11'.split()  
data = [float(i) for i in data]  
  
explode = [0.01, 0.02, 0.01, 0.01, 0.02]  
colors = ['#ACCBD0', '#E56F32', '#58C5C0', '#B9CC58', '#9C8679']  
radiuses = [1.33, 1, 1.2, 1.3, 1.05]  
  
fig, ax = plt.subplots(figsize=(6, 6))  # 設(shè)置繪圖區(qū)域大小  
  
wedges, texts = ax.pie(data, startangle=0, explode=explode, shadow=True, colors=colors, radius=radiuses)  
kw = dict(arrowprops=dict(arrowstyle='-'),  
          zorder=0, va='center')  
  
for i, p in enumerate(wedges):  
    ang = (p.theta2 - p.theta1) / 2. + p.theta1  
    y = np.sin(np.deg2rad(ang))  
    x = np.cos(np.deg2rad(ang))  
    horizontalalignment = {-1: 'right', 1: 'left'}[int(np.sign(x))]  
    connectionstyle = f'angle,angleA=0,angleB={ang}'  
    kw['arrowprops'].update({'connectionstyle': connectionstyle})  
    ax.annotate(data[i], xy=(x, y), xytext=(1.35 * np.sign(x),  1.4 * y), color=colors[i],  
                horizontalalignment=horizontalalignment, **kw)  
  
ax.axis('equal')  
  
for text, wedge, radius in zip(texts, wedges, radiuses):  
    wedge.set_radius(radius)  
  
  
plt.show()

畫圖結(jié)果如下:

繪圖效果

往期回顧

  1. 【matplotlib】可視化實(shí)戰(zhàn)1——繪制帶顏色帶的折線圖

文中難免會(huì)出現(xiàn)一些描述不當(dāng)之處(盡管我已反復(fù)檢查多次),歡迎在留言區(qū)指正,相關(guān)的知識(shí)點(diǎn)也可進(jìn)行分享,希望大家都能有所收獲??!如果覺(jué)得我的文章寫得還行,不妨支持一下。你的每一個(gè)轉(zhuǎn)發(fā)、關(guān)注、點(diǎn)贊、評(píng)論都是對(duì)我最大的支持!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容