# Matplotlib 繪圖技巧:移動的點 > 作者:王一哲 > 日期:2019/12/20 <br /> ## 前言 在這篇文章中,我利用 Matplotlib 繪製一個隨著 sin 函數移動的點,由於圖片中的物件比較簡單,算是上一篇文章〈[Matplotlib 繪圖技巧:水波干涉動畫](https://hackmd.io/@yizhewang/HJYw0EJ0r)〉的前置作業。 <img style="display: block; margin-left: auto; margin-right: auto" height="80%" width="80%" src="https://imgur.com/lkcTtag.gif"> <div style="text-align:center">使用Matplotlib產生的動畫</div> <br /> ## Python 程式碼 ```python= import numpy as np import matplotlib.pyplot as plt import matplotlib.animation as animation """ 1.參數設定 """ xmin, xmax, A, N = 0, 4*np.pi, 4, 100 x = np.linspace(xmin, xmax, N) y = A*np.sin(x) """ 2.繪圖 """ fig = plt.figure(figsize=(7, 6), dpi=100) ax = fig.gca() line, = ax.plot(x, y, color='blue', linestyle='-', linewidth=3) dot, = ax.plot([], [], color='red', marker='o', markersize=10, markeredgecolor='black', linestyle='') ax.set_xlabel('x', fontsize=14) ax.set_ylabel('y', fontsize=14) def update(i): dot.set_data(x[i], y[i]) return dot, def init(): dot.set_data(x[0], y[0]) return dot, ani = animation.FuncAnimation(fig=fig, func=update, frames=N, init_func=init, interval=1000/N, blit=True, repeat=True) plt.show() ani.save('MovingPointMatplotlib.gif', writer='imagemagick', fps=1/0.04) ``` <br /> ### 參數設定 1. 繪圖範圍最小值 xmin = 0 2. 繪圖範圍最大值 xmax = 4π 3. 振幅 A = 4 4. 動畫格數 N = 100 5. 利用 numpy.linspace 產生 0 到 4π,分為 100 等份的一維陣列 x。 6. 將 x 代入 A* sin(x) 計算對應的值並存入一維陣列 y。 <br /> ### 繪圖 1. 第17行:以陣列x、y的資料繪圖,格式為藍色實線,線寬為3。由於Matplotlib中有許多神奇的縮寫,可以用以下的程式碼代替此行: ```python line, = ax.plot(x, y, 'b-', lw=3) ``` 2. 第18行:設定移動點的格式為紅色實心的點,點的寬度為10,點的邊綠為黑色實線,可以用以下的程式碼代替此行: ```python dot, = ax.plot([], [], 'ro', ms=10, mec='k') ``` 3. 第22 - 24行:自訂函式update,使用set_data更新點的位置。 4. 第26 - 28行:自訂函式init,使用set_data畫點的起始位置。由於我們要畫的點起始位置儲存在陣列x、y當中索引值為0的位置,其實可以刪除這個自訂函式,同時將第30行的程式碼改為以下的型式 ```python ani = animation.FuncAnimation(fig, update, N, interval=1000/N, blit=True) ``` 5. 第30行:利用 matplotlib.animation.FuncAnimation 繪製動畫,選項為 - fig:目標圖片 - func:更新圖片使用的函式 - frames:圖片總數 - init_func:起始圖片 - interval:更新圖片時間間隔 - blit:若只更新圖片上會改變的部分設定為True,反之則設定為False。經過測試後發現,若設定為True,則使用plt.show()顯示圖片時會比較順,但是不會影響到產生的gif檔大小。 - repeat:是否重複執行動畫,預設值為True。 6. 第31行:顯示圖片,如果只要產生gif檔,可以省略此行。 7. 第32行:使用imagemagick將圖片存成gif檔,檔名為MovingPointMatplotlib.gif,fps為每秒更新的圖片數量。 <br /> <img style="display: block; margin-left: auto; margin-right: auto" height="80%" width="80%" src="https://imgur.com/lkcTtag.gif"> <div style="text-align:center">使用Matplotlib產生的動畫</div> <br /> ## GeoGebra 版本 由於我也常用 GeoGebra 繪圖,於是我用 GeoGebra 畫了一樣的圖來比較看看,以下是繪圖步驟。 1. 在下方的輸入欄位中入以下指令新增變數,其中 xmin 為繪圖範圍最小值、xmax 為繪圖範圍最大值、A 為振幅、N 為動畫格數。 ```c xmin = 0 xmax = 4*pi A = 4 N = 101 ``` 2. 加上控制時間的數值滑桿,再於滑桿上按滑鼠右鍵,由屬性選單中的**滑桿**分頁 ⇒ **動畫** ⇒ **重複**設定為**遞增**。 ```c t = Slider(xmin, xmax, (xmax-xmin)/N) ``` 3. 新增函數f(x) ```c f(x) = If(xmin <= x <= xmax, A*sin(x)) ``` 4. 新增點P ```c P = Point({t, f(t)}) ``` 5. 由選單選擇**檔案** ⇒ **匯出** ⇒ **動態GIF檔**,滑桿為**t=0**,影格速率**40** ms,勾選**循環播放**。 <br /> <img style="display: block; margin-left: auto; margin-right: auto" height="80%" width="80%" src="https://imgur.com/X1DsXIO.gif"> <div style="text-align:center">使用GeoGebra產生的動畫</div> <br /> ## 結語 在這篇文章中,我使用了兩種不同的方法做到同樣的效果,其實兩種方法都很方便,但是匯出之後的檔案有點大,可以再用 magick 將圖片檔案縮小,這樣使用上會比較方便。 <br /> ## 參考資料 1. Matplotlib 官方文件 **matplotlib.animation.FuncAnimation** https://matplotlib.org/3.1.1/api/_as_gen/matplotlib.animation.FuncAnimation.html 2. StackOverflow **Animate sine function with red dot** https://stackoverflow.com/questions/43559337/animate-sine-function-with-red-dot 3. 莫煩Python **Animation 动画** https://morvanzhou.github.io/tutorials/data-manipulation/plt/5-1-animation/ 4. Matplotlib 官方文件 **matplotlib.pyplot.plot** https://matplotlib.org/2.1.1/api/_as_gen/matplotlib.pyplot.plot.html --- ###### tags:`Python`、`GeoGebra`