2016-10-03 185 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