用 Matplotlib 庫生成動畫圖表

翻譯:瘋狂的技術宅
https://towardsdatascience.co...

圖片描述


更多文章請關注微信公衆號:硬核智能html


動畫是一種展現現象的有趣方式。相對於靜態圖表,人類老是容易被動畫和交互式圖表所吸引。在描述多年來的股票價格、過去十年的氣候變化、季節性和趨勢等時間序列數據時,動畫更有意義,由於咱們能夠看到特定的參數是怎樣隨時間變化的。python

上面的圖是雨滴的模擬而且已經使用 Matplotlib 庫實現,該庫是一個廣爲人知的祖父級別的 python 可視化包。 Matplotlib 經過對 50 個散點的比例和透明度進行設置來模擬雨滴。今天,Python 擁有大量強大的可視化工具,如 Plotly、Bokeh、Altair等等。這些庫可以實現最早進的動畫和交互特性。儘管如此,本文的目的是強調這個庫的另外一個方面,這個方面沒有人進行過太多的探索,這就是動畫git


概述

Matplotlib 是一個廣受歡迎的 Python 2D 繪圖庫。不少人都是從 Matplotlib 開始數據可視化之旅的。可使用matplotlib輕鬆生成圖表、直方圖、功率譜,條形圖,錯誤圖表,散點圖等。它還與 Pandas 和 Seaborn 等庫無縫集成,創造出更加複雜的可視化效果。github

matplotlib 的優勢是:web

  • 它的設計相似於 MATLAB,所以很容易在在二者之間切換。
  • 在後端進行渲染。
  • 能夠重現任何圖表(須要一點努力)。
  • 已經存在了十多年,擁有龐大的用戶羣。

然而,也有一些方面 Matplotlib 落後於同類的庫。後端

  • Matplotlib 有一個過於冗長的規則 API。
  • 有時候風格不好。
  • 對 Web 和交互式圖表的支持不佳。
  • 對於大型複雜數據而言一般很慢。

這份複習資料是來自 Datacamp 的 Matplotlib 小抄,你能夠經過它來提升本身的基礎知識。api

clipboard.png


動畫

Matplotlib 的 animation 基類負責處理動畫部分。它提供了一個構建動畫功能的框架。使用下面兩個接口來實現:微信

  • FuncAnimation 經過重複調用函數 func 來產生動畫。
  • ArtistAnimation: 動畫使用一組固定的 Artist 對象。

可是,在這兩個接口中,FuncAnimation 是最方便使用的。你能夠經過閱讀文檔 獲得的更多信息,由於咱們只關注 FuncAnimation 工具。app

要求

  • 安裝 numpymatplotlib
  • 要將動畫保存爲 mp4 或 gif,須要安裝 ffmpegimagemagick

準備好以後,咱們就能夠在 Jupyter note 中開始建立第一個動畫了。能夠從 Github 獲得本文的代碼。框架

基本動畫:移動的正弦波

咱們先用 FuncAnimation 建立一個在屏幕上移動的正弦波的動畫。動畫的源代碼來自 Matplotlib 動畫教程。首先看一下輸出,而後咱們會分析代碼以瞭解幕後的原理。

import numpy as np
from matplotlib import pyplot as plt
from matplotlib.animation import FuncAnimation
plt.style.use('seaborn-pastel')


fig = plt.figure()
ax = plt.axes(xlim=(0, 4), ylim=(-2, 2))
line, = ax.plot([], [], lw=3)

def init():
    line.set_data([], [])
    return line,
def animate(i):
    x = np.linspace(0, 4, 1000)
    y = np.sin(2 * np.pi * (x - 0.01 * i))
    line.set_data(x, y)
    return line,

anim = FuncAnimation(fig, animate, init_func=init,
                               frames=200, interval=20, blit=True)

anim.save('sine_wave.gif', writer='imagemagick')

圖片描述

  • 在第(7-9)行中,咱們只需在圖中建立一個帶有單個軸的圖形窗口。而後建立一個空的行對象,它其實是動畫中要修改的對象。稍後將用數據對行對象進行填充。
  • 在第(11-13)行中,咱們建立了 init 函數,它將使動畫開始。 init 函數對數據進行初始化並設置軸限制。
  • 在第(14-18)行中,咱們最終定義了動畫函數,該函數將幀編號( i )做爲參數並建立正弦波(或任何其餘動畫),這取決於 i 的值。此函數返回一個已修改的繪圖對象的元組,它告訴動畫框架哪些部分應該屬於動畫。
  • 在第 20 行中,咱們建立了實際的動畫對象。 blit 參數確保只重繪那些已經改變的圖塊。

這是在 Matplotlib 中建立動畫的基本方法。經過對代碼進行一些調整,能夠建立有趣的可視化圖表。接下來看看更多的可視化案例。


一個不斷增加的線圈

一樣,在 GeeksforGeeks 中有一個很好的例子。如今讓咱們在 matplotlib 的 animation 類的幫助下建立一個緩慢展開的動圈。該代碼很是相似於正弦波圖,只需稍做調整便可。

import matplotlib.pyplot as plt 
import matplotlib.animation as animation 
import numpy as np 
plt.style.use('dark_background')

fig = plt.figure() 
ax = plt.axes(xlim=(-50, 50), ylim=(-50, 50)) 
line, = ax.plot([], [], lw=2) 

# initialization function 
def init(): 
    # creating an empty plot/frame 
    line.set_data([], []) 
    return line, 

# lists to store x and y axis points 
xdata, ydata = [], [] 

# animation function 
def animate(i): 
    # t is a parameter 
    t = 0.1*i 
    
    # x, y values to be plotted 
    x = t*np.sin(t) 
    y = t*np.cos(t) 
    
    # appending new points to x, y axes points list 
    xdata.append(x) 
    ydata.append(y) 
    line.set_data(xdata, ydata) 
    return line, 
    
# setting a title for the plot 
plt.title('Creating a growing coil with matplotlib!') 
# hiding the axis details 
plt.axis('off') 

# call the animator     
anim = animation.FuncAnimation(fig, animate, init_func=init, 
                            frames=500, interval=20, blit=True) 

# save the animation as mp4 video file 
anim.save('coil.gif',writer='imagemagick')

圖片描述


實時更新圖表

在繪製動態數量(如庫存數據,傳感器數據或任何其餘時間相關數據)時,實時更新的圖表會派上用場。咱們繪製了一個簡單的圖表,當有更多數據被輸入系統時,該圖表會自動更新。下面讓咱們繪製一家假想公司在一個月內的股票價格。

# importing libraries
import matplotlib.pyplot as plt
import matplotlib.animation as animation


fig = plt.figure()
# creating a subplot 
ax1 = fig.add_subplot(1,1,1)

def animate(i):
    data = open('stock.txt','r').read()
    lines = data.split('\n')
    xs = []
    ys = []
   
    for line in lines:
        x, y = line.split(',') # Delimiter is comma    
        xs.append(float(x))
        ys.append(float(y))
    
    ax1.clear()
    ax1.plot(xs, ys)

    plt.xlabel('Date')
    plt.ylabel('Price')
    plt.title('Live graph with matplotlib')    
    
    
ani = animation.FuncAnimation(fig, animate, interval=1000) 
plt.show()

如今,打開終端並運行 python 腳本。你將獲得以下圖所示的圖表,該圖表會自動更新:

圖片描述

這裏的間隔是 1000 毫秒或一秒。


3D 圖動畫

建立 3D 圖形是很常見的,但若是咱們想要爲這些圖形的視角設置動畫,該怎麼辦呢?咱們的想法是更改攝像機視圖,而後用每一個生成的圖像來建立動畫。在 Python Graph Gallery 上有一個很好的例子。

在與 jupyter notebook 相同的目錄中建立名爲 volcano 的文件夾。全部圖片文件都將存儲在這裏,而後將在動畫中使用。

# library
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns

# Get the data (csv file is hosted on the web)
url = 'https://python-graph-gallery.com/wp-content/uploads/volcano.csv'
data = pd.read_csv(url)

# Transform it to a long format
df=data.unstack().reset_index()
df.columns=["X","Y","Z"]

# And transform the old column name in something numeric
df['X']=pd.Categorical(df['X'])
df['X']=df['X'].cat.codes

# We are going to do 20 plots, for 20 different angles
for angle in range(70,210,2):

# Make the plot
    fig = plt.figure()
    ax = fig.gca(projection='3d')
    ax.plot_trisurf(df['Y'], df['X'], df['Z'], cmap=plt.cm.viridis, linewidth=0.2)

    ax.view_init(30,angle)

    filename='Volcano/Volcano_step'+str(angle)+'.png'
    plt.savefig(filename, dpi=96)
    plt.gca()

這將會在 Volcano 文件夾中建立多個 PNG 文件。如今用 ImageMagick 將它們轉換爲動畫。打開終端並切換到 Volcano 目錄下輸入如下命令:

convert -delay 10 Volcano*.png animated_volcano.gif

圖片描述


使用 Celluloid 模塊建立的動畫

Celluloid 是一個Python模塊,它簡化了在 matplotlib 中建立動畫的過程。這個庫建立一個 matplotlib 圖,並從中再建立一個 Camera。而後從新處理數據,並在建立每一個幀後,用 camera 拍攝快照。最後建立包含全部幀的動畫。

安裝

pip install celluloid

如下是使用 Celluloid 模塊的一些示例。

Minimal

from matplotlib import pyplot as plt
from celluloid import Camera

fig = plt.figure()
camera = Camera(fig)
for i in range(10):
    plt.plot([i] * 10)
    camera.snap()
animation = camera.animate()
animation.save('celluloid_minimal.gif', writer = 'imagemagick')

圖片描述

Subplot

import numpy as np
from matplotlib import pyplot as plt
from celluloid import Camera

fig, axes = plt.subplots(2)
camera = Camera(fig)
t = np.linspace(0, 2 * np.pi, 128, endpoint=False)
for i in t:
    axes[0].plot(t, np.sin(t + i), color='blue')
    axes[1].plot(t, np.sin(t - i), color='blue')
    camera.snap()
    
animation = camera.animate()  
animation.save('celluloid_subplots.gif', writer = 'imagemagick')

clipboard.png

Legend

import matplotlib
from matplotlib import pyplot as plt
from celluloid import Camera

fig = plt.figure()
camera = Camera(fig)
for i in range(20):
    t = plt.plot(range(i, i + 5))
    plt.legend(t, [f'line {i}'])
    camera.snap()
animation = camera.animate()
animation.save('celluloid_legends.gif', writer = 'imagemagick')

圖片描述


總結

動畫有助於突出顯示沒法經過靜態圖表輕鬆傳達的某些功能。儘管如此,沒必要要的過分使用有時會使事情複雜化,應該明智地使用數據可視化中的每一個功能以產生最佳效果。

更多文章請關注微信公衆號:硬核智能

更多文章請關注微信公衆號:硬核智能

相關文章
相關標籤/搜索