超動感,百行Python代碼制作動態(tài)氣泡圖
先上圖片:

再上視頻:
最后上代碼:
import?numpy?as?np?
import?pandas?as?pd?
from?matplotlib?import?pyplot?as?plt?
import?matplotlib.animation?as??animation?
import?imageio
import?os?
import?cv2
from?PIL?import?Image
plt.rcParams['animation.writer']?=?'html'
plt.rcParams['font.sans-serif']?=?['SimHei']
plt.rcParams['axes.unicode_minus']?=?False
def?html_to_gif(html_file,?gif_file,?duration=0.1):
????path?=?html_file.replace(".html","_frames")
????images?=?[os.path.join(path,x)?for?x?in?sorted(os.listdir(path))]
????frames?=?[imageio.imread(x)?for?x?in?images]
????imageio.mimsave(gif_file,?frames,?'gif',?duration=duration)
????return?gif_file
cmap?=?[
'#2E91E5',
'#1CA71C',
'#DA16FF',
'#B68100',
'#EB663B',
'#00A08B',
'#FC0080',
'#6C7C32',
'#862A16',
'#620042',
'#DA60CA',
'#0D2A63']*100
dfx?=?pd.read_csv("./data/gdp_per_capita.csv")
dfx?=?dfx.set_index("year")
dfx.index?=?[str(x)?for?x?in?dfx.index]
dfx?=?dfx[sorted(dfx.columns)]
dfy?=?pd.read_csv("./data/life_expect.csv")
dfy?=?dfy.set_index("year")
dfy.index?=?[str(x)?for?x?in?dfy.index]
dfy?=?dfy[sorted(dfy.columns)]
dfz?=?pd.read_csv("./data/pop_amount.csv")
dfz?=?dfz.set_index("year")
dfz.index?=?[str(x)?for?x?in?dfz.index]
dfz?=?dfz[sorted(dfz.columns)]
def?bubble_chart_race(dfx,dfy,dfz,title?=?"中國大陸各省市歷年人均GDP和預(yù)期壽命變化",
??????????????????????filename?=?None,
??????????????????????figsize?=?(6.5,3.5),dpi?=?144,
??????????????????????duration?=?0.5,
??????????????????????xlabel?=?"人均GDP(人民幣)",
??????????????????????ylabel?=?"預(yù)期壽命",?
??????????????????????size_label?=?"點尺寸:?人口數(shù)量",
??????????????????????anotate_points?=?["江西省","北京市","上海市","廣東省",
????????????????????????????????????????"河南省","江蘇省","黑龍江省","西藏自治區(qū)"]):
????fig,ax?=?plt.subplots(figsize=figsize,dpi=dpi)
????ax.set_facecolor("0.9")
????ax.set_title(title,color?=?"black",fontsize?=?12)
????#?調(diào)整spines
????ax.spines["top"].set_visible(False)
????ax.spines["right"].set_visible(False)
????ax.spines["left"].set_visible(False)
????ax.spines["bottom"].set_visible(False)
????def?plot_frame(date):
????????
????????dfdata?=?pd.DataFrame()?
????????xdata?=?dfx.loc[date,:].sort_index()?
????????ydata?=?dfy.loc[date,:].sort_index()
????????zdata?=?dfz.loc[date,:].sort_index()
????????dfdata["x"]?=?xdata
????????dfdata["y"]?=?ydata
????????dfdata["z"]?=?zdata?
????????#?繪制散點圖像
????????
????????ax.clear()
????????ax.scatter(dfdata["x"],dfdata["y"],s?=?100*dfdata["z"]/dfdata["z"].mean(),
???????????????c?=?(cmap*100)[0:len(dfdata)],alpha?=?0.5)
????????#?添加圖例文字
????????for?i,p?in?enumerate(dfdata.index):
????????????px,py,pz?=?dfdata.loc[p,["x","y","z"]].tolist()?
????????????if?p?in?anotate_points:
????????????????ax.annotate(p,xy?=?(px,py),??xycoords?=?"data",
????????????????????xytext?=?(-15,10),fontsize?=?10,fontweight?=?"bold",color?=?cmap[i],?textcoords?=?"offset?points")
????????ax.tick_params(bottom?=?False,left?=?False,labelsize?=?8,direction?=?"in",length?=?2)
????????#?調(diào)整繪圖范圍
????????xlim?=?(dfx.values.min(),dfx.values.max())
????????ax.set_xlim(left?=?xlim[0]-(xlim[1]-xlim[0])/10,right?=?xlim[1]+(xlim[1]-xlim[0])/10)
????????ylim?=?(dfy.values.min(),dfy.values.max())
????????ax.set_ylim(bottom?=?ylim[0]-(ylim[1]-ylim[0])/10,top?=?ylim[1]+(ylim[1]-ylim[0])/5)
????????#?添加輔助元素
????????ax.text(0.5,?0.5,?date,?va="center",?ha="center",alpha=0.3,?size?=?50,transform?=?ax.transAxes)
????????ax.text(0.85,?0.92,?size_label,?ha="center",va="center",?size?=?10,transform?=?ax.transAxes)
????????ax.grid(axis?=?"x",color="white",lw=1,ls?=?"-")
????????ax.tick_params(bottom?=?False,left?=?False,labelsize?=?8,direction?=?"in",length?=?2)
????????ax.set_xlabel(xlabel,fontsize?=?10)
????????ax.set_ylabel(ylabel,fontsize?=?10)
????
????
????bubble_animation?=?animation.FuncAnimation(fig,plot_frame,frames?=?dfx.index?,interval?=?int(duration*1000))
????if?filename?is?None:
????????try:
????????????from?IPython.display?import?HTML
????????????return?HTML(bubble_animation.to_jshtml())
????????except?ImportError:
????????????pass
????else:
????????bubble_animation.save(filename)
????????return?filename
html_file?=?"bubble_chart_race.html"
gif_file?=?html_file.replace(".html",".gif")
bubble_chart_race(dfx,dfy,dfz,filename?=?html_file,title?=?"中國大陸各省份歷年人均GDP和預(yù)期壽命")
html_to_gif(html_file,gif_file,duration=1.0)
主要思路是構(gòu)建plot_frame函數(shù)逐幀繪制圖像,再用matplotlib的animation模塊制作動畫。
收工。??
打碼不易,喜歡本篇的小伙伴,或者需要完整代碼和繪圖數(shù)據(jù)集的同學(xué),可以對本文點贊,在看,和分享后在公眾號“算法美食屋”后臺回復(fù)關(guān)鍵字:動態(tài)圖,添加作者微信獲取。
萬水千山總是情,點個在看行不行。。。??
評論
圖片
表情
