开发者

Creating a matplotlib interactive plotting window for an existing figure

开发者 https://www.devze.com 2023-04-01 03:49 出处:网络
I am writing a program that fits curves to large sets of xy coordinate data. It is often helpful to watch the progress of the algorithm by plotting and displaying each iteration as the fitting progres

I am writing a program that fits curves to large sets of xy coordinate data. It is often helpful to watch the progress of the algorithm by plotting and displaying each iteration as the fitting progresses. I'm using matplotlib for plotting.

What I'd like to do is create the figure in the main thread, then pass it into a child thread that displays it. That way I have access to all the figure's methods and attributes in the main thread. I can plot by calling fig.gca().plot() and draw by calling fig.canvas.draw().

I can't figure out how to create an interactive plotting window that shows only the figure I pass to it. Right now I'm using matplotlib.pyplot.show(), which does di开发者_Go百科splay my figure, but it also displays any other figures that may have been defined in the program. Is there an object oriented way to create an interactive window for a specific figure? I am looking for a solution that does not rely on unsupported interfaces in matplotlib.

Here is a post that's similar, but it still doesn't answer my question: Interactive figure with OO Matplotlib

I've never understood why matplotlib always seems to use current objects (current figure, current axes, etc.) rather than specific objects (for example, why not have matplotlib.pyplot.show(fig) rather than just show()?) I think I'm missing something. If anyone could shed some light on why matplotlib is designed this way, or how I'm misunderstanding and/or misusing it, that would also be appreciated.

Here's my code:

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()


I think I got it:

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()

The only thing is if you try to create two instances of Plotter the whole thing crashes. That isn't too important for my application, but it probably means I'm using Tkinter wrong. Suggestions/corrections are welcome.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号