问题 在线程中使用matplotlib绘图


我知道在matplotlib和线程上有很多问题,而且pyplot也不是线程。然而,我找不到关于这个特定问题的任何内容。我想要做的是:绘制一个数字并每秒更新一次。为此,我想创建一个线程,但到目前为止,我甚至无法从线程中获得真实的情节。此外,我坚持使用qt4,因此可能是其他后端表现不同。

这是一个非常简单的例子:创建了一个情节 plot_a_graph()。从主程序调用时这很好,但是延迟了主代码的进一步执行。但是,从线程调用时,不会显示任何图形。

import matplotlib
matplotlib.use("qt4agg")
import matplotlib.pyplot as plt
import threading
import time

def plot_a_graph():
    f,a = plt.subplots(1)
    line = plt.plot(range(10))
    plt.show()
    print "plotted graph"    
    time.sleep(4)


testthread = threading.Thread(target=plot_a_graph)

plot_a_graph()      # this works fine, displays the graph and waits
print "that took some time"

testthread.start() # Thread starts, window is opened but no graph appears
print "already there"

谢谢你的帮助


8915
2017-10-29 15:43


起源

在主线程上进行所有绘图。至少在QT,如果你试图这样做,gui不喜欢它。 - tacaswell


答案:


我的建议是使用python  模块而不是线程模块。我已经能够对您的示例代码执行稍微修改,并成功地将matplotlib绘图卸载到子进程,同时主进程中的控制流继续(请参阅下面的代码)。

如果您希望子进程在较大的代码控制流(不是'上下文中)与父进程来回通信,我建议您阅读多处理文档或有关该主题的任何过多博客文章。在你的问题中完整描述)。请注意,多处理具有绕过python的附加优势 全球翻译锁 并允许您利用多核计算机体系结构。

#a slight modification of your code using multiprocessing
import matplotlib
matplotlib.use("qt4agg")
import matplotlib.pyplot as plt 
#import threading
#let's try using multiprocessing instead of threading module:
import multiprocessing
import time

#we'll keep the same plotting function, except for one change--I'm going to use the multiprocessing module to report the plotting of the graph from the child process (on another core):
def plot_a_graph():
    f,a = plt.subplots(1)
    line = plt.plot(range(10))
    print multiprocessing.current_process().name,"starting plot show process" #print statement preceded by true process name
    plt.show() #I think the code in the child will stop here until the graph is closed
    print multiprocessing.current_process().name,"plotted graph" #print statement preceded by true process name
    time.sleep(4)

#use the multiprocessing module to perform the plotting activity in another process (i.e., on another core):
job_for_another_core = multiprocessing.Process(target=plot_a_graph,args=())
job_for_another_core.start()

#the follow print statement will also be modified to demonstrate that it comes from the parent process, and should happen without substantial delay as another process performs the plotting operation:
print multiprocessing.current_process().name, "The main process is continuing while another process deals with plotting."

9
2017-10-31 23:45



谢谢!不幸的是,我之前尝试过,我得到的是一个错误:... PicklingError:无法在0x0A5893F0处找到<function plot_a_graph>:它没有找到 主要.plot_a_graph - Fabian


使用Qt信号在主线程中调用绘图功能

import matplotlib
matplotlib.use("qt4agg")
import matplotlib.pyplot as plt
import threading
import time

from PyQt4 import QtCore

class Call_in_QT_main_loop(QtCore.QObject):
    signal = QtCore.pyqtSignal()

    def __init__(self, func):
        super().__init__()
        self.func = func
        self.args = list()
        self.kwargs = dict()
        self.signal.connect(self._target)

    def _target(self):
        self.func(*self.args, **self.kwargs)

    def __call__(self, *args, **kwargs):
        self.args = args
        self.kwargs = kwargs
        self.signal.emit()

@Call_in_QT_main_loop
def plot_a_graph():
    f,a = plt.subplots(1)
    line = plt.plot(range(10))
    plt.show()
    print("plotted graph")
    print(threading.current_thread())  # print the thread that runs this code

def worker():
    plot_a_graph()
    print(threading.current_thread())  # print the thread that runs this code
    time.sleep(4)

testthread = threading.Thread(target=worker)

testthread.start()

0
2018-05-24 19:20