利用?Python?讓圖表動起來
用Matplotlib和Seaborn這類Python庫可以畫出很好看的圖,但是這些圖只是靜態(tài)的,難以動態(tài)且美觀地呈現數值變化。要是在你下次的演示、視頻、社交媒體Po文里能用短視頻呈現數據變化,是不是很贊呢?更棒的是,你還是可以在你的圖表上用Matplotlib、Seaborn或者其他庫!
本文將使用美國國家藥物濫用研究所和疾病預防控制中心公布的藥物數據,可在此處下載:https://http://www.drugabuse.gov/sites/default/files/overdosedata1999-2015.xls
我們會用到的數據是這樣的:

我們將用Matplotlib和Seaborn繪圖,用Numpy和Pandas處理數據。Matplotlib也提供了一些我們做動畫可以的函數,所以讓我們首先導入所有依賴項。
import numpy as np import pandas as pd import seaborn as sns import matplotlib import matplotlib.pyplot as plt import matplotlib.animation as animation
然后用Pandas載入數據并轉成DataFrame類型的數據結構。因為我們要針對不同類藥物的濫用畫圖,寫個函數來載入感興趣的特定行的數據能避免重復代碼。(小編注:原文提供的代碼在讀取excel文件的時候使用了已廢棄的sheetname參數,本文中已修正為sheet_name)
overdoses = pd.read_excel('overdose_data_1999-2015.xls',sheet_name='Online',skiprows =6)
def get_data(table,rownum,title):
data = pd.DataFrame(table.loc[rownum][2:]).astype(float)
data.columns = {title}
return data
現在讓我們來做動畫吧!
首先,如果你和我一樣使用的是jupyter notebook,請在代碼首行加入 %matplotlib notebook,如此便可在notebook直接看到生成的動畫而非保存后才可見。
我現在使用 get_data函數從表中檢索過量的數據并放在有兩列的Pandas DataFrame中,一列是年,一列是過量死亡的人數。
%matplotlib notebook
title = 'Heroin Overdoses'
d = get_data(overdoses,18,title)
x = np.array(d.index)
y = np.array(d['Heroin Overdoses'])
overdose = pd.DataFrame(y,x)
#XN,YN = augment(x,y,10)
#augmented = pd.DataFrame(YN,XN)
overdose.columns = {title}
接下來我們初始化一個ffmpeg Writer并以20幀每秒、1800比特率進行錄屏。你也可以根據喜好自行設置這些值。
Writer = animation.writers['ffmpeg'] writer = Writer(fps=20, metadata=dict(artist='Me'), bitrate=1800)
(小編注:如果出現 RuntimeError:RequestedMovieWriter(ffmpeg)notavailable的報錯,請自行安裝ffmpeg,裝了brew的Mac可以直接: brew install ffmpeg)
現在我們創(chuàng)建一個有幾個標簽的圖形。確保設置x和y軸的限制,以免動畫隨當前顯示的數據范圍亂跳轉。
fig = plt.figure(figsize=(10,6))
plt.xlim(1999, 2016)
plt.ylim(np.min(overdose)[0], np.max(overdose)[0])
plt.xlabel('Year',fontsize=20)
plt.ylabel(title,fontsize=20)
plt.title('Heroin Overdoses per Year',fontsize=20)
動畫的核心是動畫函數,你可以在其中定義視頻的每一幀發(fā)生什么。這里的 i表示動畫中幀的索引。使用這個索引可以選擇應在此幀中可見的數據范圍。然后我使用seaborn線圖來繪制所選的數據。最后兩行代碼只是為了讓圖表更美觀。
def animate(i):
data = overdose.iloc[:int(i+1)] #選擇數據范圍
p = sns.lineplot(x=data.index, y=data[title], data=data, color="r")
p.tick_params(labelsize=17)
plt.setp(p.lines,linewidth=7)
我們用調用了 animate 函數并定義了幀數的 matplotlib.animation.FuncAnimation來開始動畫, frames實際上定義了調用 animate的頻率。
ani = matplotlib.animation.FuncAnimation(fig, animate, frames=17, repeat=True)
你可以用 ani.save()把動畫保存為mp4,如果你想直接看一看動畫效果可以用plt.show() 。
ani.save('HeroinOverdosesJumpy.mp4', writer=writer)
現在我們的圖表動起來啦:

動畫能夠正常運行但是感覺有點跳躍,所以我們需要在已有數據點之間增加更多的數據點來使動畫的過渡平滑。于是我們使用另一個函數 augment。
def augment(xold,yold,numsteps):
xnew = []
ynew = []
for i in range(len(xold)-1):
difX = xold[i+1]-xold[i]
stepsX = difX/numsteps
difY = yold[i+1]-yold[i]
stepsY = difY/numsteps
for s in range(numsteps):
xnew = np.append(xnew,xold[i]+s*stepsX)
ynew = np.append(ynew,yold[i]+s*stepsY)
return xnew,ynew
現在我們只需要對我們的數據應用這個函數、增加 matplotlib.animation.FuncAnimation 函數的幀數。在這里我用參數 numsteps=10調用 augment函數,也就是增加數據點至160個,并且設置 frames=160 。這樣以來,圖表顯得更為平滑,但還是在數值變動處有些突兀。

為了讓我們的動畫更平滑美觀,我們可以增加一個平滑函數(具體請見:https://www.swharden.com/wp/2008-11-17-linear-data-smoothing-in-python/ )。
def smoothListGaussian(listin,strippedXs=False,degree=5):
window=degree*2-1
weight=np.array([1.0]*window)
weightGauss=[]
for i in range(window):
i=i-degree+1
frac=i/float(window)
gauss=1/(np.exp((4*(frac))**2))
weightGauss.append(gauss)
weight=np.array(weightGauss)*weight
smoothed=[0.0]*(len(listin)-window)
for i in range(len(smoothed)):
smoothed[i]=sum(np.array(listin[i:i+window])*weight)/sum(weight)
return smoothed
另外我們也可以加上一點顏色和樣式參數,讓圖表更個性化。
sns.set(rc={'axes.facecolor':'lightgrey', 'figure.facecolor':'lightgrey','figure.edgecolor':'black','axes.grid':False})
當當當!如此我們便得到了文章開頭的動畫圖表。
這篇文章僅僅只是matplotlib動畫功能的一個例子,你大可以用它來實現任何一種圖表的動畫效果。簡單調整 animate()函數內的參數和圖表類型,就能得到無窮無盡的可能性。
到此這篇關于利用 Python 讓圖表動起來的文章就介紹到這了,更多相關Python 讓圖表動起來內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Python 3.x 安裝opencv+opencv_contrib的操作方法
下面小編就為大家分享一篇Python 3.x 安裝opencv+opencv_contrib的操作方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-04-04

