Python Tkinter Embed Matplotlib in GUI
I'm trying to embed a plot in my Tkinter GUI coded in Python. I believe the code below succeeds in simply putting a graph into a canvas, but I don't have any control of the canvas location within the GUI grid. I want to be able to have a subsection of my GUI be the plot...not the entirety of it. How can I position this canvas widget?
#!/usr/apps/Python/bin/python
import matplotlib, sys
matplotlib.use('TkAgg')
from numpy import arange, sin, pi
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from matplotlib.figure import Figure
from Tkinter import *
master = Tk()
master.title("Hello World!")
#-------------------------------------------------------------------------------
f = Figure(figsize=(5,4), dpi=100)
a = f.add_subplot(111)
t = arange(0.0,3.0,0.01)
s = sin(2*pi*t)
a.plot(t,s)
dataPlot = FigureCanvasTkAgg(f, master=master)
dataPlot.show()
dataPlot.get_tk_widget().pack(side=TOP, fill=BOTH, expand=1)
#-------------------------------------------------------------------------------
master.mainloop()
You don't have any other widgets so it's hard to know where you want other widgets. Here's what I can tell you though: by doing dataPlot.get_tk_widget().pack(side=TOP, fill=BOTH, expand=1)
you are asking Tkinter to fill the screen with the plot. This, because you ask it to fill in all directions (fill=BOTH
) and expand to fill any extra space (expand=1
).
However, you can still add other widgets. pack
works by putting widgets on one side of a container. Your container, master
, always has four sides. So, for example, if you wanted to create a toolbar you would do something like:
toolbar = tk.Frame(master)
button = tk.Button(toolbar, text="Push me")
button.pack(side="left") # left side of parent, the toolbar frame
toolbar.pack(side=TOP, fill="x") # top of parent, the master window
Notice that if you put this code after the code where you pack
the plot, the toolbar shows up on the bottom! That's because TOP
, BOTTOM
, etc refer to space left over by any other widgets that have already been pack
ed. The plot takes up the top, the space left over is at the bottom. So when you specify TOP
again it means "at the top of the area below whatever is already at the top".
So, you have some choices. The best choice is to make your widgets in the order you wish them to appear. If you pack
the toolbar at the top before you pack
the plot, it will be the toolbar that shows up at the very top. Further, you can place the plot at the bottom rather than the top and that will solve the problem, too.
By the way, I typically create my widgets in one block, then lay them all out in a separate block. I find it makes the code easier to maintain.
Another choice which may fit your mental model better is to grid
instead of pack
. With grid
you can choose the row(s) and column(s) that the widget occupies. This makes it easy to lay things out in a grid, but at the expense of having to use a little more code.
For example, to put the toolbar at the top and the plot down below you might do:
toolbar.grid(row=1, column=1, sticky="ew")
dataPlot.get_tk_widget().grid(row=1, column=1, sticky="nsew")
master.grid_rowconfigure(0, weight=0)
master.grid_rowconfigure(1, weight=1)
master.grid_columnconfigure(0, weight=1)
Notice that rows and columns start at zero. Also, "weight" refers to how much this widget expands relative to other widgets. With two rows of equal weight, they will expand equally when the window is resized. A weight of zero means no expansion. A weight of 2 for one row, and 1 for another means that the former will expand twice as much as the latter.
For more information see this page on grid, and this page on pack.