使用Matplotlib制作動(dòng)態(tài)圖的示例詳解
一、簡(jiǎn)介
matplotlib(https://matplotlib.org/)是一個(gè)著名的python繪圖庫(kù),由于其靈活強(qiáng)大的繪圖功能使得在python中可視化變得非常容易,關(guān)于matplotlib的基礎(chǔ)知識(shí)這里不再介紹,有疑問(wèn)可以去官網(wǎng)翻Tutorials和example學(xué)習(xí)。由于我們實(shí)際使用時(shí)常常是繪制靜態(tài)圖,忽略了matplotlib的動(dòng)態(tài)圖生成功能,同時(shí)matplotlib生成動(dòng)態(tài)圖的功能不是非常友善,因此大部分人在真的需要制作動(dòng)態(tài)圖時(shí)都會(huì)選擇先用matplotlib生成一系列靜態(tài)圖片,然后再用其它相對(duì)比較容易使用的第三方python庫(kù)生成動(dòng)態(tài)圖,如imageio(https://imageio.readthedocs.io/en/stable/#), 或者使用其它工具,如Matlab。這里打算簡(jiǎn)單介紹一下在matplotlib庫(kù)中制作動(dòng)態(tài)圖的方法。
二、模塊簡(jiǎn)介
matplotlib的animation模塊提供了動(dòng)態(tài)圖制作功能,animation類提供了兩個(gè)方法來(lái)生成動(dòng)態(tài)圖,即FuncAnimation和ArtistAnimation,這里我們使用FuncAnimation方法重復(fù)調(diào)用函數(shù)來(lái)生成圖片。
1. FuncAnimation類介紹
FuncAnimation類的主要參數(shù)包括:
fig: 每一幀畫(huà)面繪制使得Figure對(duì)象
func: 定義動(dòng)畫(huà)每一幀的更新函數(shù),通常這一函數(shù)需要包含額外參數(shù),此時(shí)可以用functools.partial來(lái)生成。
frames:可以是可迭代對(duì)象,整數(shù),或者生成函數(shù)或者缺省。
init_func:初始化函數(shù)
inteval:每一幀畫(huà)面的停留時(shí)間
repeat:當(dāng)動(dòng)態(tài)圖中所有幀都播放完了之后是否重復(fù)播放
bilt:是否使用blitting來(lái)優(yōu)化繪圖
…
2. 定義動(dòng)畫(huà)更新函數(shù)
在FunAnimation類中,更新函數(shù)在每一幀中都會(huì)被重新調(diào)用,通過(guò)在更新函數(shù)中更改一些繪圖函數(shù)的數(shù)據(jù),在每一幀我們就能得到不同的圖片,然后FunAnimation的Writer(后端)將這些圖片組合就能得到動(dòng)態(tài)圖片。關(guān)于更新函數(shù)的一些需要注意的地方是:
如果設(shè)置了bilt == True,更新函數(shù)的最后就需要返回所有被修改或創(chuàng)建的Artists的引用變量
生成函數(shù)的第一個(gè)傳入?yún)?shù)必須是當(dāng)前的幀數(shù),其具體值可以通過(guò)frames參數(shù)定義,可以是可迭代類型或整數(shù)
三、使用matplotlib制作動(dòng)畫(huà)
1.一步法制作動(dòng)態(tài)圖片
由于matplotlib本身自帶強(qiáng)大的繪圖功能,因此我們可以不用生成圖片,直接在初始繪圖的基礎(chǔ)上通過(guò)更新函數(shù)來(lái)修改繪圖數(shù)據(jù),一步直接生成動(dòng)態(tài)圖片,方便快捷,以下是代碼:
import numpy as np
from matplotlib.animation import FuncAnimation
import matplotlib.pyplot as plt
from functools import partial
### 繪制y=sin(2pi(x+t/t_0))*sin(2pi(t/t_0))
def getSinx_t(t=0, t_0=120, x_count=1e5):
x = np.linspace(0.0, 1.0, int(x_count))
y = np.sin(2.0*np.pi*(x + t/t_0))*np.sin(t/t_0*2.0*np.pi)
return x, y
### 圖片初始化
fig, ax = plt.subplots(dpi=100)
ax.set_aspect('auto')
ax.set_xlim((0.0, 1.0))
ax.set_ylim((-1.0, 1.0))
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_title(r'$y=sin[2\pi(x+t/t_0)]*sin(2\pi t/t_0)$')
### 繪制初始曲線
x, y = getSinx_t()
y_up = y[np.where(y>0)]
x_up = x[np.where(y>0)]
x_dn = x[np.where(y<0)]
y_dn = y[np.where(y<0)]
plot_line = ax.plot(x, y)
plot_hline = ax.hlines(y=0.0, xmin=0.0, xmax=1.0, linestyles='dashed', colors='grey')
fill_xy_up = ax.fill_between(x=x_up, y1=y_up, y2=0, color='red', alpha=0.3)
fill_xy_dn = ax.fill_between(x=x_dn, y1=y_dn, y2=0, color='green', alpha=0.3)
plot_text = ax.text(x=0.8, y=0.75, s='t=0', fontsize=16, fontfamily='cursive')
### 定義動(dòng)畫(huà)更新函數(shù)
def UpdateFigure(num, f_plot_line, f_fill_xy_up, f_fill_xy_dn, f_plot_text):
x_update, y_update = getSinx_t(t=num)
f_plot_line[0].set_data(x_update, y_update)
f_plot_text.set_text('t={}'.format(num))
x_up = x_update[np.where(y_update>0)]
y_up = y_update[np.where(y_update>0)]
xy_up1 = np.column_stack((x_up, y_up))
xy_up2 = np.column_stack((x_up[::-1], np.zeros(x_up.shape)))
x_dn = x_update[np.where(y_update<0)]
y_dn = y_update[np.where(y_update<0)]
xy_dn1 = np.column_stack((x_dn, y_dn))
xy_dn2 = np.column_stack((x_dn[::-1], np.zeros(x_dn.shape)))
f_fill_xy_up.set_verts([np.vstack((xy_up1, xy_up2))])
f_fill_xy_dn.set_verts([np.vstack((xy_dn1, xy_dn2))])
return [f_plot_line[0], f_fill_xy_up, f_fill_xy_dn, f_plot_text]
### 創(chuàng)建FunAnimation對(duì)象
ani = FuncAnimation(fig, partial(
UpdateFigure,
f_plot_line=plot_line,
f_fill_xy_up=fill_xy_up,
f_fill_xy_dn=fill_xy_dn,
f_plot_text=plot_text),
np.arange(120),
blit=True)
### 保存動(dòng)態(tài)圖片
ani.save('sinxt.gif', fps=60) 以下為得到的動(dòng)態(tài)圖片:

2. 兩步法制作動(dòng)態(tài)圖片
所謂兩步法是指,首先用matplotlib生成一系列靜態(tài)圖片,然后結(jié)合matplotlib.image.imread讀取圖片功能和matplotlib.axes.Axes.imshow展示圖片功能,來(lái)動(dòng)態(tài)地更新圖片,這種方法相比于上一種方法稍微復(fù)雜,但是這種方法靈活性更高,同時(shí)也可以用來(lái)組合一些非matplotlib生成的圖片。以下為代碼:
import matplotlib.pyplot as plt
import matplotlib.image as mimg
from matplotlib.animation import FuncAnimation
import numpy as np
from functools import partial
import os
### 繪制y=cos(2pi(x+t/t_0))*cos(2pi(t/t_0))
def getCosx_t(t=0, t_0=120, x_count=1e5):
x = np.linspace(0.0, 1.0, int(x_count))
y = np.cos(2.0*np.pi*(x + t/t_0))*np.cos(t/t_0*2.0*np.pi)
return x, y
fig_count = 120 # 圖片總數(shù)
### 定義生成所有圖片的函數(shù)
def getFigrues(fig_count):
try:
os.mkdir('fig')
except FileExistsError:
print("Dir Exist!")
for i in range(fig_count):
fig, ax = plt.subplots(dpi=100)
ax.set_aspect('auto')
ax.set_xlim((0.0, 1.0))
ax.set_ylim((-1.0, 1.0))
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_title(r'$y=cos[2\pi(x+t/t_0)]*cos(2\pi t/t_0)$')
x, y = getCosx_t(t=i)
y_up = y[np.where(y>0)]
x_up = x[np.where(y>0)]
x_dn = x[np.where(y<0)]
y_dn = y[np.where(y<0)]
ax.plot(x, y)
ax.hlines(y=0.0, xmin=0.0, xmax=1.0, linestyles='dashed', colors='grey')
ax.fill_between(x=x_up, y1=y_up, y2=0, color='red', alpha=0.3)
ax.fill_between(x=x_dn, y1=y_dn, y2=0, color='green', alpha=0.3)
ax.text(x=0.8, y=0.75, s='t={}'.format(i), fontsize=16, fontfamily='cursive')
fig.show(False)
fig.savefig('./fig/{}.jpg'.format(i))
plt.close(fig)
getFigrues(fig_count)
### 讀取圖片尺寸
def GetFigSize(fig_path='./fig/0.jpg'):
now_img = mimg.imread(fname=fig_path)
img_pxy = now_img.shape
return img_pxy[1], img_pxy[0]
### 繪圖初始化
img_px, img_py = GetFigSize()
img_dpi=100
fig, ax = plt.subplots(figsize=[img_px/img_dpi, img_py/img_dpi], dpi=img_dpi)
ax.set_aspect('equal')
ax.set_position([0.0, 0.0, 1.0, 1.0])
ax.set_axis_off()
plot_img = ax.imshow(X=np.zeros((img_py, img_px, 3)))
### 定義動(dòng)畫(huà)更新函數(shù)
def UpdateImages(num, f_plot_img):
now_img_path = './fig/{}.jpg'.format(num)
now_img = mimg.imread(fname=now_img_path)
f_plot_img.set_data(now_img)
return [f_plot_img]
### 創(chuàng)建FunAnimation對(duì)象
ani = FuncAnimation(
fig, partial(UpdateImages, f_plot_img=plot_img),
np.arange(fig_count),
blit=True)
### 保存動(dòng)態(tài)圖片
ani.save('cosxt.gif', fps=60) 得到的動(dòng)態(tài)圖片:

到此這篇關(guān)于使用Matplotlib制作動(dòng)態(tài)圖的示例詳解的文章就介紹到這了,更多相關(guān)Matplotlib動(dòng)態(tài)圖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
python傳參時(shí)一個(gè)星號(hào)和兩個(gè)星號(hào)的區(qū)別小結(jié)
在Python中,一個(gè)星號(hào)(*)和兩個(gè)星號(hào)(**)用于函數(shù)定義中的參數(shù)傳遞,本文主要介紹了python傳參時(shí)一個(gè)星號(hào)和兩個(gè)星號(hào)的區(qū)別小結(jié),具有一定的參考價(jià)值,感興趣的可以了解一下2024-02-02
Python數(shù)據(jù)結(jié)構(gòu)之鏈表詳解
在順序存儲(chǔ)方式中,根據(jù)數(shù)據(jù)元素的序號(hào)就可隨機(jī)存取表中任何一個(gè)元素,但同時(shí)在插入和刪除運(yùn)算需要移動(dòng)大量的元素,造成算法效率較低。解決此缺陷的一個(gè)辦法是:對(duì)線性表采用鏈?zhǔn)酱鎯?chǔ)方式。本文將介紹鏈?zhǔn)酱鎯?chǔ)結(jié)構(gòu)的特點(diǎn)以及各種基本操作的實(shí)現(xiàn)。需要的可以參考一下2022-01-01
python使用PyV8執(zhí)行javascript代碼示例分享
這篇文章主要介紹了python使用PyV8執(zhí)行javascript的小示例,大家參考使用吧2013-12-12
Python實(shí)現(xiàn)線性搜索算法的示例代碼
線性搜索算法,也稱為順序搜索算法,是一種簡(jiǎn)單但常用的搜索技術(shù),在本文中,將深入研究線性搜索算法,并演示如何在?Python?中實(shí)現(xiàn)它,需要的可以參考下2024-02-02
Python中的defaultdict模塊和namedtuple模塊的簡(jiǎn)單入門(mén)指南
這篇文章主要介紹了Python中的defaultdict模塊和namedtuple模塊的簡(jiǎn)單入門(mén)指南,efaultdict繼承自dict、namedtuple繼承自tuple,是Python中內(nèi)置的數(shù)據(jù)類型,需要的朋友可以參考下2015-04-04
Python使用Altair創(chuàng)建交互式數(shù)據(jù)可視化的操作指南
Altair 是一個(gè)基于 Vega-Lite 的 Python 數(shù)據(jù)可視化庫(kù),它旨在簡(jiǎn)化數(shù)據(jù)可視化的創(chuàng)建過(guò)程,尤其適用于統(tǒng)計(jì)圖表的生成,Altair 強(qiáng)調(diào)聲明式編碼方式,通過(guò)簡(jiǎn)單的語(yǔ)法,用戶能夠快速創(chuàng)建復(fù)雜的交互式圖表,本文將介紹 Altair 的基礎(chǔ)用法、常見(jiàn)圖表類型,需要的朋友可以參考下2024-12-12
基于Python實(shí)現(xiàn)一個(gè)簡(jiǎn)單的注冊(cè)機(jī)并生成卡密
這篇文章主要為大家詳細(xì)介紹了如何使用Python編寫(xiě)一個(gè)簡(jiǎn)單而強(qiáng)大的注冊(cè)機(jī),生成卡密來(lái)實(shí)現(xiàn)用戶注冊(cè),從而輕松登錄應(yīng)用程序,有需要的小伙伴快可以參考下2023-12-12

