0%

使用Python + Matplotlib绘制双柱状图

demo

在实际工作中,发现上游软件组件(SWC)发送的 Mobileye 前向视觉数据存在丢帧情况,需要对丢帧情况进行统计量化,想到的方法是将实车录得的 LCM log 文件进行 x86 离线回放,x86 应用程序中通过 easylogging++打印关键信息(是否是一帧数据报文,以及数据报文中是否存在部分信息丢失)的 Flag 到日志文件中,通过统计日志文件中关键信息对应的 Flag 数量,计算数据丢帧率并绘制双柱状图。

环境依赖

  • windows 7, 8, 10
  • Python 3+

Linux 系统理论上也是可行的,但博主在 Ubuntu 上安装相关的 Python 依赖时遇到了问题,未作进一步的探究。

Python 依赖

通过pip包管理工具安装numpy matplotlib 这两个库依赖:

1
2
pip install numpy
pip install matplotlib

若安装过程因网络问题很难成功,可尝试更换至国内镜像源进行安装,如使用清华镜像源:

1
2
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple numpy
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple matplotlib

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
import os
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt


class GroupedBarChart(object):
def __init__(self):
self.path_current = os.path.dirname(__file__)
print(self.path_current)
self.path_logs = [
(self.path_current + "/" + i)
for i in os.listdir(self.path_current)
if (os.path.isfile(os.path.join(self.path_current, i))
and i.endswith('.txt'))
]
self.num_frames_total = 0
self.num_frames_lost = 0
self.list_valid_log_name = []
self.list_frame_lost_percent = []
self.list_frame_normal_percent = []
# 字体设置,若不将'family'设置为中文相关字体,则无法正常显示中文
self.font = {
'family': 'Microsoft YaHei',
'style': 'normal',
'weight': 'normal',
'size': 16
}
self.title = '标题'

def Parse(self):
for path_log in self.path_logs:
log_name = path_log.split('/')[-1]
log = open(path_log)
for line in log.readlines():
if 'Flag_DataFrame' in line:
self.num_frames_total += 1
elif 'Flag_FrameLost' in line:
self.num_frames_lost += 1
else:
pass

if self.num_frames_total is not 0:
self.list_valid_log_name.append(log_name.split('_')[-1].split('.')[0])
self.frame_lost_ratio = format(self.num_frames_lost / self.num_frames_total * 100, '.2f') if self.num_frames_total is not 0 else '#NA'
self.list_frame_lost_percent.append(float(self.frame_lost_ratio))
self.list_frame_normal_percent.append(100 - float(self.frame_lost_ratio))

print('\nlog file: {}'.format(log_name))
print('--------------------------------------------------------')
print('num_frames_total: {}'.format(self.num_frames_total))
print(' num_frames_lost: {}'.format(self.num_frames_lost))
print('frame_lost_ratio: {}%'.format(self.frame_lost_ratio))
print('--------------------------------------------------------\n')

self.num_frames_total = 0
self.num_frames_lost = 0

def PlotSet(self):
if len(self.list_valid_log_name) is not 0:
ind = np.arange(len(self.list_valid_log_name))
# bar的宽度
width = 0.35
self.fig, self.ax = plt.subplots()
# bar1
self.rects_frame_lost = self.ax.bar(
ind - width / 2,
self.list_frame_lost_percent,
width,
color="tomato",
label="label1")
# bar2
self.rects_frame_normal = self.ax.bar(
ind + width / 2,
self.list_frame_normal_percent,
width,
color="steelblue",
label="label2")
# 设置纵坐标标签
self.ax.set_ylabel('百分比 (%)', fontdict=self.font)
# 设置坐标轴刻度大小
plt.tick_params(labelsize=18)
# 设置标题
self.ax.set_title(self.title, fontdict=self.font)
# 设置横坐标刻度
self.ax.set_xticks(ind)
# 设置横坐标刻度标签
self.ax.set_xticklabels(self.list_valid_log_name, fontdict=self.font)
# 设置图例:位置,字体
self.ax.legend(loc='upper left', prop=self.font)
print('average_frame_lost_ratio: {}%'.format(round(np.mean(self.list_frame_lost_percent), 2)))

def AutoLabel(self):
"""
为每一个bar打上标注
"""
for rects in (self.rects_frame_lost, self.rects_frame_normal):
for rect in rects:
height = rect.get_height()
self.ax.text(
rect.get_x() + rect.get_width() / 2.,
height + 1,
'%.2f' % height,
ha='center',
va='bottom',
fontsize=12)


def main():
obj = GroupedBarChart()
obj.Parse()
obj.PlotSet()
obj.AutoLabel()

plt.show()


if __name__ == "__main__":
main()

运行上述 Python 代码,弹出 Figure 窗口,适当调整格式,调整并保存统计结果,如文首所示。点击这里下载完整的工程 demo。

后记

本文中使用 matplotlib 绘制双柱状图的 demo 具体结合了博主工作中的应用场景,更简洁纯粹的代码示例请查看 matplotlib 官网上的样例Grouped bar chart with labels,官网上还给出了 matplotlib 所有绘图的example以及详细的tutorial

本文中 bar 的颜色分别是番茄红tomato和钢铁蓝steelblue,更多的颜色示例可以到这里选择。


Thank you for your donate!