如何使 Matplotlib 小部件更快?

How to make Matplotlib widget faster?

我在一个有很多图的图形上使用 Matplotlib 小部件滑块。当我移动滑块时,大约需要 5 秒来更新图形,这是我的问题。

排除问题后,罪魁祸首似乎是调用 fig.canvas.draw() 的小部件本身。当在移动滑块时不执行任何操作(不修改任何子图)时,它仍然需要 5 秒来更新滑块,因为 fig.canvas.draw() 每次我触摸滑块时都会重新绘制所有图形和所有子图.

在所有抱怨 Matplotlib 绘图速度的线程中,像这里:why is plotting with Matplotlib so slow?,建议不要使用 fig.canvas.draw(),因为它会重绘整个图形,而是使用 ax.draw_artist( ) 而不是只重新绘制已修改的子图的数据。所以 Matplotlib 小部件破坏了我使该图具有交互性的所有努力(5s 滞后并不是真正的交互)。在我可能会使用不同的图书馆之前我会知道,但现在已经太晚了。

这个问题实际上是在2013年提出的(http://matplotlib.1069221.n5.nabble.com/Making-an-interactive-plot-faster-td41312.html),建议可以选择使用draw_artist代替。将 drawon 设置为 False 的可能性对我不起作用,因为如本 post 中所述,小部件无论如何至少调用一次 fig.canvas.draw()。自从大约 8 年前首次提出这个问题以来,是否有任何改进(我还没有找到)使 Matplotlib 小部件仅更新小部件并让用户决定图形上的哪些元素也应该更新?

我认为这是 Matplotlib 小部件的一个主要限制,我真的希望有一种方法可以纠正这种行为。在我的例子中,我可能可以通过将最大的图(静态的)绘制为图像或减少点数来加快绘图速度,但它仍然比让小部件不每次都重新绘制它效率低。

--------------------更新---------------------

创建图形并仅添加小部件(5 个滑块、4 个按钮、1 个单选按钮)和 3 个空子图后,滑块已经滞后了!此时没有数据,图中只有 10 个小部件和 3 个空的子图,每次我想移动滑块时已经有大约 0.5s - 1s 的滞后(通过眼睛)。 如果我连续上下移动滑块,我的 CPU 会从 15% 跳到 50%!我有一台带 i7 7660U 的 Dell XPS13(2 核 4 线程,4GHz 睿频)。我不明白为什么移动 1 个滑块会如此 CPU 密集。 matplotlib计算什么这么重? 结果,我没有任何解决方法了。我用图像替换最大图的想法不是很有用,因为即使没有任何数据或图像,滑块也已经太慢了!

有谁知道为什么移动 1 个滑块会如此疯狂 cpu 密集,最重要的是,每次我触摸滑块时如何避免这种延迟?

谢谢

这是我用来生成具有 10 个小部件和 3 个空子图的图形的代码示例。

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider, Button, RadioButtons

fig = plt.figure(figsize=(16, 10))
ax1 = plt.subplot2grid((6,10),(0,0), rowspan = 2, colspan = 8)
ax2 = plt.subplot2grid((6,10),(3,0), rowspan = 2, colspan = 7)
ax3 = plt.subplot2grid((6,10),(3,8), rowspan = 2, colspan = 2)

ax_color = 'lightgoldenrodyellow' # Color of the sliders
ax_win = plt.axes([0.23, 0.53, 0.65, 0.023], facecolor=ax_color)
ax_thres = plt.axes([0.23, 0.5, 0.65, 0.023], facecolor=ax_color)
ax_min_dist = plt.axes([0.23, 0.56, 0.65, 0.023], facecolor=ax_color)
ax_move_win = plt.axes([0.55, 0.05, 0.35, 0.023], facecolor=ax_color)
ax_resize_win = plt.axes([0.55, 0.08, 0.35, 0.023], facecolor=ax_color)
ax_save_res = plt.axes([0.20, 0.05, 0.075, 0.04])
ax_save_all = plt.axes([0.30, 0.05, 0.075, 0.04])
ax_previous = plt.axes([0.05, 0.05, 0.05, 0.04])
ax_next = plt.axes([0.1, 0.05, 0.05, 0.04])
ax_cb = plt.axes([0.85, 0.6, 0.12, 0.15])
ax_cb.set_frame_on(False)
ax_cb.text(0.5, 1, 'Plot', horizontalalignment='center', verticalalignment='top', transform=ax_cb.transAxes, fontsize=16)

s_win = Slider(ax_win, 'Res window width [kHz]', 10, 1000, valinit = 2e5/1e3)
s_thresdB = Slider(ax_thres, 'Min res depth threshold [dB]', -10, 0.0, valinit = -0.5)
s_min_dist = Slider(ax_min_dist, 'Min inter-res distance [kHz]', 0, 3, valinit = np.log10(6))
s_move_win = Slider(ax_move_win, 'Zoom position', 0, 1, valinit = 0)
s_resize_win = Slider(ax_resize_win, 'Zoom width', 0, 0.25, valinit = 0.05)
b_save_res = Button(ax_save_res, 'Save res', color='lightblue', hovercolor='gold')
b_save_all = Button(ax_save_all, 'Save all res', color='lightblue', hovercolor='gold')
b_previous = Button(ax_previous, 'Previous', color='greenyellow', hovercolor='gold')
b_next = Button(ax_next, 'Next', color='greenyellow', hovercolor='gold')
cb_plot2 = RadioButtons(ax_cb, ('FPtemp vs fres', 'BBtemp vs fres', 'Close'), (False, False, True))

好的,经过一些调查,Matplotlib 3.3.1 似乎有问题(如此处所述:https://github.com/matplotlib/matplotlib/pull/18304)。更新到 3.3.2 版帮助很大。仍然有一点延迟,所以它并不完美,但它更可用。