【问题标题】:Python, QT and matplotlib scatter plots with blittingPython、QT 和 matplotlib 散点图与 blitting
【发布时间】:2017-02-11 14:47:18
【问题描述】:

我正在尝试为散点图制作动画(它需要是散点图,因为我想改变圆的大小)。我已经获得了 matplotlib 文档教程 matplotlib documentation tutorial 在我的 PyQT 应用程序中工作,但我想在方程式中引入 blitting,因为我的应用程序可能会在动画可能不那么流畅的较慢机器上运行。

我看过许多带有 blitting 的动画示例,但没有一个使用散点图(它们使用绘图或线条),所以我真的很难弄清楚如何初始化动画(那些不' t 每次都重新渲染)和那些这样做的。我已经尝试了很多东西,但似乎无济于事(我相信它们会引起更多的混乱而不是帮助!)。我假设我错过了一些相当基本的东西。有没有人这样做过?谁能帮我把图分成需要启动的部分和需要更新的部分?

下面的代码可以工作,但不能 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_())

【问题讨论】:

    标签: python qt matplotlib scatter-plot blit


    【解决方案1】:

    如果要将FuncAnimationblit=True 一起使用,则需要在update 方法的末尾添加return self.scat,。另请参阅这个漂亮的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_())
    

    【讨论】:

    • 这很棒。谢谢让,非常感谢。有趣的是要注意与“更新”方法的冲突。想一想,这可能是阻止我让它工作几次的原因。嗬!自我注意:不要对函数名使用通用术语!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-22
    • 1970-01-01
    • 1970-01-01
    • 2012-06-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多