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

3 投票
1 回答
4032 浏览
提问于 2025-04-17 01:08

我正在写一个程序,用来处理大量的xy坐标数据并拟合曲线。在这个过程中,能看到算法的进展是很有帮助的,所以我想在每次迭代时绘图并显示出来。我使用的是matplotlib这个库来绘图。

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

但是我不知道怎么创建一个只显示我传给它的图形的交互式窗口。目前我使用的是matplotlib.pyplot.show(),这个方法确实能显示我的图形,但它也会显示程序中定义的其他图形。我想知道有没有面向对象的方法来为特定的图形创建一个交互式窗口?我希望找到一个不依赖于matplotlib中不支持的接口的解决方案。

这里有一个类似的帖子,但它仍然没有回答我的问题:使用面向对象的Matplotlib创建交互式图形

我一直不明白为什么matplotlib总是使用当前对象(比如当前图形、当前坐标轴等),而不是特定的对象(例如,为什么不让matplotlib.pyplot.show(fig)而只是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 个回答

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的时候有些不对。欢迎大家提出建议或纠正。

撰写回答