01 带饼图的散点图
有这样一个例子:假设有五个人,每个人的月均收入水平为a=[1,3,2,4,3],消费水平b=[2,1,3,3,5],数据单位均有千元。同时五个人消费水平中,按照每月衣食住行的消费比例为:
s1=[0.1,0.2,0.3,0.4]
s2=[0.35,0.35,0.2,0.1]
s3=[0.2,0.25,0.25,0.3]
s4=[0.5,0.1,0.15,0.25]
s5=[0.0,0.25,0.4,0.35]
依据上述数据(数据纯属虚构),我可以将这些数据画在一个图形里,如图:(其中,蓝色:衣;黄色:食;红色:住;绿色:行)
这个图形就是带饼图的散点图,从图中不仅可以看出五个人的消费与收入的关系趋势,也可以看出每个人的衣食住行消费比例不同。
是不是很有趣的一个图形?它是怎么做出来的?
02 matplotlib中marker参数的一个隐藏功能
上图是用python中matplotlib包绘制的,而绘制成带饼图的散点图则是用了里边关键的marker参数,所以在介绍如何绘制此图之前,先说说marker参数的一个隐藏功能。
一般的我们绘制散点图基本的命令为:
import matplotlib.pyplot as plt
plt.scatter(x, y, s=20, c=None, marker='o')
其中,s是点的大小,c是颜色,marker就是指定点标记的形状,在这里用的就是小圆点o;我们还可以用“*”、“x”、“Δ”等等,甚至还有数字、字母所代表的形状。
03 单个带饼图的散点图绘制过程
但是,完全绘制成上述那个图形也并非那么容易,下面我们从一个带饼图的散点绘制讲起。
比如上面的a=1,b=2那个点的消费比例为:s1=[0.1,0.2,0.3,0.4],代码如下:
x = [0] + np.cos(np.linspace(0, 2 * np.pi * 0.1, 5)).tolist()#[0]表示x的初始值
y = [0] + np.sin(np.linspace(0, 2 * np.pi * 0.1, 5)).tolist() #用tolist()形成数列
xy1 = list(zip(x, y))
x = [0] + np.cos(np.linspace(2 * np.pi * 0.1, 2 * np.pi * 0.3, 5)).tolist()
y = [0] + np.sin(np.linspace(2 * np.pi * 0.1, 2 * np.pi * 0.3, 5)).tolist()
xy2 = list(zip(x, y))
x = [0] + np.cos(np.linspace(2 * np.pi * 0.3, 2 * np.pi* 0.6, 5)).tolist()
y = [0] + np.sin(np.linspace(2 * np.pi * 0.3, 2 * np.pi* 0.6, 5)).tolist()
xy3 = list(zip(x, y))
x = [0] + np.cos(np.linspace(2 * np.pi * 0.6, 2 * np.pi*1, 5)).tolist()
y = [0] + np.sin(np.linspace(2 * np.pi * 0.6, 2 * np.pi*1, 5)).tolist()
xy4 = list(zip(x, y))
fig, ax = plt.subplots()
ax.scatter(a[0], b[0], marker=(xy1),
s=500,facecolor='blue')
ax.scatter(a[0], b[0], marker=(xy2),
s=500,facecolor='y')
ax.scatter(a[0], b[0], marker=(xy3),
s=500,facecolor='red')
ax.scatter(a[0], b[0], marker=(xy4),
s=500,facecolor='green') #为了饼图看得清,散点的size要大一些
plt.show()
得到结果就是:首先讲讲x、y变量的生成,其原理是先根据每个占比数值所形成的角度(乘以2π,如2 * np.pi * 0.1),然后再用np.linspace函数五等分形成6个角度值,每个值赋予cos、sin函数,这是因为cos2θ+sin2θ=1,所有经过cos、sin函数的值会自动形成一个圆形。
值得注意的是,因为四个占比要围成一个圆形,所以除了第一个占比外,后边的都要用累计占比,如第二个0.2的占比np.linspace(2 * np.pi * 0.1, 2 * np.pi * 0.3, 5),第三个0.3的就是0.3-0.6之间,第四个是0.6-1之间。
如果还没明白那就单独把一个x、y生成的变量,单独作图可以看一下:
x = [0] + np.cos(np.linspace(0, 2 * np.pi * 0.1, 5)).tolist()
y = [0] + np.sin(np.linspace(0, 2 * np.pi * 0.1, 5)).tolist()
plt.plot(x,y,c='b')
plt.show()
可以看出,第一个占比x、y的轨迹就是一个弧形,然后再用初始值(0,0)牵引着,这样再对这个轨迹进行填充时,就会形成一个扇形,如下:
plt.scatter(a[0], b[0], marker=(xy1),
s=500,facecolor='blue')
plt.show()
这样一个x、y所形成的marker=(xy1)标记,再用facecolor='blue'填充就会形成一个扇形散点标记。最后用fig, ax = plt.subplots()把xy2、xy3、xy4所有子图都放上去,就形成一个圆形,然后用不同颜色填充,就形成一个饼图,每个饼图的角度大小由其占比比例决定。
04 所有点的饼图-散点图
上边是一个点的饼图-散点图,若是将a=[1,3,2,4,3],b=[2,1,3,3,5],以及b的所有个体衣食住行的消费比例全放进去,那就需要用到while、for循环条件,代码如下:
#5个消费水平下衣食住行的占比
s1=[0.1,0.2,0.3,0.4]
s2=[0.35,0.35,0.2,0.1]
s3=[0.2,0.25,0.25,0.3]
s4=[0.5,0.1,0.15,0.25]
s5=[0.0,0.25,0.4,0.35]
#计算累计占比
ss1=[s1[0],sum(s1[0:2]),sum(s1[0:3]),sum(s1[0:4])]
ss2=[s2[0],sum(s2[0:2]),sum(s2[0:3]),sum(s2[0:4])]
ss3=[s3[0],sum(s3[0:2]),sum(s3[0:3]),sum(s3[0:4])]
ss4=[s4[0],sum(s4[0:2]),sum(s4[0:3]),sum(s4[0:4])]
ss5=[s5[0],sum(s5[0:2]),sum(s5[0:3]),sum(s5[0:4])]
s=[ss1,ss2,ss3,ss4,ss5]
a=[1,3,2,4,3] #收入水平(千元)
b=[2,1,3,3,5] #消费水平(千元)
fig, ax = plt.subplots(figsize=(10,6))
i=0
while i<len(b):
x = [0] + np.cos(np.linspace(0, 2 * np.pi * s[i][0], 15)).tolist()
y = [0] + np.sin(np.linspace(0, 2 * np.pi * s[i][0], 15)).tolist()
xy1 = list(zip(x, y))
x = [0] + np.cos(np.linspace(2 * np.pi * s[i][0], 2 * np.pi * s[i][1], 15)).tolist()
y = [0] + np.sin(np.linspace(2 * np.pi * s[i][0], 2 * np.pi * s[i][1], 15)).tolist()
xy2 = list(zip(x, y))
x = [0] + np.cos(np.linspace(2 * np.pi * s[i][1],
2 * np.pi* s[i][2], 15)).tolist()
y = [0] + np.sin(np.linspace(2 * np.pi * s[i][1],
2 * np.pi* s[i][2], 15)).tolist()
xy3 = list(zip(x, y))
x = [0] + np.cos(np.linspace(2 * np.pi * s[i][2],
2 * np.pi*1, 15)).tolist()
y = [0] + np.sin(np.linspace(2 * np.pi * s[i][2],
2 * np.pi*1, 15)).tolist()
xy4 = list(zip(x, y))
xy=[xy1,xy2,xy3,xy4]
c=['b','y','r','g']
for j in range(4):
ax.scatter(a[i], b[i], marker=(xy[j]),
s=800,facecolor=c[j])
i=i+1
plt.show()
最终得到本文前边那个图形。
另外还需说明一下,这个图形只适用于小样本数据,也就是图形三点的个数不能太多,每个点中比例数量也不能太多,否则影响展示效果。
写作不易,特别是技术类的写作,请大家多多支持,关注、点赞、转发等等,也欢迎大家关注知乎爬虫与数据分析专栏:https://zhuanlan.zhihu.com/zjying2000。