2016-10-03 6 views
2

散布図をアニメーション化しようとしています(円のサイズを変えたいので散布図が必要です)。私はmatplotlibのドキュメンテーションチュートリアルmatplotlib documentation tutorialをPyQTアプリケーションで動作させていますが、アニメーションがスムーズでない低速のマシンではアプリケーションが実行される可能性があるため、方程式にblittingを導入したいと考えています。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

あなたはblit=TrueFuncAnimationを使用したい場合はupdateメソッドの最後にreturn self.scat,を追加する必要があります。 blitを使ったmatplotlibを使った散布図アニメーションの例を紹介しているこの素敵なStackOverflow postも見てください。

mpl図形をQtアプリケーションに埋め込みたい場合は、matplotlib documentationで提案されているように、pyplotインターフェイスを使用しないで、代わりにmplのオブジェクト指向APIを使用する方がよいでしょう。

これは、たとえば、mplWidgetをメインアプリケーションに他のQtウィジェットとして埋め込むことができます。 FigureCanvasQTAggクラスの既存のメソッドとの競合を避けるため、updateメソッドの名前をupdate_plotに変更しました。

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