堆积图常用于综合展示不同分类的指标趋势以及它们的总和的趋势。比如说,我们想看一下过去二十年来中国人口总量的变化趋势,同时,我们又想看一下男、女性人口各自的变化趋势,甚至我们还想看一下它们各自占比的变化趋势,这时,我们就可以用堆积图来更高效、更简洁地展示出来。
欢迎大家关注我的个人博客【数洞】 【备用站】
我们举这样一个例子,有一个班里有20名学生,它们的编号分别是0-19,y1、y2、y3分别代表本次月考他们的语文、数学和英语的成绩,我们想观察这些学生的总成绩以及各科成绩的情况。
1. 堆积柱状图
首先,我们使用堆积柱状图来达到我们的目的:
import matplotlib.pyplot as plt
import numpy as np
# 生成数据
x = np.linspace(0, 20, 20)
y1 = np.random.randint(50, 100, 20)
y2 = np.random.randint(50, 100, 20)
y3 = np.random.randint(50, 100, 20)
# 堆积柱状图
plt.bar(x, y1, color='r', label='语文')
plt.bar(x, y2, bottom=y1, color='g', label='数学')
plt.bar(x, y3, bottom=y1+y2, color='c', label='英语')
# 显示范围
plt.xlim(-2, 22)
plt.ylim(0, 280)
# 添加图例
plt.legend(loc='upper right')
plt.grid(axis='y', color='gray', linestyle=':', linewidth=2)
plt.show()
可以看到,有四位同学的总成绩高于250分,还有些同学严重偏科,另外有一个同学平均下来在及格线下方……大家不同太为他担心,因为这些都是随机生成的数据。
我们还可以将柱子横过来:
import matplotlib.pyplot as plt
import numpy as np
# 生成数据
x = np.linspace(0, 20, 20)
y1 = np.random.randint(50, 100, 20)
y2 = np.random.randint(50, 100, 20)
y3 = np.random.randint(50, 100, 20)
# 堆积柱状图
plt.barh(x, y1, color='r', label='语文')
plt.barh(x, y2, left=y1, color='g', label='数学')
plt.barh(x, y3, left=y1+y2, color='c', label='英语')
# 显示范围
plt.ylim(-2, 22)
plt.xlim(0, 300)
# 添加图例
plt.legend(loc='lower right')
plt.show()
我们需要将bottom参数的名字改成left,这样更符合我们的视觉认知,其他参数上没有什么分别。
2. 堆积折线图
这次,我们假设小明参加了20次月考,我们想看下他的总成绩以及语数外三科成绩的变化趋势。
import matplotlib.pyplot as plt
import numpy as np
# 生成数据
# 假设一个班里有20名学生,x代表他们的编号,y1/y2/y3分别是他们本次月考的成绩。
x = np.linspace(0, 20, 20)
y1 = np.random.randint(50, 100, 20)
y2 = np.random.randint(50, 100, 20)
y3 = np.random.randint(50, 100, 20)
# 堆积柱状图
plt.stackplot(x, y1, y2, y3, baseline='zero', labels=['语文', '数学', '英语'], colors=['r', 'g', 'c'])
# 显示范围
plt.xlim(-2, 22)
plt.ylim(0, 300)
# 添加图例和网格线
plt.legend(loc='upper right')
plt.grid(axis='y', color='gray', linestyle=':', linewidth=2)
plt.show()
嗯……小明的成绩太不稳定了,不过还好,平均成绩还没到过及格线以下。从这张图里边,我们看不到明显的上升或者下降的趋势。
这样我们看到了成绩的变化趋势,但是我们不能清楚地分辨小明哪科成绩更好,哪科成绩是短板,因此我们需要看一下小明的总成绩中各科成绩占比的变化趋势。
import matplotlib.pyplot as plt
import numpy as np
# 生成数据
# 假设一个班里有20名学生,x代表他们的编号,y1/y2/y3分别是他们本次月考的成绩。
x = np.linspace(0, 20, 20)
y1 = np.random.randint(50, 100, 20)
y2 = np.random.randint(50, 100, 20)
y3 = np.random.randint(50, 100, 20)
# 计算百分比
y1p = y1 / (y1 + y2 + y3)
y2p = y2 / (y1 + y2 + y3)
y3p = y3 / (y1 + y2 + y3)
# 比例堆积柱状图
plt.stackplot(x, y1p, y2p, y3p, baseline='zero', labels=['语文', '数学', '英语'], colors=['r', 'g', 'c'])
# 显示范围
plt.xlim(0, 20)
plt.ylim(0, 1)
# 添加图例
plt.legend(loc='upper right')
plt.grid(axis='y', color='gray', linestyle=':', linewidth=2)
plt.show()
由于这里各科的成绩都是我们随机生成的,所以我们从图中并不能看出来小明的强弱势科目,但这种表现方式非常实用。比如我们要分析用户结构的变化趋势、分析内容类型分布的趋势等。这种图形相当于在饼图的基础上增加了时间序列的维度,将多个饼图拉伸开来,连接到一起。
今天我们展示了如何绘制堆积柱状图和堆积折线图(面积图),之后这一系列文章每一期会专门针对一个点来进行分享,确保每次大家能用十来分钟就学会一项新的实用技能,这样才不负咱们“功利主义”的“美名”。