为现有图形创建matplotlib交互式绘图窗口

时间:2011-09-01 19:45:09

标签: python multithreading oop matplotlib

我正在编写一个程序,可以将曲线拟合到大量的xy坐标数据中。通过在拟合进行时绘制和显示每次迭代来观察算法的进度通常是有帮助的。我正在使用matplotlib进行绘图。

我想要做的是在主线程中创建图形,然后将其传递给显示它的子线程。这样我就可以访问主线程中所有图形的方法和属性。我可以通过调用fig.gca()。plot()绘图并通过调用fig.canvas.draw()绘制。

我无法弄清楚如何创建一个交互式绘图窗口,只显示我传递给它的图形。现在我正在使用matplotlib.pyplot.show(),它显示我的图形,但它也显示可能已在程序中定义的任何其他图形。是否有面向对象的方式为特定图形创建交互式窗口?我正在寻找一种不依赖于matplotlib中不支持的接口的解决方案。

这是一篇类似的帖子,但它仍然没有回答我的问题:Interactive figure with OO Matplotlib

我从未理解为什么matplotlib似乎总是使用当前对象(当前图形,当前轴等)而不是特定对象(例如,为什么不使用matplotlib.pyplot.show(图)而不是仅显示( )?)我想我错过了什么。如果有人能说明为什么matplotlib是这样设计的,或者我是如何误解和/或误用它,那也是值得赞赏的。

这是我的代码:

import matplotlib.pyplot
import threading
import time

class Plotter():
    def __init__(self,fig):
        t = threading.Thread(target=self.PlottingThread,args=(fig,))
        t.start()       

    def PlottingThread(self,fig):
        #This line shows fig1 AND fig2 from below. I want it to show fig ONLY.
        matplotlib.pyplot.show()  

if __name__ == "__main__":
    fig1 = matplotlib.pyplot.figure()
    fig2 = matplotlib.pyplot.figure()

    Plotter(fig1)

    fig1.gca().clear()
    fig1.gca().plot([1,2,3])
    fig1.canvas.draw()

1 个答案:

答案 0 :(得分:2)

我想我明白了:

import Tkinter
import threading
import matplotlib.backends.backend_tkagg

root = Tkinter.Tk()

class Plotter():
    def __init__(self,fig):
        t = threading.Thread(target=self.PlottingThread,args=(fig,))
        t.start()       

    def PlottingThread(self,fig):        
        canvas = matplotlib.backends.backend_tkagg.FigureCanvasTkAgg(fig, master=root)
        canvas.show()
        canvas.get_tk_widget().pack(side=Tkinter.TOP, fill=Tkinter.BOTH, expand=1)

        toolbar = matplotlib.backends.backend_tkagg.NavigationToolbar2TkAgg(canvas, root)
        toolbar.update()
        canvas._tkcanvas.pack(side=Tkinter.TOP, fill=Tkinter.BOTH, expand=1)

        Tkinter.mainloop()

if __name__ == "__main__":
    import time

    fig1 = matplotlib.figure.Figure(figsize=(5,4), dpi=100)
    fig1.gca().plot([1,2,3])     
    fig2 = matplotlib.figure.Figure(figsize=(5,4), dpi=100)
    fig2.gca().plot([3,2,1])

    #Shows fig1 and not fig2, just like it's supposed to
    Plotter(fig1)

    time.sleep(1)

    #I can still plot to fig1 from my main thread
    fig1.gca().clear()
    fig1.gca().plot([5,2,7])
    fig1.canvas.draw()

唯一的问题是,如果你试图创建两个Plotter实例,整个事情就会崩溃。这对我的应用程序来说并不重要,但这可能意味着我使用的是Tkinter错误。欢迎提出建议/更正。