2016-10-03 210 views
2

我正在嘗試動畫散點圖(它需要散點圖,因爲我想改變圓的大小)。我已經獲得了matplotlib文檔教程matplotlib documentation tutorial在我的PyQT應用程序中工作,但想要將blitting引入方程中,因爲我的應用程序可能會在動畫可能不夠流暢的較慢機器上運行。Python,QT和matplotlib與blitting散點圖

我看過很多動畫片斷的例子,但從來沒有使用散點圖(他們使用圖形或線條),所以我真的很想弄清楚如何初始化動畫(位每次都不會重新渲染)以及那些做的。我已經嘗試了很多事情,似乎沒有任何進展(我相信他們會造成比幫助更多的困惑!)。我認爲我錯過了一些相當基礎的東西。有沒有人做過這個?任何人都可以幫助我將數字分解成需要啓動的部分和獲取更新的部分?

下面的代碼工作,但不blit。追加

blit=True 

到動畫通話結束產生以下錯誤:

RuntimeError: The animation function must return a sequence of Artist objects. 

任何幫助將是巨大的。

問候

FP

import numpy as np 
from PyQt4 import QtGui, uic 
import sys 
import matplotlib.pyplot as plt 
from matplotlib.animation import FuncAnimation 

class MainWindow(QtGui.QMainWindow): 
    def __init__(self): 
     super(MainWindow, self).__init__() 

     self.setupAnim() 

     self.show() 

    def setupAnim(self): 
     self.fig = plt.figure(figsize=(7, 7)) 
     self.ax = self.fig.add_axes([0, 0, 1, 1], frameon=False) 
     self.ax.set_xlim(0, 1), self.ax.set_xticks([]) 
     self.ax.set_ylim(0, 1), self.ax.set_yticks([]) 

     # Create rain data 
     self.n_drops = 50 
     self.rain_drops = np.zeros(self.n_drops, dtype=[('position', float, 2), 
               ('size',  float, 1), 
               ('growth', float, 1), 
               ('color', float, 4)]) 

     # Initialize the raindrops in random positions and with 
     # random growth rates. 
     self.rain_drops['position'] = np.random.uniform(0, 1, (self.n_drops, 2)) 
     self.rain_drops['growth'] = np.random.uniform(50, 200, self.n_drops) 

     # Construct the scatter which we will update during animation 
     # as the raindrops develop. 
     self.scat = self.ax.scatter(self.rain_drops['position'][:, 0], self.rain_drops['position'][:, 1], 
          s=self.rain_drops['size'], lw=0.5, edgecolors=self.rain_drops['color'], 
          facecolors='none') 

     self.animation = FuncAnimation(self.fig, self.update, interval=10) 
     plt.show() 

    def update(self, frame_number): 
     # Get an index which we can use to re-spawn the oldest raindrop. 
     self.current_index = frame_number % self.n_drops 

     # Make all colors more transparent as time progresses. 
     self.rain_drops['color'][:, 3] -= 1.0/len(self.rain_drops) 
     self.rain_drops['color'][:, 3] = np.clip(self.rain_drops['color'][:, 3], 0, 1) 

     # Make all circles bigger. 
     self.rain_drops['size'] += self.rain_drops['growth'] 

     # Pick a new position for oldest rain drop, resetting its size, 
     # color and growth factor. 
     self.rain_drops['position'][self.current_index] = np.random.uniform(0, 1, 2) 
     self.rain_drops['size'][self.current_index] = 5 
     self.rain_drops['color'][self.current_index] = (0, 0, 0, 1) 
     self.rain_drops['growth'][self.current_index] = np.random.uniform(50, 200) 

     # Update the scatter collection, with the new colors, sizes and positions. 
     self.scat.set_edgecolors(self.rain_drops['color']) 
     self.scat.set_sizes(self.rain_drops['size']) 
     self.scat.set_offsets(self.rain_drops['position']) 

if __name__== '__main__': 
    app = QtGui.QApplication(sys.argv) 
    window = MainWindow() 
    sys.exit(app.exec_()) 

回答

1

您需要在update方法的末尾添加return self.scat,如果你想使用FuncAnimationblit=True。另請參閱這個不錯的StackOverflow post,其中展示了使用blit的matplotlib的散點圖動畫示例。

作爲一個側面提示,如果您希望在Qt應用程序中嵌入mpl圖形,最好避免使用pyplot接口,並使用matplotlib documentation中建議的mpl的面向對象API。

例如,如下所示,可以將mplWidget作爲任何其他Qt小部件嵌入到主應用程序中。請注意,我將update方法重命名爲update_plot,以避免與已有的FigureCanvasQTAgg類的方法衝突。

import numpy as np 
from PyQt4 import QtGui 
import sys 
import matplotlib as mpl 
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg 
from matplotlib.animation import FuncAnimation 
import matplotlib.pyplot as plt 

class mplWidget(FigureCanvasQTAgg): 
    def __init__(self): 
     super(mplWidget, self).__init__(mpl.figure.Figure(figsize=(7, 7))) 

     self.setupAnim() 
     self.show() 

    def setupAnim(self): 
     ax = self.figure.add_axes([0, 0, 1, 1], frameon=False) 
     ax.axis([0, 1, 0, 1]) 
     ax.axis('off') 

     # Create rain data 
     self.n_drops = 50 
     self.rain_drops = np.zeros(self.n_drops, dtype=[('position', float, 2), 
                 ('size',  float, 1), 
                 ('growth', float, 1), 
                 ('color', float, 4) 
                 ]) 

     # Initialize the raindrops in random positions and with 
     # random growth rates. 
     self.rain_drops['position'] = np.random.uniform(0, 1, (self.n_drops, 2)) 
     self.rain_drops['growth'] = np.random.uniform(50, 200, self.n_drops) 

     # Construct the scatter which we will update during animation 
     # as the raindrops develop. 
     self.scat = ax.scatter(self.rain_drops['position'][:, 0], 
           self.rain_drops['position'][:, 1], 
           s=self.rain_drops['size'], 
           lw=0.5, facecolors='none', 
           edgecolors=self.rain_drops['color']) 

     self.animation = FuncAnimation(self.figure, self.update_plot, 
             interval=10, blit=True) 

    def update_plot(self, frame_number): 
     # Get an index which we can use to re-spawn the oldest raindrop. 
     indx = frame_number % self.n_drops 

     # Make all colors more transparent as time progresses. 
     self.rain_drops['color'][:, 3] -= 1./len(self.rain_drops) 
     self.rain_drops['color'][:, 3] = np.clip(self.rain_drops['color'][:, 3], 0, 1) 

     # Make all circles bigger. 
     self.rain_drops['size'] += self.rain_drops['growth'] 

     # Pick a new position for oldest rain drop, resetting its size, 
     # color and growth factor. 
     self.rain_drops['position'][indx] = np.random.uniform(0, 1, 2) 
     self.rain_drops['size'][indx] = 5 
     self.rain_drops['color'][indx] = (0, 0, 0, 1) 
     self.rain_drops['growth'][indx] = np.random.uniform(50, 200) 

     # Update the scatter collection, with the new colors, 
     # sizes and positions. 
     self.scat.set_edgecolors(self.rain_drops['color']) 
     self.scat.set_sizes(self.rain_drops['size']) 
     self.scat.set_offsets(self.rain_drops['position']) 

     return self.scat, 


if __name__ == '__main__': 
    app = QtGui.QApplication(sys.argv) 
    window = mplWidget() 
    sys.exit(app.exec_()) 
+0

這很好。謝謝讓,非常感謝。 有趣的是要注意與「更新」方法的衝突。考慮到這可能是我無法使其工作幾次的原因。衛生署!注意自己:不要爲函數名稱使用通用術語! – fp1991