1

我正在尝试在使用 wxPython 的“生产”应用程序中实时绘制 matplotlib 中的数据。我一直为此目的使用 Chaco,但出于多种原因,我试图在未来避免使用 Chaco,其中一个原因是,由于它没有很好的文档记录,因此我经常必须在需要时花很长时间阅读 Chaco 源代码甚至将最小的特征添加到我的一个情节中。Chaco 胜过 matplotlib 的一个方面是速度,所以我正在探索从 matplotlib 获得可接受性能的方法。

我在 matplotlib 中看到广泛用于快速绘图的一种技术是设置animatedTrue您希望经常更新的绘图元素,然后只绘制一次背景(轴、刻度线等),并使用该canvas.copy_from_bbox()方法保存背景。然后,在绘制新foreground的(绘图轨迹等)时,您canvas.restore_region()只需将预渲染的背景复制到屏幕上,然后将新的前景与axis.draw_artist()它一起绘制canvas.blit()到屏幕上。

我编写了一个相当简单的示例,将 FigureCanvasWxAgg 嵌入到 wxPython 框架中,并尝试以 45 FPS 的速度显示随机数据的单个跟踪。当程序以默认大小的帧(在我的源代码中硬编码)运行时,它在我的机器上达到每秒约 13-14 帧。当我最大化窗口时,刷新率下降到 5.5 FPS 左右。我认为这对我的应用程序来说不够快,尤其是当我开始添加要实时渲染的其他元素时。

我的代码发布在这里:basic_fastplot.py

我想知道这是否可以更快,所以我分析了代码,发现到目前为止,处理时间的最大消耗者是对canvas.blit()第 99 行和第 109 行的调用。我进一步挖掘,检测 matplotlib 代码本身以发现最这段时间花在了对MemoryDC.SelectObject(). 在周围的代码中有几个调用SelectObject,但只有下面标记的一个需要任何可观的时间。

来自 matplotlib 源代码 backend_wxagg.py:

class FigureCanvasWxAgg(FigureCanvasAgg, FigureCanvasWx):
    # ...

    def blit(self, bbox=None):
    """
    Transfer the region of the agg buffer defined by bbox to the display.
    If bbox is None, the entire buffer is transferred.
    """
    if bbox is None:
        self.bitmap = _convert_agg_to_wx_bitmap(self.get_renderer(), None)
        self.gui_repaint()
        return

    l, b, w, h = bbox.bounds
    r = l + w
    t = b + h
    x = int(l)
    y = int(self.bitmap.GetHeight() - t)

    srcBmp = _convert_agg_to_wx_bitmap(self.get_renderer(), None)
    srcDC = wx.MemoryDC()
    srcDC.SelectObject(srcBmp)          # <<<< Most time is spent here, 30milliseconds or more!

    destDC = wx.MemoryDC()
    destDC.SelectObject(self.bitmap)

    destDC.BeginDrawing()
    destDC.Blit(x, y, int(w), int(h), srcDC, x, y)
    destDC.EndDrawing()

    destDC.SelectObject(wx.NullBitmap)
    srcDC.SelectObject(wx.NullBitmap)
    self.gui_repaint()

我的问题:

  • SelectObject() 会花这么长时间做什么?我有点假设它只是设置指针等,而不是做太多的复制或计算。
  • 有什么办法可以加快速度(全屏时可能达到 10 FPS)?
4

0 回答 0