在本系列的上篇文章里,我们从Matplotlib的基础可视化框架开始,逐步画出折线图、柱状图等基础图表,通过对坐标轴标签、标题文本等的精细调节画出信息更明确丰富的可视图,也实践了双轴图及子图,最后看了下极坐标系下绘图的效果。本篇继续探索Matplotlib的强悍可视化能力。
Matplotlib动态可视化
计算机及通信技术的发展极大丰富了多媒体内容的发展,文不如图、图不如动图;BI近些年也逐渐发展,人们已不满足于看静态的图表。短视频的火热也给了动态图更多的发展空间。动态图和交互图表能更生动地表现数据变化及数据联系,传达更多的信息。
插入排序的动态展现
生动的动画有助于我们理解算法。通过Matplotlib其实我们也可以绘制动态的算法关键过程,下面拿插入排序作为例子看Matplotlib如何绘制动态图。
玩扑克时的抓牌环节很契合插入排序的执行过程。其思路是:保持手中的已有的牌始终有序,当抓到一张新牌时,按照牌面的点数,将其插入合适的位置。怎么去判断该插入的位置呢?我们通常的做法就是从左到右或从右到左扫描以找到当前牌的位置,初始化时我们可以新建一个数组作为始终有序的结果集,也可以直接用原来的数组空间进行交换操作,整体时间复杂度是O(n^2)。将这一过程翻译为Python代码如下:
def isort(lst):
n=len(lst) #直接用原数组进行排序
for i in range(1,n):
x=lst[i] #当前值
j=i-1
while j>=0 and x<lst[j]: #从右往左找插入的位置
lst[j+1]=lst[j] #将比x大的牌往后移一位
j-=1
lst[j+1]=x #换牌
return lst

为了直观展示插入排序的关键步骤,我们将每做一次插入的结果保存下来然后用Matplotlib画成一系列柱状图。通过matplotlib.animation
绘制成动态图。
首先改一下排序函数,增加一个变量保存每次到插入步骤时的数组,因为不是递归的排序代码,在for循环前用一个变量w保存关键结果,基于这些中间结果花一系列的图,再连成动态GIF图,代码如下,关键步骤都有注释。
def isort(lst): #插入排序代码
n=len(lst)
w={
0:{
'v':lst.copy(),'j':-1}} #保存j以确定到哪里插入
for i in range(1,n):
x=lst[i] #当前值
j=i-1
while j>=0 and x<lst[j]: #x比j处值小时,继续向左
lst[j+1]=lst[j] #将比x大的牌往后移一位
j-=1
lst[j+1]=x #换牌
w[i]={
'v':lst.copy(),'j':j}
#print(xs,i,j,x)
return w #不需要lst
import matplotlib.animation as anm #引入接口
fig,ax=plt.subplots()
def draw_bar(i): #每传入一个i画一个柱状图
w=wk[i]
nw=len(w['v'])
ax.clear() #清空之前画的元素
c1=[]
for j in range(nw): #调节柱的颜色
if j<i:
c1.append('#1EAFAE')
elif i==nw-1:
c1.append('#1EAFAE')
elif j==i:
c1.append('#BA5C25')
else:
c1.append('#69FFFF')
if i!=nw-1 and w['j']+1!=i: #所交换的位置
c1[w['j']+1]='#FFA069'
rs=ax.bar(range(nw),w['v'],color=c1)
ax.set_ylim(0,8)
ax.set_title('Insert Sorted Animation')
c=0
for r in rs: #给每个柱加文本标签
ax.annotate('{0}'.format(w['v'][c]),xy=(r.get_x()+r.get_width()/2,r.get_height()+0.1))
c+=1
#绘制动图
amt=anm.FuncAnimation(fig,draw_bar,frames=range(6),interval=600)
amt.save('insert-sorted-animation-1.gif')
拿一个未排序数组进行测试,效果如下:

排序过程动图(其中青色表示已排序元素,淡蓝色表示未排序,枣红色柱表示当前需排序元素,插入到橙色柱位置)
Matplotlib绘制动态图表的思路是将一系列图按一定时间间隔顺序播放,利用眼睛的视觉暂留形成动态感,每张静态图就是一帧。上面的代码看上去有些长,但大部分语句用来调颜色和标签文本,画图部分仍然是熟悉的fig,ax=plt.subplots()
建画布、ax.bar()
画柱状图、ax.set_title()
设置标题、ax.annotate()
在每个柱的合适位置加文本标签。Matplotlib将动图相关的接口封装在matplotlib.animation
里,FuncAnimation(fig,func,frames)
通过重复调用func里的画图函数在fig