Convert matplotlib graph from plot to figure for Tkinter canvas widget embed Convert matplotlib graph from plot to figure for Tkinter canvas widget embed tkinter tkinter

Convert matplotlib graph from plot to figure for Tkinter canvas widget embed


One of the most important things to learn about Matplotlib is that it operates in one of three modes (for lack of a better word). 1) It is ingrained in pylab, 2) it has a pyplot interface, and 3) it has its underlying object interface. I'll try to disentangle them, and if anybody more familiar than I sees anything wrong with what I say below, please let me know and I'll fix it!

The first should really be avoided almost all of the time - it also bleeds in numpy and scipy, and should never be used for scripting or coding. The second is (or should be) primarily used for interactive plotting and is designed to mimic Matlab's functionality. The last one is by far the most robust for coding and is essential to the kind of embedding you want to do.

Your code currently uses a mishmash of the latter two, which can actually cause problems - pyplot does more behind the scenes than just make the plots. Matplotlib is inherently object-oriented, and pyplot is just a giant wrapper around it for convenience and to help Matlab users transition. It uses a default backend for display (in my case most of the time it uses Qt4Agg), whereas you actually want to force it to use TkAgg so Tkinter knows what to do with it. Pyplot can interfere with that if you aren't very careful.

The only pyplot calls you really should keep are the figure creation fig = plt.figure(), and your subplot2grid calls. Actually you can nix the figure call too if you import the Figure object directly (from matplotlib.figure import Figure). Once you have your axes, abandon pyplot and use the object methods directly (i.e. ax.plot()). Read up on the documentation online to see how to use them, the calling requirements for them are sometimes different!

The Tkinter embedding uses a FigureCanvasTkAgg object, which requires a Figure object. Therefore your plotting function has to return that Figure object so that it can be used to construct the FigureCanvasTkAgg. You also don't need any plt.show() - all that does is pop up the current pyplot figure, which you actually don't want because your figure is embedded in your GUI.

Therefore the answer to the problem at hand is the same as before - eliminate as many of the plt. commands as you can, and return fig. Then in the GUI code you can do

fig = graphData(stock, MA1, MA2)canvas = FigureCanvasTkAgg(fig)

Here is a minimum example that runs with no errors constructed in a way similar to yours, without using pyplot at all.

import Tkinter as Tkimport numpy as npfrom matplotlib.figure import Figurefrom matplotlib.backends.backend_tkagg import FigureCanvasTkAggdef myplotcode():    x = np.linspace(0,2*np.pi)    fig = Figure()    ax = fig.add_subplot(111)    ax.plot(x, x**2)    return figclass mygui(Tk.Frame):    def __init__(self, parent):        Tk.Frame.__init__(self, parent)        self.parent = parent        self.fig = myplotcode()        self.canvas = FigureCanvasTkAgg(self.fig, master=parent)        self.canvas.show()        self.canvas.get_tk_widget().pack()        self.pack(fill=Tk.BOTH, expand=1)root = Tk.Tk()app = mygui(root)root.mainloop()