柱状图标注问题
前言
很多时候我们画柱状图都是光秃秃的几个柱体,缺少相应的标注会让我们的可视化效果变差许多,例如下图所示,所以为了更好的可视化效果,我们需要对柱状图进行标注。
错误的无标注柱状图:
解决方案一
如果你的matplotlib库版本为3.4.1,那么pyplot库会自带一个方法bar_label,它的函数原型如下:
bar_label(container,labels = None,fmt = '%g',label_type = 'edge',padding = 0,**kwargs)
参数说明:
参数1:container:指定包含所有柱状图和错误条形图的容器,基本从bar函数或者barh函数返回
参数2:labels:指定应显示的标签文本列表。如果未给出,则标签文本将是使用fmt格式化的数据值
参数3:fmt:字符型,指定标签的格式字符串
参数4:label_type:指定标签的类型,{'edge','center'}
edge:标签放置在柱体的端点,显示的值将是该端点的位置
center:标签位于柱体的中心,显示的值将是该段的长度
参数5:padding:浮点型,指定标签到柱状图末端的距离
参数6: **kwargs:其余关键字参数都会传递给Axes.annotate
返回值:包含Text实例的列表
参数详解:
1.fmt参数格式跟其他字符串显示格式是一致的。
2.container参数不一定是bar函数的返回值,他可以是所有Patch类的子类实例
3.4.1版本标注程序如下:
#添加标签等函数
def label(ax):
ax.set_xlabel('X', fontsize=15)
ax.set_ylabel('Y', fontsize=15)
ax.legend(loc='best')
figure = plt.figure(figsize=(8, 6))
ax1 = figure.add_subplot(2, 1, 1)
ax2 = figure.add_subplot(2, 1, 2)
#初始化数据
x = np.random.randint(0, 10, 10)
#画图1label_type='center'
Rectangle1 = ax1.bar(range(10), x, width=0.8, label='有标注,label_type=center')
ax1.bar_label(Rectangle1, label_type='center') #进行标注
label(ax1)
ax1.set_title('bar画图', fontsize=25)
#画图2label_type='edge'
Rectangle2 = ax2.bar(range(10), x, width=0.8, label='有标注,label_type=edge')
ax2.bar_label(Rectangle2, label_type='edge') #进行标注
label(ax2)
plt.show()
画图结果如下:
从上图我们可以看出对于单一的柱状图,label_type参数没有多大实质影响,知识简单的改变了标注的位置。label_type参数真正的影响在于叠加柱状图时对两种不同的柱状图进行标注。一个简单的示例如下:
#初始化数据
N = 5
Y1 = np.random.randint(0, 20, N)
Y2 = np.random.randint(0, 20, N)
fig, ax = plt.subplots()
#绘制叠加柱状图
p1 = ax.bar(range(N), Y1, width=0.6, label='Y1')
p2 = ax.bar(range(N), Y2, width=0.6, bottom=Y1, label='Y2')
#设置标签等
ax.set_ylabel('Y', fontsize=15)
ax.set_xlabel('X', fontsize=15)
ax.set_title('叠加柱状图', fontsize=25)
ax.legend() #打开图例
#使用bar_label方法对柱状图进行标注,默认是在顶端进行标注
ax.bar_label(p1, label_type='center', fontsize=13) #label_type='center'
ax.bar_label(p2, label_type='center', fontsize=13) #label_type='center'
ax.bar_label(p2, fontsize=13) #label_type='edge'
plt.show()
画图结果如下:
从上图可以看到柱体中心的数字代表该柱体的高度,柱体顶端的数字代表两个柱体加在一起的高度,即定点的高度。这样我们就完成了两个叠加柱状图的标注。
!!!!bar_label方法不光可以标注柱状图还可以标注直方图等返回值具有patches属性的图
解决方案二
如果matplotlib库版本较低,pyplot并不支持bar_label方法,那么只能使用自定义的添加函数进行柱状图标注了,使用annotate方法进行标注。具体程序如下:
def autolabel(self, rects):
"""
自动标定柱状图柱体高度
rects:要进行标定的Rectangle类列表
"""
for rect in rects:
height = rect.get_height()
self.fig1.axes.annotate(format(height, '.2f'),
xy=(rect.get_x() +
rect.get_width() / 2, height),
xytext=(0, 2), # 垂直偏移两格
textcoords="offset points",
ha='center',
va='bottom')
self.fig1.draw()
单柱状图画图结果如下:
叠加柱状图画图结果如下:
由上两图可知,单一的柱状图标注使用该函数没有什么问题,但是叠加柱状图就出现了很大的问题,其原因在于
height = rect.get_height()
这句话,标注位置的高度使用的是柱体的高度而不是柱体顶点的值,那么对于叠加柱状图中的bottom参数则无法很好的响应,故而对叠加柱状图进行标注的效果很糟糕。
总结
如果能更新matplotlib库,那么最好更新到3.4.1使用库自带方法进行标注,比自建函数要好上不少。但是旧版本可以通过添加参数或修改函数逻辑的方法增加其适用范围,作为备选方法是可行的。