Embedding a matplotlib chart in tkinter
Tkinter has no chart widget. There is no tk.Chart, no ttk.Graph, and
nothing in the standard library that draws a line or a bar for you. So the moment an app needs
to show numbers over time, everyone lands in the same place: matplotlib, embedded in the
window through a backend called FigureCanvasTkAgg.
It works well once it clicks, but the first attempt usually doesn't, because the object you get back is not a widget and doesn't behave like one. Here is the whole thing, then the parts that catch people out.
The minimal working example
import tkinter as tk
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
root = tk.Tk()
root.geometry("520x380")
figure = Figure(figsize=(4.0, 3.0), dpi=100)
axes = figure.add_subplot(111)
axes.plot([1, 2, 3, 4], [10, 30, 20, 45])
chart = FigureCanvasTkAgg(figure, master=root)
chart.draw()
chart.get_tk_widget().place(x=20, y=20, width=400, height=300)
root.mainloop() Three objects, in order: a Figure holding the plot, an axes to draw on,
and a FigureCanvasTkAgg bridging the two into tkinter. Everything below is a
consequence of that structure.
1. The canvas is not a widget
This is the one that stops people first. FigureCanvasTkAgg has no place(), no pack(), no grid(), so the obvious line
raises AttributeError. It holds a real tkinter widget, which you reach with get_tk_widget(), and that is what you position:
chart.get_tk_widget().place(x=20, y=20, width=400, height=300) The same applies to anything else you would normally do to a widget: bind(), configure(), destroying it. Go through get_tk_widget() every time.
2. Figures are measured in inches, not pixels
figsize is inches, multiplied by dpi to get pixels. For a 400×300
area at the default 100 dpi that's figsize=(4.0, 3.0). Get this wrong and the
plot is drawn at one size and then squashed into a differently sized widget, which is why
axis labels sometimes come out clipped or comically large.
3. Don't use pyplot
Nearly every matplotlib tutorial starts with import matplotlib.pyplot as plt,
and inside a GUI that is the wrong tool. pyplot keeps global figure state and
manages its own windows, so mixing it with tkinter's main loop gives you a stray second
window, or a chart that only appears when the app closes. Construct a Figure directly, as above, and pyplot never enters the picture.
4. Redrawing clears more than you expect
To show new data, clear the axes, plot again, and call draw() on the canvas. The
catch is that clear() removes the title and axis labels as well as the data, so
they have to go back on afterwards or they quietly disappear the first time the user hits
refresh:
def plot_chart(self, x, y):
self.chart_axes.clear()
self.chart_axes.plot(x, y)
self.chart_axes.set_title("Monthly sales") # clear() wiped this
self.chart.draw() Packaging an app that plots
matplotlib is a third-party package, so unlike a plain tkinter app your program now has a
dependency: pip install matplotlib on any machine that runs it, or a line in requirements.txt. If you build a standalone executable with PyInstaller, its
bundled matplotlib hook handles the data files for you, but the build does get noticeably
larger — matplotlib and NumPy are not small.
Doing it without writing any of this
Tkinter Designer has a Chart widget in its palette. Drag it onto the window,
pick line, bar or scatter, set the title and axis labels, and the generated main.py contains the embedding code above — figure sized from the box you drew,
placed through get_tk_widget(), with a plot_<name>(x, y) helper that clears, redraws and re-applies your labels. Download the project as a zip and matplotlib is already listed in requirements.txt.
It works the same way whichever toolkit you export for, because matplotlib draws into its own canvas and neither CustomTkinter nor ttkbootstrap replaces it. See the widgets reference for the rest of the palette.
Quick answers
- Is there a tkinter chart widget? No. matplotlib via
FigureCanvasTkAggis the standard answer. place()raises AttributeError? Positionget_tk_widget(), not the canvas object.- Chart is the wrong size?
figsizeis inches — divide your pixel size by the dpi. - A second window keeps opening? You're using
pyplot. Use aFigureinstead. - Title vanishes on refresh?
clear()removed it; set it again beforedraw().
Drag a chart onto a window and get the embedding code written for you.
Open the tkinter designer →