前述文章里,我们已经探索了如何画直方图,以及如何设置图例、颜色等。具体可通过下述链接找到:
https://mp.csdn.net/mp_blog/creation/editor/141830709
https://mp.csdn.net/mp_blog/creation/editor/141894225
本期文章,我们继续探索: 堆叠直方图
直方图堆叠是常见的数据表达方式,有助于大家表达两种及以上类别的累积影响。
在python中绘制直方图,需要在常规的坐标轴上,增加设置底座直方图(地基)和叠加多层(建楼)两个操作。
打开官网https://matplotlib.org/stable/gallery/lines_bars_and_markers/index.html
我们看到Bar Label Demo和Stacked bar chart模块都显示了堆叠直方图。

图1
分别点进 Bar Label Demo和Stacked bar chart模块,发现后者是前者的一部分,但前者内容更多,因此先打开Stacked bar chart。由此进入学习模式。
代码前两行,引入计算模块numpy用于数值运算,画图模块matplotlib用于绘图。
import matplotlib.pyplot as plt #引入matplotlib模块用于绘图 import numpy as np #引入numpy模块用于数值计算
之后开始定义直方图的类别:
species = ( #定义species数组,作为直方图的类别
"Adelie\n $\\mu=$3700.66g",
"Chinstrap\n $\\mu=$3733.09g",
"Gentoo\n $\\mu=5076.02g$",
)
之后定义直方图各类别对应数值:
weight_counts = { #定义weight_counts数组,这个数组包括两个子数组,直方图叠加依据这两组数
"Below": np.array([70, 31, 58]), #直方图第一层的依据数据
"Above": np.array([82, 37, 66]), #直方图第二层的依据数据
}
然后定义了图形的基本属性:
width = 0.5 #定义width常数,用于设置直方图间距 fig, ax = plt.subplots() #定义一个带坐标轴的图,坐标轴属性用ax控制
实际上width=0.5出现略早,因为图形还没开始定义,上述代码交换一下位置更合适。不过当前这种先后顺序不会影响实际输出效果,所以无需深究。
之后定义了bottom = np.zeros(3) ,定义了一个1X3的全0矩阵。
bottom = np.zeros(3) #定义1X3的全0矩阵
在后续运行中将会发现,叠加矩阵的第一层需要设置是从y=0开始画方块。
也即,堆叠直方图需要明确“地基”起点。
此后定义了画图函数,使用for循环反复输出:
for boolean, weight_count in weight_counts.items(): #for函数用于遍历weight_counts内部分布尔型数组 p = ax.bar(species, weight_count, width, label=boolean, bottom=bottom) #以species为类别,weight_count为数值, width为不同方块间距, label=boolean图例为boolean, bottom=bottom为方块底部对应Y值 bottom += weight_count #用bottom+weight_count赋值旧的bottom,即bottom =bottom+weight_count,新的bottom是新的一轮直方图起点
这里需要注意的是:bottom += weight_count。
它代表的意思是,上一轮直方图行绘制完毕,其顶部对应y值,应该是下一轮直方图绘制的起点。
这里需要注意的是这是实现堆叠的根本原因。
最后:设置了图名、图例名,并要求输出了图形。
ax.set_title("Number of penguins with above average body mass") #设置图名
ax.legend(loc="upper right") #设置图例名
plt.show() #输出图形

图2
官网代码绘制出了两层堆叠图,我们尝试绘制三层,将weight_counts部分增加一个数组,改后为:
weight_counts = { #定义weight_counts数组,这个数组包括两个子数组,直方图叠加依据这两组数
"Below": np.array([70, 31, 58]),
"Above": np.array([82, 37, 66]),
"add": np.array([90, 70, 80]), #新增对叠层
}
此时的输出图形如下:
图3
完整代码为;
import matplotlib.pyplot as plt #引入matplotlib模块用于绘图
import numpy as np #引入numpy模块用于数值计算
# data from https://allisonhorst.github.io/palmerpenguins/
species = ( #定义species数组,作为直方图的类别
"Adelie\n $\\mu=$3700.66g",
"Chinstrap\n $\\mu=$3733.09g",
"Gentoo\n $\\mu=5076.02g$",
)
weight_counts = { #定义weight_counts数组,这个数组包括两个子数组,直方图叠加依据这两组数
"Below": np.array([70, 31, 58]),
"Above": np.array([82, 37, 66]),
"Add": np.array([70, 90, 80]), #新增对叠层
}
width = 0.5 #定义width常数,用于设置直方图间距
fig, ax = plt.subplots() #定义一个带坐标轴的图,坐标轴属性用ax控制
bottom = np.zeros(3) #定义1X3的全0矩阵
for boolean, weight_count in weight_counts.items(): #for函数用于遍历weight_counts内部分布尔型数组
p = ax.bar(species, weight_count, width, label=boolean, bottom=bottom) #以species为类别,weight_count为数值, width为不同方块间距, label=boolean图例为boolean, bottom=bottom为方块底部对应Y值
bottom += weight_count #用bottom+weight_count赋值旧的bottom,即bottom =bottom+weight_count
ax.set_title("Number of penguins with above average body mass") #设置图名
ax.legend(loc="upper right") #设置图例名
plt.show() #输出图形
各队叠层如果只是图形,虽然直观,但是各部分实际数据如果能一同体现则更好。
直方图是以类别区分,以数据作为画图高度,因此把数据作为标签显示出来即可。
在for循环中增加一行:
ax.bar_label(p, label_type='center') #将各部分数据作为标签输出,至于方块图中间
输出图形为:

图4
由图4可见,各部分数据已经显示。
完整代码如下:
import matplotlib.pyplot as plt #引入matplotlib模块用于绘图
import numpy as np #引入numpy模块用于数值计算
# data from https://allisonhorst.github.io/palmerpenguins/
species = ( #定义species数组,作为直方图的类别
"Adelie\n $\\mu=$3700.66g",
"Chinstrap\n $\\mu=$3733.09g",
"Gentoo\n $\\mu=5076.02g$",
)
weight_counts = { #定义weight_counts数组,这个数组包括两个子数组,直方图叠加依据这两组数
"Below": np.array([70, 31, 58]),
"Above": np.array([82, 37, 66]),
"Add": np.array([70, 90, 80]), #新增对叠层
}
width = 0.5 #定义width常数,用于设置直方图间距
fig, ax = plt.subplots() #定义一个带坐标轴的图,坐标轴属性用ax控制
bottom = np.zeros(3) #定义1X3的全0矩阵
for boolean, weight_count in weight_counts.items(): #for函数用于遍历weight_counts内部分布尔型数组
p = ax.bar(species, weight_count, width, label=boolean, bottom=bottom) #以species为类别,weight_count为数值, width为不同方块间距, label=boolean图例为boolean, bottom=bottom为方块底部对应Y值
bottom += weight_count #用bottom+weight_count赋值旧的bottom,即bottom =bottom+weight_count
ax.bar_label(p, label_type='center') #将各部分数据作为标签输出,至于方块图中间
ax.set_title("Number of penguins with above average body mass") #设置图名
ax.legend(loc="upper right") #设置图例名
plt.show() #输出图形
本文学习堆叠直方图的画法,包括使用for循环使用对叠层的设置、层数变化和各对叠层数据显示。