Tkinter Designer

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 FigureCanvasTkAgg is the standard answer.
  • place() raises AttributeError? Position get_tk_widget(), not the canvas object.
  • Chart is the wrong size? figsize is inches — divide your pixel size by the dpi.
  • A second window keeps opening? You're using pyplot. Use a Figure instead.
  • Title vanishes on refresh? clear() removed it; set it again before draw().

Drag a chart onto a window and get the embedding code written for you.

Open the tkinter designer →