今天,梁先国网络科技网带大家来尝试通过python绘制动态气泡图,复制粘贴程序,一键出图。
STEP 1 数据准备
按照下图格式建立待读取的Excel文件:每一工作表包含一个维度的相应数据,例如,下表展示的为不同省份、年份对应的申请量数据:

不同省份、年份对应的生产总值数据:
不同工作表中,年份或地区的顺序可以存在不同,当展示的为地区数据时,是否有“省”、“市”的后缀并不影响程序的读取。
STEP 2 适应性修改一键出图
下载ImageMagick软件(百度网盘链接:https://pan.baidu.com/s/1mWZHh-EiTcYKp5RTMJ0CRw,密码:6fnr),用于帮助我们生成gif动图,安装完成后,请记住安装路径。
程序及相关配置文件链接:https://pan.baidu.com/s/1LOo0SYBf5VtXyP4P5k1mSQ ,密码:aegt。
将源程序,配置文件(matplotlibrc),以及需要可视化的数据复制到同一文件夹内,使用spyder打开配置文件,修改最后一行:填写ImageMagick安装路径,并删注释井号,
在下文程序说明中第二部分,涉及Excel读取中,适应性修改待读取的Excel文件名和工作表名称(修改方式如作图详解 |如何利用Python绘制技术功效图的方法(实战作图详解))
使用“Excute in an external system terminal”的方式运行程序,运行后,程序会自动在当前文件夹下生成以横纵坐标为名字的gif文件。
如果需要暂停或者恢复播放动画,按键盘上的空格键即可。
程序说明
程序共分为五个部分。
第一部分,导入所需要的包:
# -*- coding: utf-8 -*-
importmatplotlib.pyplot asplt
importnumpy as np
importmatplotlib.animation
importmatplotlib.patches asmpatches
importpandas as pd
importsys
第二部分,读入excel文件:
用户可根据实际需求修改此处的代码,以读取相应的sheet。根据实际需求,可以修改x轴数据,y轴数据,排序依据(即气泡大小表征的数据),以及显示多少个地区的标签。
#读入excel文件,根据实际需求修改文件名称和sheet名称
x_name='专利有效量'
y_name='技术市场成交额(亿元)'
sorted_by='申请量'
areas_to_show=10
df=pd.read_excel('分省年度数据GDP_最新.xls',sheetname=sorted_by,index_col='地区')
df1=pd.read_excel('分省年度数据GDP_最新.xls',sheetname=y_name,index_col='地区')
df2=pd.read_excel('分省年度数据GDP_最新.xls',sheetname=x_name,index_col='地区')
第三部分,处理输入数据:
在输入的地区数据中,可能只对排名靠前的几个地区感兴趣,这段代码涉及对各个地区的申请量进行排序挑选出前10名。输入的excel中有多个工作表,不能保证每个工作表的排序都是一致的,代码还涉及自动按照申请量排序后整理各个工作表的数据。
#对输入数据按照指定的维度排序
data_temp=[]
fori in df.index:
data_temp.append(df.loc[i].sum())
df_merge=pd.DataFrame(index=df.index,columns=['sum'],data=data_temp)
df_joined=df.join(df_merge)
df_top10=df_joined.sort_values(by='sum',ascending=False).head(areas_to_show)
df_top10=df_top10.drop('sum',1)
drop_list=[]
fori in df1.index:
if i[:2] in df_top10.index:
pass
else:
drop_list.append(i)
df1_temp=df1.drop(drop_list,0)
index_list=[]
fori in df_top10.index:
for j in df1_temp.index:
if j[:2]== i[:2]:
index_list.append(j)
else:
pass
df1_temp=df1_temp.ix[index_list,:]
drop_list=[]
fori in df2.index:
if i[:2] in df_top10.index:
pass
else:
drop_list.append(i)
df2_temp=df2.drop(drop_list,0)
index_list=[]
fori in df_top10.index:
for j in df2_temp.index:
if j[:2]== i[:2]:
index_list.append(j)
else:
pass
df2_temp=df2_temp.ix[index_list,:]
第四部分,动画:
完成每一帧动画的更新,具体操作为从数据源中提取下一年的新数据,用新数据更新气泡大小和位置,同时更新相应的年份文本标签。
#动画函数
defanimate(i):
globalx,y,ax,s1,scale,t1,df,df1,df2,colors_list,key_flag,index_flag,df2_temp,df1_temp,text_list
if key_flag:
return
if index_flag==0:
t1.set_text(df.columns[-1])
scale=3*np.sqrt(df[df.columns[-1]])
x=df2[df2.columns[-1]]
y=df1[df1.columns[-1]]
offsets=[]
for a,b in zip(x,y):
offsets.append((a,b))
s1.set_offsets(offsets)
s1.set_sizes(scale*2)
s1.set_color(colors_list)
for i in text_list:
i.set_position((df2_temp.loc[i.get_text()][df2_temp.columns[len(df2_temp.columns)-index_flag-1]],df1_temp.loc[[j for j in df1_temp.index if i.get_text() inj][0]][df1_temp.columns[len(df1_temp.columns)-index_flag-1]]))
index_flag+=1
return
scale=3*np.sqrt(df[df.columns[len(df.columns)-index_flag-1]])
x=df2[df2.columns[len(df.columns)-index_flag-1]]
y=df1[df1.columns[len(df.columns)-index_flag-1]]
offsets=[]
for a,b in zip(x,y):
offsets.append((a,b))
s1.set_offsets(offsets)
s1.set_sizes(scale*2)
t1.set_text(df.columns[len(df.columns)-index_flag-1])
for i in text_list:
i.set_position((df2_temp.loc[i.get_text()][df2_temp.columns[len(df2_temp.columns)-index_flag-1]],df1_temp.loc[[j for j in df1_temp.index if i.get_text() inj][0]][df1_temp.columns[len(df1_temp.columns)-index_flag-1]]))
if index_flag < 9:
index_flag+=1
else:
index_flag=0
第五部分,主体程序:
主要完成画布的初始化,动画的初始化,以及控制绘图和保存生成的gif动图。
#主体程序,初始化绘图,动画设定,输出设置等
fig=plt.figure(figsize=(12,7))
ax=fig.add_subplot(111)
fig.canvas.mpl_connect('key_press_event',press)
scale=3*np.sqrt(df[df.columns[-1]])
x=df2[df2.columns[-1]]
y=df1[df1.columns[-1]]
colors_list=[]
forindex in df.index:
for i in provinces_four_parts:
for j inprovinces_four_parts[i]:
for k in j:
if index in k:
colors_list.append(j[k])
s1=ax.scatter(x, y, c=colors_list,s=scale*2,
alpha=0.5)
ax.set_ylim(0,1.0*max(df1.max()))
ax.set_xlim(0,0.7*max(df2.max()))
ax.grid()
ax.legend(handles=[mpatches.Patch(color=colors_list[i],alpha=0.5,label=df.index[i]) fori inrange(len(df.index))],bbox_to_anchor=(1.1, 1),borderaxespad=0.)
ax.set_title('2007-2016各省市'+x_name+'和'+y_name+'关系',size=20)
ax.set_xlabel(x_name,size=20)
ax.set_ylabel(y_name,size=20)
t1=ax.text(0.05*max(df2.max()),0.85*max(df1.max()),df.columns[-1],size=40)
text_list=[]
fora,b inzip(df2_temp.index,df1_temp.index):
t2=ax.text(df2_temp.loc[a]['2007年'],df1_temp.loc[b]['2007年'],a,size=15,horizontalalignment='center',verticalalignment='center')
text_list.append(t2)
ani =matplotlib.animation.FuncAnimation(fig, animate, init_func=init_animation,frames=10,interval=1000)
ani.save(x_name+'VS'+y_name+'.gif', writer='imagemagick',fps=2)
plt.show()