为什么matplotlib无法在其他线程中绘图? [英] Why can't matplotlib plot in a different thread?

查看:73
本文介绍了为什么matplotlib无法在其他线程中绘图?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望以下内容能显示出一个图,但我看不到任何图,解释器只是挂起(我的后端将其自身报告为 TkAgg ).

I expect the following to show a plot, but i see no plot and the interpreter just hangs (my backend reports itself as TkAgg).

import matplotlib.pyplot as plt
from threading import Thread

def plot():
    fig, ax = plt.subplots()
    ax.plot([1,2,3], [1,2,3])
    plt.show()

def main():
    thread = Thread(target=plot)
    thread.setDaemon(True)
    thread.start()
    print 'Done'

如何让绘图显示?

我正在运行一个包含很多迭代的仿真,并且希望每1000次迭代更新一次绘图,以便我可以监视仿真的进展情况.

I am running a simulation with lots iterations and would like to update my plot every 1000 iterations so that I can monitor how my simulation is evolving.

下面的伪代码:

iterations = 100000
for i in iterations:
    result = simulate(iteration=i)
    if not i % 1000:
        # Update/redraw plot here:
        # Add some lines, add some points, reset axis limits, change some colours

在主线程中绘制绘图会导致绘图 GUI 挂起/崩溃,大概是因为我还有其他工作正在进行.所以我们的想法是在一个单独的线程中进行绘图.

Having the plot in the main thread causes the plot GUI to hang/crash presumably because I have other work going on. So the idea was to do the plotting in a separate thread.

我已经看到建议(例如此处)使用进程而不是线.但是随后我无法在仿真运行时操纵图形或轴以添加线等,因为图形对象处于远程过程中.

I have seen suggestions (e.g. here) to use a process rather than a thread. But then I cannot manipulate the figure or axes to add lines etc while my simulation runs because the figure object is in the remote process.

我不认为这个问题是重复的另一个问题 因为这个问题涉及为什么 pyplot api 不能用于操作 两个不同的图,每个图都在一个单独的线程上.这是因为同时执行两个图所产生的竞争条件会阻止 pyplot 确定哪个图是 当前图.

I'm not convinced this question is a duplicate of another one because that question deals with why the pyplot api cannot be used to manipulate two different plots that are each on a separate thread. It is because race conditions arising from executing two plots simultaneously prevents pyplot from determining which figure is the current figure.

然而,我只有 1 个图,所以 pyplot 只有一个唯一的当前图.

However, I only have 1 plot and so pyplot only ever has a single and unique current figure.

推荐答案

正如其他人所说,Matplotlib 不是线程安全的,您可以选择的一种方法是使用多处理.您说这对您不利,因为您需要访问来自不同进程的轴,但是您可以通过在模拟进程和根进程之间共享数据然后管理所有绘图来克服这个问题根进程中的相关活动.例如

As other people have told, Matplotlib is not thread safe, one option you have is to use multiprocessing. You say that this is not good for you, because you need access to the axes from different process, but you can overcome this by sharing data between the simulation process and the root process and then managing all the plotting related activities in the root process. For example

import matplotlib
matplotlib.use('TkAgg')
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
import multiprocessing
import time
import random
from Tkinter import *


#Create a window
window=Tk()



def main():
    #Create a queue to share data between process
    q = multiprocessing.Queue()

    #Create and start the simulation process
    simulate=multiprocessing.Process(None,simulation,args=(q,))
    simulate.start()

    #Create the base plot
    plot()

    #Call a function to update the plot when there is new data
    updateplot(q)

    window.mainloop()
    print 'Done'


def plot():    #Function to create the base plot, make sure to make global the lines, axes, canvas and any part that you would want to update later

    global line,ax,canvas
    fig = matplotlib.figure.Figure()
    ax = fig.add_subplot(1,1,1)
    canvas = FigureCanvasTkAgg(fig, master=window)
    canvas.show()
    canvas.get_tk_widget().pack(side=TOP, fill=BOTH, expand=1)
    canvas._tkcanvas.pack(side=TOP, fill=BOTH, expand=1)
    line, = ax.plot([1,2,3], [1,2,10])




def updateplot(q):
    try:       #Try to check if there is data in the queue
        result=q.get_nowait()

        if result !='Q':
             print result
                 #here get crazy with the plotting, you have access to all the global variables that you defined in the plot function, and have the data that the simulation sent.
             line.set_ydata([1,result,10])
             ax.draw_artist(line)
             canvas.draw()
             window.after(500,updateplot,q)
        else:
             print 'done'
    except:
        print "empty"
        window.after(500,updateplot,q)


def simulation(q):
    iterations = xrange(100)
    for i in iterations:
        if not i % 10:
            time.sleep(1)
                #here send any data you want to send to the other process, can be any pickable object
            q.put(random.randint(1,10))
    q.put('Q')

if __name__ == '__main__':
    main()

这篇关于为什么matplotlib无法在其他线程中绘图?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆