matplotlib 和 pyqt4:在一个线程中更新绘图,在另一个线程中绘制
我正在使用 PyQt4 和 matplotlib 创建一个实时数据监视器 GUI 来创建绘图。 GUI 一次显示多个图(大约 6 或 7 个)。为了给 GUI 线程更多的时间和更好的响应时间,我只执行绘图 canvas.draw()
以及我在更新绘图数据的线程中执行的所有其他绘图命令。因此,在非 GUI 线程中,我执行诸如 line.set_ydata
、ax.set_ylim
之类的命令以及其他可能需要更新的内容。
这两个线程可以通过在初始化时传递给两个线程的字典来访问图形和画布对象。当非 GUI 线程获取数据并更新绘图时,它会向 GUI 线程发出信号,使用 Qts 信号(自动连接)重绘画布。我的线程经验告诉我,我应该使用锁或确保非 GUI 线程以某种方式在重绘时被阻塞,但在我的编码匆忙中,我从来没有把它放进去,直到现在才忘记它。这种情况的关键点是我希望看到情节的每次更新,而不是在其他线程更新中间重绘,甚至错过更新(如果有意义的话)。目前,我认为我的时机很幸运,一切似乎都进展顺利。
另一件可能有帮助的事情是,我通过使用 moveToThread 将 QObject 移动到 QThread 来创建线程。
我的问题是:
- 我只是运气好还是 Qt 只是做了一些神奇的事情?
- 在 matplotlib 画布/图形上完成阻塞的最佳方法是什么?
我可能应该注意到,这是我第一次尝试使 GUI 更具响应性(将 matplotlib 命令移动到数据线程中),并且我可能会转向仅更新绘图中发生变化的部分的 blit 动画风格绘图。但我还是很好奇我有多幸运。
感谢您的任何帮助。
更新/澄清/评论继续:我希望可能只熟悉 matlab 甚至 matplotlib 的科学家可以轻松更改/更新整个监控系统。我并不完全反对更改为 pyqwt 来绘制速度。就每秒帧数而言,我实际上根本不需要太多,因为标称每 0.5 秒绘制一次数据(最快 0.2 秒)。 GUI 响应能力似乎“吃**”,因为有太多的情节。我已经用 matplotlib blitting 对我的代码进行了概念验证,它似乎有很大帮助,如果需要的话 pyqwt 会发生。我之前的问题仍然成立。
I'm creating a live data monitor GUI with PyQt4 and matplotlib to create the plots. The GUI displays multiple plots at a time (around 6 or 7). To give the GUI thread more time and slightly better response time I only do the drawing canvas.draw()
and all other plotting commands I do in the thread that updates the plot data. So in the non-GUI thread I do commands like line.set_ydata
, ax.set_ylim
, and other things that might need to be updated.
The two threads have access to the figure and canvas objects through a dictionary that is passed to the two threads at initialization. When the non-GUI thread gets data and updates the plot, it then signals the GUI thread to redraw the canvas using Qts signals (auto-connection). My threading experience tells me that I should use a lock or make sure the non-GUI thread is blocked on the redraw in some way, but in my coding rush I never put it in and forgot about it until now. The key point to this situation is that I want to see every update of the plot, not redraw in the middle of the other thread updating or even miss an update (if that makes sense). Currently, I think I'm just getting lucky with timing and things seem to be working ok.
Another thing that might be helpful to know is that I'm creating threads by moving a QObject to a QThread by using moveToThread.
My questions are:
- Am I just getting lucky or is Qt just doing something magical?
- What is the best way to accomplish the blocking on the matplotlib canvas/figure?
I should probably note that this was my first attempt at making the GUI more responsive (moving matplotlib commands into the data thread) and I may be moving to a blit animation style drawing of only updating the parts of the plot that change. But I'm still curious as to how lucky I am.
Thanks for any help.
Update/Clarification/Continuation from comments: I wanted the entire monitor system to be easily changed/updated by scientists who may only be familiar with matlab and maybe matplotlib. I'm not completely against changing to pyqwt for plotting for speed. And in terms of frames per second, I don't really need a lot at all since the data that is being plotted only comes in every 0.5 seconds nominal (0.2 seconds at the fastest). The GUI responsiveness just seems to "eat **" because there are so many plots. I've done a proof of concept hacking of my code with matplotlib blitting and it seems to help a ton, pyqwt will happen if needed. My previous questions still stand.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我偶然发现了类似的问题。我有很多图要绘制(~250),所以我的 GUI 窗口最终会在 Windows 中显示为挂起。
我修改了图形类以作为单独的线程执行绘图。
结果 - 我的 GUI 不再挂起,绘图完成后会显示绘图窗口。要使用它,您需要创建
PlotDialog
实例并使用plot_data
参数调用draw_plots
方法。plot_data
是一个字典列表,每个字典代表子图。每个子图都有以下键(以及相应的数据):title
、xlabel
、ylabel
和data
。希望这是有道理的。这是我的代码:
I stumbled upon similar problem. I had a lot of plots to draw (~250) so my GUI window would eventually show up as hanging in Windows.
I modified figure class to perform plotting as a separate thread.
The result - my GUI does not hang anymore, plot window shows up once the plotting is done. To use it, you create
PlotDialog
instance and calldraw_plots
method withplot_data
argument.plot_data
is a list of dictionaries, each dictionary represents subplot. Each subplot has following keys (and corresponding data):title
,xlabel
,ylabel
anddata
. Hope that makes sense.Here is my code: