1. 程式人生 > >今天把 MATPLOTLIB的動態散點圖程式碼 讀懂了

今天把 MATPLOTLIB的動態散點圖程式碼 讀懂了

程式碼如下:

心得後附。

import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np


class AnimatedScatter(object):
    """An animated scatter plot using matplotlib.animations.FuncAnimation."""
    def __init__(self, numpoints=50):
        self.numpoints = numpoints
        self.stream = self.data_stream()


        # Setup the figure and axes...
        self.fig, self.ax = plt.subplots()
        # Then setup FuncAnimation.
        self.ani = animation.FuncAnimation(self.fig, self.update, interval=5, 
                                           init_func=self.setup_plot, blit=True)


    def setup_plot(self):
        """Initial drawing of the scatter plot."""
        x, y, s, c = next(self.stream)
        self.scat = self.ax.scatter(x, y, c=c, s=s, animated=True)
        self.ax.axis([-10, 10, -10, 10])


        # For FuncAnimation's sake, we need to return the artist we'll be using
        # Note that it expects a sequence of artists, thus the trailing comma.
        return self.scat,


    def data_stream(self):
        """Generate a random walk (brownian motion). Data is scaled to produce
        a soft "flickering" effect."""
        data = np.random.random((4, self.numpoints))
        xy = data[:2, :]
        s, c = data[2:, :]
        xy -= 0.5
        xy *= 10
        while True:
            xy += 0.03 * (np.random.random((2, self.numpoints)) - 0.5)
            s += 0.05 * (np.random.random(self.numpoints) - 0.5)
            c += 0.02 * (np.random.random(self.numpoints) - 0.5)
            yield data


    def update(self, i):
        """Update the scatter plot."""
        data = next(self.stream)


        # Set x and y data...
        self.scat.set_offsets(data[:2, :])
        # Set sizes...
        self.scat._sizes = 300 * abs(data[2])**1.5 + 100
        # Set colors..
        self.scat.set_array(data[3])


        # We need to return the updated artist for FuncAnimation to draw..
        # Note that it expects a sequence of artists, thus the trailing comma.
    
        return self.scat,


    def show(self):
        plt.show()


if __name__ == '__main__':
    a = AnimatedScatter()
    a.show()


簡單解釋一下程式,我的理解
1. 程式定義了一個動態散點類

然後在主程式中例項化了這個類並呼叫了類的show()函式

class AnimatedScatter(object):

...

if __name__ == '__main__':
    a = AnimatedScatter()

    a.show()

2. 下面看看這個類都實現的功能


class AnimatedScatter(object):
    
    def __init__(self, numpoints=50):

    def setup_plot(self):

    def data_stream(self):

    def update(self, i):

    def show(self):

上述函式,其實都是為了這句服務的:self.ani = animation.FuncAnimation(self.fig, self.update, interval=5, init_func=self.setup_plot, blit=True)


3. 下面對程式進行註釋

import matplotlib.pyplot as plt                     #引入pyplot繪圖函式
import matplotlib.animation as animation   #引入動畫函式
import numpy as np


class AnimatedScatter(object):              #定義類


    def __init__(self, numpoints=50):     #定義類初始函式 請與 繪圖的初始化函式區分開
        self.numpoints = numpoints         #散點數為50
        self.stream = self.data_stream()   #呼叫類的資料流函式,此函式提供了無盡的資料流,給50個散點的X,Y座標,s是直徑,c是顏色這4個值進行賦值。相當於每次迭代提供(4,50)的一個數據塊。
        self.fig, self.ax = plt.subplots()  #設定繪圖畫布及繪圖區域
        self.ani = animation.FuncAnimation(self.fig, self.update, interval=5, 
                                           init_func=self.setup_plot, blit=True)    #進入此句後,程式進入迭代狀態,直到退出。此FuncAnimation()函式先呼叫init_func對畫面初始化,然後以5ms一幀的速率用update函式進行迭代。blit是指動態圖進行位塊輸送的優化。


    def setup_plot(self):  #設定繪畫,相當於繪圖的初始化函式
        x, y, s, c = next(self.stream)  #迭代,用stream對x,y,s,c進行一次賦值,注意stream指向data_stream()
        self.scat = self.ax.scatter(x, y, c=c, s=s, animated=True) # 利用上述值繪製散點圖
        self.ax.axis([-10, 10, -10, 10]) #設立X,Y座標軸的起始與終止點
        return self.scat, # 初始化函式返回散點圖的控制代碼


    def data_stream(self):  #資料流函式,注意此函式在繪圖的初始化函式和迭代函式中均被呼叫
        data = np.random.random((4, self.numpoints))#初始化一個(4,50)陣列,陣列中數為【0,1)的隨機數
        xy = data[:2, :]  #取陣列的前2行,為50個點 的XY座標賦值,注意xy是指向data陣列前兩行的指標
        s, c = data[2:, :] #取陣列的後兩行,分別為50個點的S和C賦值,同上,S和C指向data陣列後兩行
        xy -= 0.5   #對XY的值做調整
        xy *= 10   #對XY的值做調整,以便匹配-10:10的座標
        while True:  #進入迭代,每次上個函式setup_pl
            xy += 0.03 * (np.random.random((2, self.numpoints)) - 0.5)  #迭代直接修改了data的值
            s += 0.05 * (np.random.random(self.numpoints) - 0.5)
            c += 0.02 * (np.random.random(self.numpoints) - 0.5)
            yield data    #返回data值,注意data是個(4,50)的陣列


    def update(self, i): #此函式每次迭代都會被呼叫,此函式在繪製動態圖中已經被定義為迭代函式,此迭代函式的作用是利用data的值,給散點函式的50個點重新賦值,此i有何作用還請大牛指點。
        data = next(self.stream)   #更新data值
        self.scat.set_offsets(data[:2, :])  #設定散點的XY
        self.scat._sizes = 300 * abs(data[2])**1.5 + 100#設定散點直徑
        self.scat.set_array(data[3])  #設定散點顏色


        # We need to return the updated artist for FuncAnimation to draw..
        # Note that it expects a sequence of artists, thus the trailing comma.
    
        return self.scat,  #為何返回散點繪圖函式控制代碼,不明白?是因為動畫函式需要麼?


    def show(self):  #開始繪製函式
        plt.show()


if __name__ == '__main__':  #主函式
    a = AnimatedScatter()   #定義類,注意定義類會呼叫類的初始化函式,從而啟動整個流程

    a.show()  # 開始繪製,這步只是將上一步的繪製顯示到螢幕上,具體為什麼能從上面的迭代過程跳出來開始繪製動畫,這個我也不懂啥機制。