在mpl的plt.draw()函数中规避输入到动作的延迟

时间:2015-08-15 00:56:33

标签: python performance user-interface matplotlib

在尝试追踪matplotlib的plt.draw()函数的不可接受的(257ms)运行时的来源时,我偶然发现了这篇文章:http://bastibe.de/2013-05-30-speeding-up-matplotlib.html。特别是,这句引起了我的注意:

  

“我在这里使用pause()来更新绘图而不会阻塞。正确的方法是使用draw()代替......”

进一步深入研究,我发现plt.draw()可以用两个命令代替,

plt.pause(0.001)
fig.canvas.blit(ax1.bbox)

我的代码中分别占用256ms1ms

这是不正常的,为什么1ms暂停需要256ms完成?我拿了一些数据,发现了以下内容:

plt.pause(n):
  n(s)           time(ms)       overhead(n(ms)-time(ms))
 0.0001          270-246         ~246ms
 0.001           270-254         ~253ms
 0.01            280-265         ~255ms
 0.1             398-354         ~254ms
 0.2             470-451         ~251ms
 0.5             779-759         ~259ms
 1.0            1284-1250        ~250ms
numbers courtesy of rkern's line_profiler

这清楚地表明plt.pause()做的不仅仅是暂停程序,而且我是正确的:

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
   175                                           def pause(interval):
   176                                               """
   177                                               Pause for *interval* seconds.
   178                                           
   179                                               If there is an active figure it will be updated and displayed,
   180                                               and the GUI event loop will run during the pause.
   181                                           
   182                                               If there is no active figure, or if a non-interactive backend
   183                                               is in use, this executes time.sleep(interval).
   184                                           
   185                                               This can be used for crude animation. For more complex
   186                                               animation, see :mod:`matplotlib.animation`.
   187                                           
   188                                               This function is experimental; its behavior may be changed
   189                                               or extended in a future release.
   190                                           
   191                                               """
   192         1            6      6.0      0.0      backend = rcParams['backend']
   193         1            1      1.0      0.0      if backend in _interactive_bk:
   194         1            5      5.0      0.0          figManager = _pylab_helpers.Gcf.get_active()
   195         1            0      0.0      0.0          if figManager is not None:
   196         1            2      2.0      0.0              canvas = figManager.canvas
   197         1       257223 257223.0     20.4              canvas.draw()
   198         1          145    145.0      0.0              show(block=False)
   199         1      1000459 1000459.0     79.5              canvas.start_event_loop(interval)
   200         1            2      2.0      0.0              return
   201                                           
   202                                               # No on-screen figure is active, so sleep() is all we need.
   203                                               import time
   204                                               time.sleep(interval)
once again courtesy of rkern's line_profiler

这是一个突破,因为突然清楚为什么plt.pause()能够替换plt.draw(),它内部有一个绘制函数,同时具有相同的〜250ms开销我的计划的开始。

此时,我决定简要介绍plt.draw()

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
   551                                           def draw():
   571         1       267174 267174.0    100.0      get_current_fig_manager().canvas.draw()

好吧,又向兔子洞走了一步:

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
    57                                               def draw_wrapper(artist, renderer, *args, **kwargs):
    58       769         1798      2.3      0.7          before(artist, renderer)
    59       769       242060    314.8     98.5          draw(artist, renderer, *args, **kwargs)
    60       769         1886      2.5      0.8          after(artist, renderer)

不幸的是,这就是我通过源代码运行探查器的能力结束的地方,让我在draw()函数的下一级别上摸不着头脑,以及为什么它被调用了769次。 / p>

事实证明,答案就在我面前!同样的文章,首先开始了整个强迫性狩猎,实际上是为了研究同样奇怪的行为而创建的!他们的解决方案:将plt.draw()替换为需要更新的每个artist,而不是每一个!

我希望我追逐这种行为可以帮助其他人理解它,虽然目前我每次尝试复制他的方法时都会遇到CGContextRef is NULL错误,这似乎是MacOSX特有的后端...

更多信息来了!请在下面的答案中添加更多相关信息,或者如果您可以帮我解决CGContextRef is NULL错误。

0 个答案:

没有答案