13

我知道关于 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"

谢谢你的帮助

4

2 回答 2

10

我的建议是使用 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."
于 2013-10-31T23:45:33.253 回答
2

使用 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()
于 2017-05-24T19:20:48.443 回答