【matplotlib】可视化实战——绘制凸起的饼状图

需求

客户希望绘制一个特殊的饼状图,具体需求如下:

  1. 每个扇形外侧都有一个指向扇形的注释,要有箭头;
  2. 能够指定每个扇形的半径;
  3. 能够指定每个扇形的颜色;
  4. 饼状图要有阴影;
  5. 各个扇形要有一定的凸起。

实现

首先,针对需求我们进行一下分析,先从需求 2 看起,plt.pie() 方法提供了一个关键字参数 radius,通过这个参数可以指定饼状图的半径,但是这里只能传递一个浮点数,不能传递一个数组,也就是说不能单独指定每一个扇形的半径,如果传递一个容器类型,则会抛出 TypeError: 'radius' must be an instance of numbers.Number, not a list 错误。因此我们只得另辟蹊径,首先 plt.pie() 方法是有返回值的,一般情况下他会返回两个值,第一个是包含所有扇形 Artist 子实例的 Wedge 对象列表;第二个是包含所有扇形标签的 Text 对象列表;除此之外,如果 autopct 参数不为空,则会返回第三个值,从需求 1 和需求 2 来看,我们就需要前两个返回值即可,因此代码是 wedges, texts, *_ = plt.pie(...)。通过 Wedge 对象的 set_radius() 方法完成需求 2。这里提一嘴,由于我们设置了阴影,调用 Axes.patches 属性不光会获取饼状图所有的 Wedge 对象,也会获取所有的阴影 Shadow对象,当然我们可以进行过滤,但是实现起来多了一步,没那个必要。

需求 3、需求 4 和需求 5 非常简单,plt.pie() 方法本身提供了相关的关键字参数,只需要指定 shadow=Truecolor=colors[i]explode=explodes 就可以实现。真正的难点是需求 1,所以重点说一下,我们都知道 plt.pie() 方法提供了 labelslabeldistance 这两个参数,这两个参数可以控制每个标签和标签的位置,但是这样无法实现箭头功能,因此使用 plt.pie() 方法本身提供的能力是无法实现需求的。从需求 1 上来看,绘制要有注释和箭头,这两个名词放在一起我们应该非常敏感才对,这不就是典型的指向型注释嘛,因此我们需要使用 annotate 方法实现需求 1,知道了方法和目标,实现起来就很简单了,至此所有的需求都已经被实现了。

最后,整个程序的完整代码如下:

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))  # 设置绘图区域大小  
  
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()

画图结果如下:

【matplotlib】可视化实战——绘制凸起的饼状图_第1张图片

往期回顾

  1. 【matplotlib】可视化实战1——绘制带颜色带的折线图

文中难免会出现一些描述不当之处(尽管我已反复检查多次),欢迎在留言区指正,相关的知识点也可进行分享,希望大家都能有所收获!!如果觉得我的文章写得还行,不妨支持一下。你的每一个转发、关注、点赞、评论都是对我最大的支持!

你可能感兴趣的:(#,可视化实战,matplotlib,python,开发语言)